about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml20
-rw-r--r--Cargo.lock91
-rw-r--r--compiler/rustc_ast/src/ast.rs1
-rw-r--r--compiler/rustc_ast/src/lib.rs2
-rw-r--r--compiler/rustc_ast/src/token.rs7
-rw-r--r--compiler/rustc_ast_lowering/src/asm.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/index.rs14
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs38
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs34
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs7
-rw-r--r--compiler/rustc_ast_passes/src/lib.rs1
-rw-r--r--compiler/rustc_attr/src/lib.rs1
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs71
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs9
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs5
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs3
-rw-r--r--compiler/rustc_borrowck/src/lib.rs3
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs5
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs1949
-rw-r--r--compiler/rustc_builtin_macros/src/format/ast.rs240
-rw-r--r--compiler/rustc_builtin_macros/src/format/expand.rs353
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/example/std_example.rs2
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/int.rs2
-rw-r--r--compiler/rustc_codegen_llvm/Cargo.toml1
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs66
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs259
-rw-r--r--compiler/rustc_codegen_llvm/src/consts.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs1
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs74
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs36
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs16
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs1
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/intrinsic.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs2
-rw-r--r--compiler/rustc_const_eval/src/lib.rs1
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs5
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/ops.rs13
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs12
-rw-r--r--compiler/rustc_data_structures/src/lib.rs1
-rw-r--r--compiler/rustc_driver/Cargo.toml2
-rw-r--r--compiler/rustc_driver/src/lib.rs1
-rw-r--r--compiler/rustc_driver/src/pretty.rs4
-rw-r--r--compiler/rustc_error_codes/src/error_codes.rs2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0094.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0211.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0311.md42
-rw-r--r--compiler/rustc_error_messages/locales/en-US/parser.ftl211
-rw-r--r--compiler/rustc_error_messages/locales/en-US/session.ftl2
-rw-r--r--compiler/rustc_errors/Cargo.toml2
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs20
-rw-r--r--compiler/rustc_errors/src/lib.rs6
-rw-r--r--compiler/rustc_expand/src/build.rs4
-rw-r--r--compiler/rustc_expand/src/lib.rs1
-rw-r--r--compiler/rustc_feature/src/accepted.rs6
-rw-r--r--compiler/rustc_feature/src/active.rs12
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs1
-rw-r--r--compiler/rustc_feature/src/removed.rs2
-rw-r--r--compiler/rustc_hir/src/def.rs115
-rw-r--r--compiler/rustc_hir/src/hir.rs52
-rw-r--r--compiler/rustc_hir/src/hir_id.rs60
-rw-r--r--compiler/rustc_hir/src/intravisit.rs14
-rw-r--r--compiler/rustc_hir/src/lib.rs3
-rw-r--r--compiler/rustc_hir/src/stable_hash_impls.rs10
-rw-r--r--compiler/rustc_hir_analysis/Cargo.toml (renamed from compiler/rustc_typeck/Cargo.toml)2
-rw-r--r--compiler/rustc_hir_analysis/README.md (renamed from compiler/rustc_typeck/README.md)0
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/errors.rs (renamed from compiler/rustc_typeck/src/astconv/errors.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/generics.rs (renamed from compiler/rustc_typeck/src/astconv/generics.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs (renamed from compiler/rustc_typeck/src/astconv/mod.rs)44
-rw-r--r--compiler/rustc_hir_analysis/src/bounds.rs (renamed from compiler/rustc_typeck/src/bounds.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/_match.rs (renamed from compiler/rustc_typeck/src/check/_match.rs)4
-rw-r--r--compiler/rustc_hir_analysis/src/check/autoderef.rs (renamed from compiler/rustc_typeck/src/check/autoderef.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/callee.rs (renamed from compiler/rustc_typeck/src/check/callee.rs)274
-rw-r--r--compiler/rustc_hir_analysis/src/check/cast.rs (renamed from compiler/rustc_typeck/src/check/cast.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs (renamed from compiler/rustc_typeck/src/check/check.rs)29
-rw-r--r--compiler/rustc_hir_analysis/src/check/closure.rs (renamed from compiler/rustc_typeck/src/check/closure.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/coercion.rs (renamed from compiler/rustc_typeck/src/check/coercion.rs)6
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_method.rs (renamed from compiler/rustc_typeck/src/check/compare_method.rs)1
-rw-r--r--compiler/rustc_hir_analysis/src/check/demand.rs (renamed from compiler/rustc_typeck/src/check/demand.rs)2
-rw-r--r--compiler/rustc_hir_analysis/src/check/diverges.rs (renamed from compiler/rustc_typeck/src/check/diverges.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/dropck.rs (renamed from compiler/rustc_typeck/src/check/dropck.rs)2
-rw-r--r--compiler/rustc_hir_analysis/src/check/expectation.rs (renamed from compiler/rustc_typeck/src/check/expectation.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/expr.rs (renamed from compiler/rustc_typeck/src/check/expr.rs)6
-rw-r--r--compiler/rustc_hir_analysis/src/check/fallback.rs (renamed from compiler/rustc_typeck/src/check/fallback.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs (renamed from compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/fn_ctxt/arg_matrix.rs (renamed from compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/fn_ctxt/checks.rs (renamed from compiler/rustc_typeck/src/check/fn_ctxt/checks.rs)7
-rw-r--r--compiler/rustc_hir_analysis/src/check/fn_ctxt/mod.rs (renamed from compiler/rustc_typeck/src/check/fn_ctxt/mod.rs)1
-rw-r--r--compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs (renamed from compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/gather_locals.rs (renamed from compiler/rustc_typeck/src/check/gather_locals.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/generator_interior.rs (renamed from compiler/rustc_typeck/src/check/generator_interior.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges.rs (renamed from compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_build.rs (renamed from compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_propagate.rs (renamed from compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_propagate.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_visualize.rs (renamed from compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs (renamed from compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/inherited.rs (renamed from compiler/rustc_typeck/src/check/inherited.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs (renamed from compiler/rustc_typeck/src/check/intrinsic.rs)27
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsicck.rs (renamed from compiler/rustc_typeck/src/check/intrinsicck.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/method/confirm.rs (renamed from compiler/rustc_typeck/src/check/method/confirm.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/method/mod.rs (renamed from compiler/rustc_typeck/src/check/method/mod.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/method/prelude2021.rs (renamed from compiler/rustc_typeck/src/check/method/prelude2021.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/method/probe.rs (renamed from compiler/rustc_typeck/src/check/method/probe.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/method/suggest.rs (renamed from compiler/rustc_typeck/src/check/method/suggest.rs)212
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs (renamed from compiler/rustc_typeck/src/check/mod.rs)2
-rw-r--r--compiler/rustc_hir_analysis/src/check/op.rs (renamed from compiler/rustc_typeck/src/check/op.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/pat.rs (renamed from compiler/rustc_typeck/src/check/pat.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/place_op.rs (renamed from compiler/rustc_typeck/src/check/place_op.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs (renamed from compiler/rustc_typeck/src/check/region.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/rvalue_scopes.rs (renamed from compiler/rustc_typeck/src/check/rvalue_scopes.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/upvar.rs (renamed from compiler/rustc_typeck/src/check/upvar.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs (renamed from compiler/rustc_typeck/src/check/wfcheck.rs)61
-rw-r--r--compiler/rustc_hir_analysis/src/check/writeback.rs (renamed from compiler/rustc_typeck/src/check/writeback.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check_unused.rs (renamed from compiler/rustc_typeck/src/check_unused.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs (renamed from compiler/rustc_typeck/src/coherence/builtin.rs)18
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs (renamed from compiler/rustc_typeck/src/coherence/inherent_impls.rs)6
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs (renamed from compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/mod.rs (renamed from compiler/rustc_typeck/src/coherence/mod.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs (renamed from compiler/rustc_typeck/src/coherence/orphan.rs)2
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/unsafety.rs (renamed from compiler/rustc_typeck/src/coherence/unsafety.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs (renamed from compiler/rustc_typeck/src/collect.rs)1228
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs481
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs (renamed from compiler/rustc_typeck/src/collect/item_bounds.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs707
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs (renamed from compiler/rustc_typeck/src/collect/type_of.rs)137
-rw-r--r--compiler/rustc_hir_analysis/src/constrained_generic_params.rs (renamed from compiler/rustc_typeck/src/constrained_generic_params.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs (renamed from compiler/rustc_typeck/src/errors.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/expr_use_visitor.rs (renamed from compiler/rustc_typeck/src/expr_use_visitor.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/hir_wf_check.rs (renamed from compiler/rustc_typeck/src/hir_wf_check.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check.rs (renamed from compiler/rustc_typeck/src/impl_wf_check.rs)6
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs (renamed from compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs)11
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs (renamed from compiler/rustc_typeck/src/lib.rs)2
-rw-r--r--compiler/rustc_hir_analysis/src/mem_categorization.rs (renamed from compiler/rustc_typeck/src/mem_categorization.rs)15
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/explicit.rs (renamed from compiler/rustc_typeck/src/outlives/explicit.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs (renamed from compiler/rustc_typeck/src/outlives/implicit_infer.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/mod.rs (renamed from compiler/rustc_typeck/src/outlives/mod.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/test.rs (renamed from compiler/rustc_typeck/src/outlives/test.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/utils.rs (renamed from compiler/rustc_typeck/src/outlives/utils.rs)17
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors.rs (renamed from compiler/rustc_typeck/src/structured_errors.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs (renamed from compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs (renamed from compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs (renamed from compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/variance/constraints.rs (renamed from compiler/rustc_typeck/src/variance/constraints.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/variance/mod.rs (renamed from compiler/rustc_typeck/src/variance/mod.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/variance/solve.rs (renamed from compiler/rustc_typeck/src/variance/solve.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/variance/terms.rs (renamed from compiler/rustc_typeck/src/variance/terms.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/variance/test.rs (renamed from compiler/rustc_typeck/src/variance/test.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/variance/xform.rs (renamed from compiler/rustc_typeck/src/variance/xform.rs)0
-rw-r--r--compiler/rustc_incremental/src/lib.rs1
-rw-r--r--compiler/rustc_incremental/src/persist/dirty_clean.rs8
-rw-r--r--compiler/rustc_index/src/lib.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs7
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs8
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs3
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs7
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs2
-rw-r--r--compiler/rustc_infer/src/infer/outlives/components.rs17
-rw-r--r--compiler/rustc_infer/src/infer/outlives/env.rs6
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs144
-rw-r--r--compiler/rustc_infer/src/infer/outlives/verify.rs109
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/mod.rs10
-rw-r--r--compiler/rustc_infer/src/lib.rs4
-rw-r--r--compiler/rustc_infer/src/traits/util.rs12
-rw-r--r--compiler/rustc_interface/Cargo.toml2
-rw-r--r--compiler/rustc_interface/src/lib.rs1
-rw-r--r--compiler/rustc_interface/src/passes.rs5
-rw-r--r--compiler/rustc_interface/src/proc_macro_decls.rs5
-rw-r--r--compiler/rustc_interface/src/tests.rs1
-rw-r--r--compiler/rustc_lexer/src/cursor.rs16
-rw-r--r--compiler/rustc_lexer/src/lib.rs53
-rw-r--r--compiler/rustc_lexer/src/unescape.rs27
-rw-r--r--compiler/rustc_lint/src/builtin.rs242
-rw-r--r--compiler/rustc_lint/src/context.rs2
-rw-r--r--compiler/rustc_lint/src/internal.rs2
-rw-r--r--compiler/rustc_lint/src/lib.rs2
-rw-r--r--compiler/rustc_lint/src/pass_by_value.rs2
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp258
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp8
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic.rs157
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs674
-rw-r--r--compiler/rustc_macros/src/diagnostics/subdiagnostic.rs349
-rw-r--r--compiler/rustc_macros/src/diagnostics/utils.rs353
-rw-r--r--compiler/rustc_macros/src/lib.rs1
-rw-r--r--compiler/rustc_metadata/src/lib.rs2
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs9
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs43
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs3
-rw-r--r--compiler/rustc_middle/benches/lib.rs54
-rw-r--r--compiler/rustc_middle/src/dep_graph/dep_node.rs116
-rw-r--r--compiler/rustc_middle/src/dep_graph/mod.rs52
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs59
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs36
-rw-r--r--compiler/rustc_middle/src/lib.rs2
-rw-r--r--compiler/rustc_middle/src/middle/resolve_lifetime.rs8
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs4
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs1
-rw-r--r--compiler/rustc_middle/src/query/mod.rs21
-rw-r--r--compiler/rustc_middle/src/thir.rs4
-rw-r--r--compiler/rustc_middle/src/traits/query.rs4
-rw-r--r--compiler/rustc_middle/src/ty/adt.rs3
-rw-r--r--compiler/rustc_middle/src/ty/cast.rs2
-rw-r--r--compiler/rustc_middle/src/ty/context.rs27
-rw-r--r--compiler/rustc_middle/src/ty/error.rs2
-rw-r--r--compiler/rustc_middle/src/ty/parameterized.rs5
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs87
-rw-r--r--compiler/rustc_middle/src/ty/query.rs10
-rw-r--r--compiler/rustc_middle/src/ty/rvalue_scopes.rs2
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs32
-rw-r--r--compiler/rustc_middle/src/ty/subst.rs1
-rw-r--r--compiler/rustc_middle/src/ty/util.rs16
-rw-r--r--compiler/rustc_mir_build/src/build/block.rs43
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs2
-rw-r--r--compiler/rustc_mir_build/src/lib.rs1
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs5
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/lib.rs1
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs1
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs4
-rw-r--r--compiler/rustc_monomorphize/src/lib.rs1
-rw-r--r--compiler/rustc_parse/src/errors.rs1251
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs390
-rw-r--r--compiler/rustc_parse/src/lexer/tokentrees.rs394
-rw-r--r--compiler/rustc_parse/src/lib.rs3
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs159
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs939
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs401
-rw-r--r--compiler/rustc_parse/src/parser/item.rs112
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs114
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs2
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs104
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs11
-rw-r--r--compiler/rustc_parse_format/src/lib.rs2
-rw-r--r--compiler/rustc_passes/src/check_attr.rs16
-rw-r--r--compiler/rustc_passes/src/dead.rs43
-rw-r--r--compiler/rustc_passes/src/diagnostic_items.rs8
-rw-r--r--compiler/rustc_passes/src/entry.rs8
-rw-r--r--compiler/rustc_passes/src/errors.rs4
-rw-r--r--compiler/rustc_passes/src/hir_id_validator.rs15
-rw-r--r--compiler/rustc_passes/src/layout_test.rs2
-rw-r--r--compiler/rustc_passes/src/lib.rs1
-rw-r--r--compiler/rustc_passes/src/reachable.rs14
-rw-r--r--compiler/rustc_passes/src/stability.rs24
-rw-r--r--compiler/rustc_privacy/Cargo.toml2
-rw-r--r--compiler/rustc_privacy/src/lib.rs126
-rw-r--r--compiler/rustc_query_impl/src/keys.rs14
-rw-r--r--compiler/rustc_query_impl/src/lib.rs2
-rw-r--r--compiler/rustc_query_impl/src/plumbing.rs142
-rw-r--r--compiler/rustc_query_impl/src/profiling_support.rs25
-rw-r--r--compiler/rustc_query_system/src/dep_graph/dep_node.rs73
-rw-r--r--compiler/rustc_query_system/src/dep_graph/mod.rs39
-rw-r--r--compiler/rustc_query_system/src/ich/hcx.rs7
-rw-r--r--compiler/rustc_query_system/src/lib.rs1
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs3
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs2
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs10
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs25
-rw-r--r--compiler/rustc_resolve/src/ident.rs22
-rw-r--r--compiler/rustc_resolve/src/late.rs122
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs615
-rw-r--r--compiler/rustc_resolve/src/late/lifetimes.rs87
-rw-r--r--compiler/rustc_resolve/src/lib.rs3
-rw-r--r--compiler/rustc_save_analysis/src/dump_visitor.rs49
-rw-r--r--compiler/rustc_save_analysis/src/lib.rs10
-rw-r--r--compiler/rustc_save_analysis/src/sig.rs2
-rw-r--r--compiler/rustc_serialize/src/lib.rs1
-rw-r--r--compiler/rustc_session/src/errors.rs15
-rw-r--r--compiler/rustc_session/src/lib.rs1
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_session/src/parse.rs20
-rw-r--r--compiler/rustc_session/src/session.rs44
-rw-r--r--compiler/rustc_span/src/lib.rs1
-rw-r--r--compiler/rustc_span/src/symbol.rs15
-rw-r--r--compiler/rustc_symbol_mangling/src/test.rs8
-rw-r--r--compiler/rustc_target/src/lib.rs1
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs3
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs3
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs3
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_unknown_openbsd.rs3
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs3
-rw-r--r--compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs3
-rw-r--r--compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs3
-rw-r--r--compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs3
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs3
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs3
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs3
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs3
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs3
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_openbsd.rs3
-rw-r--r--compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs3
-rw-r--r--compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs3
-rw-r--r--compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs3
-rw-r--r--compiler/rustc_target/src/spec/s390x_unknown_linux_musl.rs3
-rw-r--r--compiler/rustc_trait_selection/src/lib.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs24
-rw-r--r--compiler/rustc_trait_selection/src/traits/outlives_bounds.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs43
-rw-r--r--compiler/rustc_traits/src/implied_outlives_bounds.rs72
-rw-r--r--compiler/rustc_traits/src/lib.rs1
-rw-r--r--compiler/rustc_ty_utils/src/assoc.rs2
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs2
-rw-r--r--compiler/rustc_ty_utils/src/lib.rs1
-rw-r--r--config.toml.example4
-rw-r--r--library/alloc/src/boxed.rs14
-rw-r--r--library/alloc/src/boxed/thin.rs2
-rw-r--r--library/alloc/src/collections/btree/map.rs6
-rw-r--r--library/alloc/src/collections/btree/map/entry.rs1
-rw-r--r--library/alloc/src/collections/btree/set.rs6
-rw-r--r--library/alloc/src/collections/mod.rs1
-rw-r--r--library/alloc/src/collections/vec_deque/mod.rs14
-rw-r--r--library/alloc/src/ffi/c_str.rs3
-rw-r--r--library/alloc/src/lib.rs10
-rw-r--r--library/alloc/src/raw_vec.rs12
-rw-r--r--library/alloc/src/slice.rs6
-rw-r--r--library/alloc/src/string.rs3
-rw-r--r--library/alloc/src/sync.rs1
-rw-r--r--library/alloc/src/vec/drain.rs4
-rw-r--r--library/alloc/src/vec/in_place_collect.rs4
-rw-r--r--library/alloc/src/vec/into_iter.rs16
-rw-r--r--library/alloc/src/vec/mod.rs6
-rw-r--r--library/alloc/tests/lib.rs3
-rw-r--r--library/core/src/alloc/layout.rs2
-rw-r--r--library/core/src/alloc/mod.rs2
-rw-r--r--library/core/src/array/mod.rs5
-rw-r--r--library/core/src/cell.rs1
-rw-r--r--library/core/src/char/decode.rs2
-rw-r--r--library/core/src/char/mod.rs2
-rw-r--r--library/core/src/cmp.rs55
-rw-r--r--library/core/src/convert/mod.rs4
-rw-r--r--library/core/src/fmt/mod.rs7
-rw-r--r--library/core/src/hint.rs2
-rw-r--r--library/core/src/intrinsics.rs103
-rw-r--r--library/core/src/iter/traits/iterator.rs25
-rw-r--r--library/core/src/lib.rs3
-rw-r--r--library/core/src/marker.rs2
-rw-r--r--library/core/src/mem/mod.rs41
-rw-r--r--library/core/src/mem/transmutability.rs4
-rw-r--r--library/core/src/num/error.rs3
-rw-r--r--library/core/src/num/int_macros.rs40
-rw-r--r--library/core/src/num/mod.rs2
-rw-r--r--library/core/src/num/nonzero.rs154
-rw-r--r--library/core/src/num/uint_macros.rs20
-rw-r--r--library/core/src/ops/generator.rs1
-rw-r--r--library/core/src/ops/range.rs2
-rw-r--r--library/core/src/ops/try_trait.rs84
-rw-r--r--library/core/src/option.rs15
-rw-r--r--library/core/src/ptr/const_ptr.rs5
-rw-r--r--library/core/src/ptr/mut_ptr.rs5
-rw-r--r--library/core/src/slice/iter.rs16
-rw-r--r--library/core/src/slice/iter/macros.rs8
-rw-r--r--library/core/src/slice/mod.rs43
-rw-r--r--library/core/src/slice/rotate.rs4
-rw-r--r--library/core/src/slice/sort.rs6
-rw-r--r--library/core/src/str/error.rs3
-rw-r--r--library/core/src/str/mod.rs1
-rw-r--r--library/core/src/time.rs98
-rw-r--r--library/core/src/tuple.rs3
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/std/src/backtrace.rs26
-rw-r--r--library/std/src/collections/hash/map.rs2
-rw-r--r--library/std/src/env.rs2
-rw-r--r--library/std/src/error.rs1023
-rw-r--r--library/std/src/io/error.rs1
-rw-r--r--library/std/src/io/mod.rs2
-rw-r--r--library/std/src/lib.rs10
-rw-r--r--library/std/src/os/fd/mod.rs13
-rw-r--r--library/std/src/os/fd/owned.rs6
-rw-r--r--library/std/src/os/fd/raw.rs18
-rw-r--r--library/std/src/os/mod.rs2
-rw-r--r--library/std/src/os/unix/io/fd.rs8
-rw-r--r--library/std/src/os/unix/io/mod.rs11
-rw-r--r--library/std/src/os/unix/io/raw.rs6
-rw-r--r--library/std/src/os/unix/io/tests.rs (renamed from library/std/src/os/unix/io/fd/tests.rs)0
-rw-r--r--library/std/src/os/wasi/io/mod.rs8
-rw-r--r--library/std/src/rt.rs5
-rw-r--r--library/std/src/sync/rwlock.rs1
-rw-r--r--library/std/src/sys/unix/os.rs4
-rw-r--r--library/std/src/sys/unix/time.rs34
-rw-r--r--library/std/src/sys/unsupported/locks/condvar.rs1
-rw-r--r--library/std/src/sys/unsupported/locks/mutex.rs1
-rw-r--r--library/std/src/sys/unsupported/locks/rwlock.rs1
-rw-r--r--library/std/src/sys_common/condvar.rs1
-rw-r--r--library/std/src/sys_common/condvar/check.rs1
-rw-r--r--library/std/src/sys_common/mutex.rs1
-rw-r--r--library/std/src/sys_common/rwlock.rs1
-rw-r--r--library/std/src/thread/local.rs1
-rw-r--r--library/test/src/lib.rs1
-rw-r--r--src/bootstrap/build.rs36
-rw-r--r--src/bootstrap/builder.rs6
-rw-r--r--src/bootstrap/compile.rs15
-rw-r--r--src/bootstrap/config.rs64
-rw-r--r--src/bootstrap/dist.rs69
-rw-r--r--src/bootstrap/lib.rs26
-rw-r--r--src/ci/docker/host-x86_64/disabled/dist-x86_64-haiku/Dockerfile2
-rw-r--r--src/ci/docker/host-x86_64/dist-various-2/Dockerfile2
-rw-r--r--src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile2
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-llvm-13-stage1/Dockerfile1
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-llvm-13/Dockerfile1
-rw-r--r--src/ci/github-actions/ci.yml20
-rwxr-xr-xsrc/ci/run.sh5
-rw-r--r--src/doc/unstable-book/src/compiler-flags/self-profile-events.md2
-rw-r--r--src/etc/natvis/libcore.natvis4
-rw-r--r--src/librustdoc/clean/inline.rs4
-rw-r--r--src/librustdoc/clean/mod.rs12
-rw-r--r--src/librustdoc/clean/types.rs30
-rw-r--r--src/librustdoc/clean/utils.rs4
-rw-r--r--src/librustdoc/core.rs10
-rw-r--r--src/librustdoc/fold.rs2
-rw-r--r--src/librustdoc/formats/cache.rs11
-rw-r--r--src/librustdoc/html/highlight.rs9
-rw-r--r--src/librustdoc/html/render/mod.rs13
-rw-r--r--src/librustdoc/html/render/print_item.rs2
-rw-r--r--src/librustdoc/html/sources.rs2
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css144
-rw-r--r--src/librustdoc/html/static/css/settings.css3
-rw-r--r--src/librustdoc/html/static/css/themes/ayu.css8
-rw-r--r--src/librustdoc/html/static/css/themes/dark.css8
-rw-r--r--src/librustdoc/html/static/css/themes/light.css8
-rw-r--r--src/librustdoc/html/static/js/main.js7
-rw-r--r--src/librustdoc/html/static/js/scrape-examples.js2
-rw-r--r--src/librustdoc/html/static/js/source-script.js4
-rw-r--r--src/librustdoc/json/conversions.rs7
-rw-r--r--src/librustdoc/json/mod.rs8
-rw-r--r--src/librustdoc/lib.rs6
-rw-r--r--src/librustdoc/passes/propagate_doc_cfg.rs2
-rw-r--r--src/librustdoc/scrape_examples.rs11
-rw-r--r--src/librustdoc/visit.rs2
-rw-r--r--src/rustdoc-json-types/lib.rs10
-rw-r--r--src/stage0.json676
-rw-r--r--src/test/codegen/stack-probes-call.rs22
-rw-r--r--src/test/codegen/stack-probes-inline.rs26
-rw-r--r--src/test/codegen/stack-probes.rs22
-rw-r--r--src/test/incremental/spans_significant_w_panic.rs1
-rw-r--r--src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff6
-rw-r--r--src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff2
-rw-r--r--src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff2
-rw-r--r--src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff2
-rw-r--r--src/test/mir-opt/derefer_complex_case.main.Derefer.diff2
-rw-r--r--src/test/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.diff4
-rw-r--r--src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff8
-rw-r--r--src/test/mir-opt/inline/cycle.f.Inline.diff2
-rw-r--r--src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff6
-rw-r--r--src/test/mir-opt/inline/dyn_trait.mk_cycle.Inline.diff2
-rw-r--r--src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff4
-rw-r--r--src/test/mir-opt/inline/inline_generator.main.Inline.diff2
-rw-r--r--src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir6
-rw-r--r--src/test/mir-opt/inline/inline_shims.clone.Inline.diff2
-rw-r--r--src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir2
-rw-r--r--src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir2
-rw-r--r--src/test/mir-opt/inline/issue_78442.bar.Inline.diff2
-rw-r--r--src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff4
-rw-r--r--src/test/mir-opt/issue-101867.rs2
-rw-r--r--src/test/mir-opt/issue_101867.main.mir_map.0.mir4
-rw-r--r--src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff2
-rw-r--r--src/test/mir-opt/issue_91633.bar.mir_map.0.mir2
-rw-r--r--src/test/mir-opt/issue_91633.foo.mir_map.0.mir2
-rw-r--r--src/test/mir-opt/issue_91633.hey.mir_map.0.mir2
-rw-r--r--src/test/mir-opt/issue_99325.main.mir_map.0.mir8
-rw-r--r--src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff8
-rw-r--r--src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff2
-rw-r--r--src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir2
-rw-r--r--src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff4
-rw-r--r--src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff2
-rw-r--r--src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir2
-rw-r--r--src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir2
-rw-r--r--src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir10
-rw-r--r--src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir2
-rw-r--r--src/test/pretty/issue-4264.pp2
-rw-r--r--src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/src/lib.rs8
-rw-r--r--src/test/rustdoc-gui/anchor-navigable.goml2
-rw-r--r--src/test/rustdoc-gui/basic-code.goml2
-rw-r--r--src/test/rustdoc-gui/docblock-code-block-line-number.goml12
-rw-r--r--src/test/rustdoc-gui/font-weight.goml4
-rw-r--r--src/test/rustdoc-gui/headers-color.goml6
-rw-r--r--src/test/rustdoc-gui/implementors.goml8
-rw-r--r--src/test/rustdoc-gui/search-result-color.goml153
-rw-r--r--src/test/rustdoc-gui/sidebar-mobile-scroll.goml6
-rw-r--r--src/test/rustdoc-gui/source-code-page.goml16
-rw-r--r--src/test/rustdoc-gui/src-font-size.goml8
-rw-r--r--src/test/rustdoc-gui/src/lib2/lib.rs3
-rw-r--r--src/test/rustdoc-js-std/asrawfd.js6
-rw-r--r--src/test/rustdoc-json/primitives/primitive_impls.rs34
-rw-r--r--src/test/rustdoc-json/primitives/primitive_overloading.rs (renamed from src/test/rustdoc-json/primitive_overloading.rs)0
-rw-r--r--src/test/rustdoc-json/primitives/primitive_type.rs (renamed from src/test/rustdoc-json/primitives.rs)0
-rw-r--r--src/test/rustdoc-json/primitives/use_primitive.rs (renamed from src/test/rustdoc-json/primitive.rs)2
-rw-r--r--src/test/rustdoc-ui/diagnostic-width.rs2
-rw-r--r--src/test/rustdoc-ui/z-help.stdout1
-rw-r--r--src/test/rustdoc/anonymous-lifetime.rs2
-rw-r--r--src/test/rustdoc/assoc-consts.rs4
-rw-r--r--src/test/rustdoc/blanket-reexport-item.rs2
-rw-r--r--src/test/rustdoc/const-generics/add-impl.rs2
-rw-r--r--src/test/rustdoc/const-generics/const-generics-docs.rs12
-rw-r--r--src/test/rustdoc/const-generics/const-impl.rs10
-rw-r--r--src/test/rustdoc/const-generics/lazy_normalization_consts/const-equate-pred.rs2
-rw-r--r--src/test/rustdoc/duplicate_impls/issue-33054.rs6
-rw-r--r--src/test/rustdoc/empty-impl-block.rs2
-rw-r--r--src/test/rustdoc/extern-impl.rs6
-rw-r--r--src/test/rustdoc/fn-bound.rs2
-rw-r--r--src/test/rustdoc/generic-impl.rs2
-rw-r--r--src/test/rustdoc/higher-ranked-trait-bounds.rs2
-rw-r--r--src/test/rustdoc/impl-disambiguation.rs10
-rw-r--r--src/test/rustdoc/impl-parts.rs4
-rw-r--r--src/test/rustdoc/inline_cross/issue-31948-1.rs20
-rw-r--r--src/test/rustdoc/inline_cross/issue-31948-2.rs12
-rw-r--r--src/test/rustdoc/inline_cross/issue-31948.rs20
-rw-r--r--src/test/rustdoc/inline_cross/issue-32881.rs4
-rw-r--r--src/test/rustdoc/inline_cross/issue-33113.rs4
-rw-r--r--src/test/rustdoc/inline_cross/trait-vis.rs2
-rw-r--r--src/test/rustdoc/inline_local/trait-vis.rs4
-rw-r--r--src/test/rustdoc/issue-29503.rs2
-rw-r--r--src/test/rustdoc/issue-33592.rs4
-rw-r--r--src/test/rustdoc/issue-46727.rs2
-rw-r--r--src/test/rustdoc/issue-50159.rs4
-rw-r--r--src/test/rustdoc/issue-51236.rs2
-rw-r--r--src/test/rustdoc/issue-54705.rs4
-rw-r--r--src/test/rustdoc/issue-55321.rs8
-rw-r--r--src/test/rustdoc/issue-56822.rs2
-rw-r--r--src/test/rustdoc/issue-60726.rs4
-rw-r--r--src/test/rustdoc/issue-75588.rs4
-rw-r--r--src/test/rustdoc/issue-80233-normalize-auto-trait.rs2
-rw-r--r--src/test/rustdoc/issue-82465-asref-for-and-of-local.rs4
-rw-r--r--src/test/rustdoc/issue-98697.rs4
-rw-r--r--src/test/rustdoc/negative-impl.rs4
-rw-r--r--src/test/rustdoc/primitive-reference.rs2
-rw-r--r--src/test/rustdoc/primitive/primitive-generic-impl.rs2
-rw-r--r--src/test/rustdoc/recursive-deref.rs18
-rw-r--r--src/test/rustdoc/rfc-2632-const-trait-impl.rs8
-rw-r--r--src/test/rustdoc/safe-intrinsic.rs2
-rw-r--r--src/test/rustdoc/sidebar-links-to-foreign-impl.rs4
-rw-r--r--src/test/rustdoc/sized_trait.rs2
-rw-r--r--src/test/rustdoc/src-links-auto-impls.rs6
-rw-r--r--src/test/rustdoc/synthetic_auto/basic.rs4
-rw-r--r--src/test/rustdoc/synthetic_auto/complex.rs2
-rw-r--r--src/test/rustdoc/synthetic_auto/crate-local.rs6
-rw-r--r--src/test/rustdoc/synthetic_auto/lifetimes.rs4
-rw-r--r--src/test/rustdoc/synthetic_auto/manual.rs4
-rw-r--r--src/test/rustdoc/synthetic_auto/negative.rs4
-rw-r--r--src/test/rustdoc/synthetic_auto/nested.rs4
-rw-r--r--src/test/rustdoc/synthetic_auto/no-redundancy.rs2
-rw-r--r--src/test/rustdoc/synthetic_auto/overflow.rs2
-rw-r--r--src/test/rustdoc/synthetic_auto/project.rs4
-rw-r--r--src/test/rustdoc/synthetic_auto/self-referential.rs2
-rw-r--r--src/test/rustdoc/synthetic_auto/static-region.rs2
-rw-r--r--src/test/rustdoc/toggle-trait-fn.rs12
-rw-r--r--src/test/rustdoc/traits-in-bodies.rs6
-rw-r--r--src/test/rustdoc/typedef.rs4
-rw-r--r--src/test/rustdoc/where.rs10
-rw-r--r--src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs2
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs116
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr355
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs24
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr172
-rw-r--r--src/test/ui/abi/stack-probes-lto.rs2
-rw-r--r--src/test/ui/abi/stack-probes.rs29
-rw-r--r--src/test/ui/anonymous-higher-ranked-lifetime.stderr20
-rw-r--r--src/test/ui/asm/aarch64/type-check-2-2.stderr10
-rw-r--r--src/test/ui/asm/x86_64/type-check-5.stderr10
-rw-r--r--src/test/ui/associated-consts/issue-102335-const.rs12
-rw-r--r--src/test/ui/associated-consts/issue-102335-const.stderr9
-rw-r--r--src/test/ui/associated-type-bounds/issue-102335-ty.rs12
-rw-r--r--src/test/ui/associated-type-bounds/issue-102335-ty.stderr9
-rw-r--r--src/test/ui/async-await/await-keyword/2018-edition-error-in-non-macro-position.stderr4
-rw-r--r--src/test/ui/async-await/in-trait/issue-102138.rs46
-rw-r--r--src/test/ui/async-await/in-trait/issue-102219.rs10
-rw-r--r--src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr2
-rw-r--r--src/test/ui/binop/issue-77910-1.rs2
-rw-r--r--src/test/ui/binop/issue-77910-1.stderr10
-rw-r--r--src/test/ui/binop/issue-77910-2.stderr4
-rw-r--r--src/test/ui/borrowck/borrowck-block-unint.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-break-uninit-2.stderr4
-rw-r--r--src/test/ui/borrowck/borrowck-break-uninit.stderr4
-rw-r--r--src/test/ui/borrowck/borrowck-init-in-called-fn-expr.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-init-in-fn-expr.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-init-in-fru.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-init-op-equal.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-init-plus-equal.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-return.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-storage-dead.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-uninit-after-item.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-uninit-field-access.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-uninit-in-assignop.stderr50
-rw-r--r--src/test/ui/borrowck/borrowck-uninit-ref-chain.stderr15
-rw-r--r--src/test/ui/borrowck/borrowck-uninit.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-use-in-index-lvalue.stderr10
-rw-r--r--src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-while-cond.stderr5
-rw-r--r--src/test/ui/borrowck/issue-24267-flow-exit.stderr8
-rw-r--r--src/test/ui/borrowck/issue-62107-match-arm-scopes.stderr5
-rw-r--r--src/test/ui/borrowck/reborrow-sugg-move-then-borrow.rs26
-rw-r--r--src/test/ui/borrowck/reborrow-sugg-move-then-borrow.stderr24
-rw-r--r--src/test/ui/borrowck/suggest-assign-rvalue.rs57
-rw-r--r--src/test/ui/borrowck/suggest-assign-rvalue.stderr138
-rw-r--r--src/test/ui/box/issue-95036.rs2
-rw-r--r--src/test/ui/check-static-values-constraints.rs2
-rw-r--r--src/test/ui/check-static-values-constraints.stderr4
-rw-r--r--src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr6
-rw-r--r--src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr5
-rw-r--r--src/test/ui/closures/closure-reform-bad.stderr2
-rw-r--r--src/test/ui/coherence/coherence-negative-impls-copy-bad.rs11
-rw-r--r--src/test/ui/coherence/coherence-negative-impls-copy-bad.stderr36
-rw-r--r--src/test/ui/coherence/coherence-negative-impls-copy.rs29
-rw-r--r--src/test/ui/coherence/deep-bad-copy-reason.stderr4
-rw-r--r--src/test/ui/compare-method/issue-90444.stderr6
-rw-r--r--src/test/ui/const-generics/const-generic-default-wont-borrowck.stderr5
-rw-r--r--src/test/ui/consts/cast-discriminant-zst-enum.rs1
-rw-r--r--src/test/ui/consts/const-eval/const_let.rs8
-rw-r--r--src/test/ui/consts/const-eval/const_let.stderr16
-rw-r--r--src/test/ui/consts/const-eval/issue-100878.rs8
-rw-r--r--src/test/ui/consts/const-eval/issue-65394.rs2
-rw-r--r--src/test/ui/consts/const-eval/issue-65394.stderr4
-rw-r--r--src/test/ui/consts/const-eval/livedrop.rs2
-rw-r--r--src/test/ui/consts/const-eval/livedrop.stderr4
-rw-r--r--src/test/ui/consts/const-eval/ub-enum.32bit.stderr36
-rw-r--r--src/test/ui/consts/const-eval/ub-enum.64bit.stderr36
-rw-r--r--src/test/ui/consts/const-eval/ub-enum.rs1
-rw-r--r--src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr8
-rw-r--r--src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr8
-rw-r--r--src/test/ui/consts/const_discriminant.rs1
-rw-r--r--src/test/ui/consts/control-flow/drop-fail.precise.stderr8
-rw-r--r--src/test/ui/consts/control-flow/drop-fail.rs8
-rw-r--r--src/test/ui/consts/control-flow/drop-fail.stock.stderr16
-rw-r--r--src/test/ui/consts/drop_box.rs2
-rw-r--r--src/test/ui/consts/drop_box.stderr4
-rw-r--r--src/test/ui/consts/drop_zst.stderr4
-rw-r--r--src/test/ui/consts/issue-78655.stderr5
-rw-r--r--src/test/ui/consts/issue-88071.rs2
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn.rs6
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn.stderr20
-rw-r--r--src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.rs2
-rw-r--r--src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr4
-rw-r--r--src/test/ui/consts/qualif-indirect-mutation-fail.rs18
-rw-r--r--src/test/ui/consts/qualif-indirect-mutation-fail.stderr36
-rw-r--r--src/test/ui/consts/stable-precise-live-drops-in-libcore.rs2
-rw-r--r--src/test/ui/consts/stable-precise-live-drops-in-libcore.stderr4
-rw-r--r--src/test/ui/consts/unstable-const-fn-in-libcore.rs4
-rw-r--r--src/test/ui/consts/unstable-const-fn-in-libcore.stderr8
-rw-r--r--src/test/ui/drop/repeat-drop-2.rs2
-rw-r--r--src/test/ui/drop/repeat-drop-2.stderr9
-rw-r--r--src/test/ui/error-codes/E0094.rs2
-rw-r--r--src/test/ui/error-codes/E0094.stderr2
-rw-r--r--src/test/ui/error-codes/E0308.rs2
-rw-r--r--src/test/ui/error-codes/E0308.stderr2
-rw-r--r--src/test/ui/error-codes/E0311.rs9
-rw-r--r--src/test/ui/error-codes/E0311.stderr24
-rw-r--r--src/test/ui/error-codes/E0585.stderr2
-rw-r--r--src/test/ui/extenv/issue-55897.rs2
-rw-r--r--src/test/ui/extenv/issue-55897.stderr2
-rw-r--r--src/test/ui/extern/extern-with-type-bounds.rs2
-rw-r--r--src/test/ui/extern/extern-with-type-bounds.stderr2
-rw-r--r--src/test/ui/fmt/format-args-capture-issue-102057.rs19
-rw-r--r--src/test/ui/fmt/format-args-capture-issue-102057.stderr45
-rw-r--r--src/test/ui/fmt/format-args-capture-issue-93378.rs4
-rw-r--r--src/test/ui/fmt/format-args-capture-issue-93378.stderr17
-rw-r--r--src/test/ui/fmt/ifmt-bad-arg.rs8
-rw-r--r--src/test/ui/fmt/ifmt-bad-arg.stderr98
-rw-r--r--src/test/ui/function-pointer/issue-102289.rs54
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-86218.stderr23
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-88382.stderr4
-rw-r--r--src/test/ui/generic-associated-types/issue-102333.rs15
-rw-r--r--src/test/ui/generic-associated-types/issue-102335-gat.rs12
-rw-r--r--src/test/ui/generic-associated-types/issue-102335-gat.stderr9
-rw-r--r--src/test/ui/generic-associated-types/issue-86218-2.rs23
-rw-r--r--src/test/ui/generic-associated-types/issue-86218.rs (renamed from src/test/ui/generic-associated-types/bugs/issue-86218.rs)8
-rw-r--r--src/test/ui/generics/issue-94923.rs49
-rw-r--r--src/test/ui/higher-rank-trait-bounds/issue-30786.stderr10
-rw-r--r--src/test/ui/higher-rank-trait-bounds/issue-46989.stderr2
-rw-r--r--src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr16
-rw-r--r--src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs2
-rw-r--r--src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr6
-rw-r--r--src/test/ui/hygiene/impl_items.rs2
-rw-r--r--src/test/ui/hygiene/impl_items.stderr2
-rw-r--r--src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2015.stderr4
-rw-r--r--src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr4
-rw-r--r--src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs2
-rw-r--r--src/test/ui/impl-trait/in-trait/auxiliary/rpitit.rs11
-rw-r--r--src/test/ui/impl-trait/in-trait/foreign.rs9
-rw-r--r--src/test/ui/impl-trait/issues/issue-78722.rs2
-rw-r--r--src/test/ui/impl-trait/issues/issue-78722.stderr4
-rw-r--r--src/test/ui/impl-trait/unactionable_diagnostic.fixed25
-rw-r--r--src/test/ui/impl-trait/unactionable_diagnostic.rs25
-rw-r--r--src/test/ui/impl-trait/unactionable_diagnostic.stderr14
-rw-r--r--src/test/ui/implied-bounds/issue-101951.rs50
-rw-r--r--src/test/ui/intrinsics/intrinsic-alignment.rs1
-rw-r--r--src/test/ui/intrinsics/intrinsics-integer.rs6
-rw-r--r--src/test/ui/intrinsics/safe-intrinsic-mismatch.rs11
-rw-r--r--src/test/ui/intrinsics/safe-intrinsic-mismatch.stderr14
-rw-r--r--src/test/ui/invalid/invalid-llvm-passes.rs2
-rw-r--r--src/test/ui/issues/issue-18919.stderr4
-rw-r--r--src/test/ui/issues/issue-22644.rs2
-rw-r--r--src/test/ui/issues/issue-22644.stderr2
-rw-r--r--src/test/ui/issues/issue-24322.stderr4
-rw-r--r--src/test/ui/issues/issue-40000.stderr4
-rw-r--r--src/test/ui/issues/issue-57362-2.stderr6
-rw-r--r--src/test/ui/issues/issue-75307.rs2
-rw-r--r--src/test/ui/issues/issue-75307.stderr8
-rw-r--r--src/test/ui/issues/issue-99838.rs2
-rw-r--r--src/test/ui/let-else/const-fn.rs1
-rw-r--r--src/test/ui/let-else/let-else-brace-before-else.stderr8
-rw-r--r--src/test/ui/lifetimes/issue-79187-2.stderr2
-rw-r--r--src/test/ui/lifetimes/issue-79187.stderr2
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/issue_74400.stderr2
-rw-r--r--src/test/ui/lifetimes/re-empty-in-error.stderr2
-rw-r--r--src/test/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.stderr1
-rw-r--r--src/test/ui/lint/invalid_value.rs (renamed from src/test/ui/lint/uninitialized-zeroed.rs)30
-rw-r--r--src/test/ui/lint/invalid_value.stderr (renamed from src/test/ui/lint/uninitialized-zeroed.stderr)207
-rw-r--r--src/test/ui/loops/loop-proper-liveness.stderr4
-rw-r--r--src/test/ui/macros/format-parse-errors.stderr2
-rw-r--r--src/test/ui/macros/issue-99265.stderr278
-rw-r--r--src/test/ui/macros/issue-99907.stderr4
-rw-r--r--src/test/ui/mir/drop-elaboration-after-borrowck-error.rs8
-rw-r--r--src/test/ui/mir/drop-elaboration-after-borrowck-error.stderr21
-rw-r--r--src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr2
-rw-r--r--src/test/ui/mismatched_types/closure-mismatch.stderr2
-rw-r--r--src/test/ui/mismatched_types/fn-variance-1.stderr4
-rw-r--r--src/test/ui/mismatched_types/issue-36053-2.stderr4
-rw-r--r--src/test/ui/moves/issue-72649-uninit-in-loop.stderr10
-rw-r--r--src/test/ui/moves/move-into-dead-array-1.stderr5
-rw-r--r--src/test/ui/moves/move-of-addr-of-mut.stderr4
-rw-r--r--src/test/ui/nll/closure-requirements/escape-argument-callee.stderr2
-rw-r--r--src/test/ui/nll/closure-requirements/escape-argument.stderr2
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr2
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr2
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr4
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr2
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr2
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr2
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr2
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr2
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr2
-rw-r--r--src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr2
-rw-r--r--src/test/ui/nll/issue-57642-higher-ranked-subtype.stderr10
-rw-r--r--src/test/ui/nll/issue-97997.stderr4
-rw-r--r--src/test/ui/nll/match-cfg-fake-edges.stderr5
-rw-r--r--src/test/ui/nll/match-on-borrowed.stderr5
-rw-r--r--src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr6
-rw-r--r--src/test/ui/nll/relate_tys/universe-violation.stderr2
-rw-r--r--src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr4
-rw-r--r--src/test/ui/oom_unwind.rs2
-rw-r--r--src/test/ui/opt-in-copy.stderr8
-rw-r--r--src/test/ui/parser/bad-lit-suffixes.rs16
-rw-r--r--src/test/ui/parser/bad-lit-suffixes.stderr16
-rw-r--r--src/test/ui/parser/bad-pointer-type.rs2
-rw-r--r--src/test/ui/parser/bad-pointer-type.stderr11
-rw-r--r--src/test/ui/parser/doc-after-struct-field.rs4
-rw-r--r--src/test/ui/parser/doc-after-struct-field.stderr4
-rw-r--r--src/test/ui/parser/doc-before-extern-rbrace.stderr2
-rw-r--r--src/test/ui/parser/doc-before-fn-rbrace.rs2
-rw-r--r--src/test/ui/parser/doc-before-fn-rbrace.stderr2
-rw-r--r--src/test/ui/parser/doc-before-rbrace.rs2
-rw-r--r--src/test/ui/parser/doc-before-rbrace.stderr2
-rw-r--r--src/test/ui/parser/doc-before-semi.rs2
-rw-r--r--src/test/ui/parser/doc-before-semi.stderr2
-rw-r--r--src/test/ui/parser/doc-before-struct-rbrace-1.rs2
-rw-r--r--src/test/ui/parser/doc-before-struct-rbrace-1.stderr5
-rw-r--r--src/test/ui/parser/doc-before-struct-rbrace-2.rs2
-rw-r--r--src/test/ui/parser/doc-before-struct-rbrace-2.stderr2
-rw-r--r--src/test/ui/parser/doc-inside-trait-item.stderr2
-rw-r--r--src/test/ui/parser/double-pointer.rs7
-rw-r--r--src/test/ui/parser/double-pointer.stderr15
-rw-r--r--src/test/ui/parser/empty-impl-semicolon.rs5
-rw-r--r--src/test/ui/parser/empty-impl-semicolon.stderr8
-rw-r--r--src/test/ui/parser/fn-field-parse-error-ice.stderr2
-rw-r--r--src/test/ui/parser/inner-attr-after-doc-comment.stderr2
-rw-r--r--src/test/ui/parser/issues/issue-101540.rs7
-rw-r--r--src/test/ui/parser/issues/issue-101540.stderr12
-rw-r--r--src/test/ui/parser/issues/issue-34222-1.stderr2
-rw-r--r--src/test/ui/parser/issues/issue-48636.stderr4
-rw-r--r--src/test/ui/parser/issues/issue-68000-unicode-ident-after-missing-comma.stderr2
-rw-r--r--src/test/ui/parser/item-needs-block.rs10
-rw-r--r--src/test/ui/parser/item-needs-block.stderr26
-rw-r--r--src/test/ui/parser/macro/issue-37113.stderr2
-rw-r--r--src/test/ui/parser/mismatched-braces/missing-close-brace-in-struct.stderr3
-rw-r--r--src/test/ui/parser/missing-closing-angle-bracket-struct-field-ty.stderr3
-rw-r--r--src/test/ui/parser/recover-enum2.stderr2
-rw-r--r--src/test/ui/parser/recover-field-semi.stderr8
-rw-r--r--src/test/ui/parser/recover-struct.stderr2
-rw-r--r--src/test/ui/parser/recovered-struct-variant.stderr4
-rw-r--r--src/test/ui/parser/removed-syntax-enum-newtype.stderr4
-rw-r--r--src/test/ui/parser/removed-syntax-field-let.stderr2
-rw-r--r--src/test/ui/parser/removed-syntax-field-semicolon.stderr2
-rw-r--r--src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.stderr2
-rw-r--r--src/test/ui/privacy/associated-item-privacy-inherent.rs6
-rw-r--r--src/test/ui/privacy/associated-item-privacy-inherent.stderr6
-rw-r--r--src/test/ui/privacy/associated-item-privacy-trait.rs6
-rw-r--r--src/test/ui/privacy/associated-item-privacy-trait.stderr6
-rw-r--r--src/test/ui/privacy/private-inferred-type-3.rs2
-rw-r--r--src/test/ui/privacy/private-inferred-type-3.stderr2
-rw-r--r--src/test/ui/privacy/private-inferred-type.rs2
-rw-r--r--src/test/ui/privacy/private-inferred-type.stderr2
-rw-r--r--src/test/ui/proc-macro/derive-bad.stderr5
-rw-r--r--src/test/ui/process/process-panic-after-fork.rs1
-rw-r--r--src/test/ui/pub/pub-restricted-error.stderr2
-rw-r--r--src/test/ui/regions/issue-101280.rs10
-rw-r--r--src/test/ui/regions/issue-101280.stderr14
-rw-r--r--src/test/ui/regions/issue-102374.rs20
-rw-r--r--src/test/ui/regions/issue-102374.stderr14
-rw-r--r--src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr4
-rw-r--r--src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr4
-rw-r--r--src/test/ui/regions/regions-fn-subtyping-return-static-fail.stderr2
-rw-r--r--src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr4
-rw-r--r--src/test/ui/resolve/name-collision-in-trait-fn-sig.rs11
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/specializing-constness-2.rs31
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/specializing-constness-2.stderr19
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/specializing-constness.rs26
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/specializing-constness.stderr8
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/tilde-const-and-const-params.rs34
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.rs6
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr28
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-const.rs2
-rw-r--r--src/test/ui/rfc1623-2.stderr2
-rw-r--r--src/test/ui/sanitize/address.rs4
-rw-r--r--src/test/ui/sanitize/hwaddress.rs2
-rw-r--r--src/test/ui/sanitize/leak.rs2
-rw-r--r--src/test/ui/sanitize/memory-eager.rs1
-rw-r--r--src/test/ui/sanitize/memory.rs1
-rw-r--r--src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs2
-rw-r--r--src/test/ui/span/E0204.stderr8
-rw-r--r--src/test/ui/span/E0493.rs2
-rw-r--r--src/test/ui/span/E0493.stderr4
-rw-r--r--src/test/ui/specialization/const_trait_impl.rs55
-rw-r--r--src/test/ui/static/static-drop-scope.rs16
-rw-r--r--src/test/ui/static/static-drop-scope.stderr32
-rw-r--r--src/test/ui/statics/uninhabited-static.stderr12
-rw-r--r--src/test/ui/stats/hir-stats.stderr92
-rw-r--r--src/test/ui/structs-enums/rec-align-u32.rs1
-rw-r--r--src/test/ui/structs-enums/rec-align-u64.rs1
-rw-r--r--src/test/ui/structs/struct-fn-in-definition.stderr9
-rw-r--r--src/test/ui/structs/struct-path-associated-type.rs4
-rw-r--r--src/test/ui/structs/struct-path-associated-type.stderr30
-rw-r--r--src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr8
-rw-r--r--src/test/ui/suggestions/inner_type.fixed40
-rw-r--r--src/test/ui/suggestions/inner_type.rs40
-rw-r--r--src/test/ui/suggestions/inner_type.stderr83
-rw-r--r--src/test/ui/suggestions/inner_type2.rs26
-rw-r--r--src/test/ui/suggestions/inner_type2.stderr29
-rw-r--r--src/test/ui/suggestions/issue-101984.stderr4
-rw-r--r--src/test/ui/suggestions/issue-85347.rs1
-rw-r--r--src/test/ui/suggestions/issue-85347.stderr11
-rw-r--r--src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr1
-rw-r--r--src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr2
-rw-r--r--src/test/ui/suggestions/missing-bound-in-manual-copy-impl-2.stderr4
-rw-r--r--src/test/ui/suggestions/missing-bound-in-manual-copy-impl.stderr4
-rw-r--r--src/test/ui/suggestions/non-existent-field-present-in-subfield-recursion-limit.rs2
-rw-r--r--src/test/ui/suggestions/return-closures.stderr2
-rw-r--r--src/test/ui/suggestions/struct-field-type-including-single-colon.stderr4
-rw-r--r--src/test/ui/symbol-names/impl1.legacy.stderr2
-rw-r--r--src/test/ui/symbol-names/impl1.rs4
-rw-r--r--src/test/ui/symbol-names/impl1.v0.stderr2
-rw-r--r--src/test/ui/thir-tree.stdout4
-rw-r--r--src/test/ui/traits/associated_type_bound/check-trait-object-bounds-2.stderr2
-rw-r--r--src/test/ui/traits/copy-impl-cannot-normalize.stderr4
-rw-r--r--src/test/ui/type-alias-impl-trait/implied_bounds.rs51
-rw-r--r--src/test/ui/type-alias-impl-trait/implied_bounds.stderr16
-rw-r--r--src/test/ui/type-alias-impl-trait/implied_bounds2.rs10
-rw-r--r--src/test/ui/type-alias-impl-trait/implied_bounds3.rs18
-rw-r--r--src/test/ui/type-alias-impl-trait/implied_bounds_closure.rs31
-rw-r--r--src/test/ui/type-alias-impl-trait/implied_bounds_closure.stderr11
-rw-r--r--src/test/ui/type-alias-impl-trait/implied_bounds_from_types.rs51
-rw-r--r--src/test/ui/type-alias-impl-trait/implied_bounds_from_types.stderr16
-rw-r--r--src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check.rs27
-rw-r--r--src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check3.rs43
-rw-r--r--src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check3.stderr58
-rw-r--r--src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.rs11
-rw-r--r--src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.stderr14
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr2
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-58662-generator-with-lifetime.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-58662-simplified.rs20
-rw-r--r--src/test/ui/type-alias-impl-trait/unbounded_opaque_type.rs14
-rw-r--r--src/test/ui/typeck/issue-69378-ice-on-invalid-type-node-after-recovery.stderr4
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr12
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr18
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr6
-rw-r--r--src/test/ui/uninhabited/privately-uninhabited-mir-call.stderr5
-rw-r--r--src/test/ui/union/union-copy.stderr4
-rw-r--r--src/test/ui/where-clauses/higher-ranked-fn-type.quiet.stderr18
-rw-r--r--src/test/ui/where-clauses/higher-ranked-fn-type.rs25
-rw-r--r--src/test/ui/where-clauses/higher-ranked-fn-type.verbose.stderr18
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_dev/src/lib.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/default_union_representation.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/doc.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/enum_variants.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/escape.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/exhaustive_items.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/exit.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/fallible_impl_from.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/must_use.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/result.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_hasher.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_to_string.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/large_const_arrays.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/utils.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/needless_match.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_doc.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_inline.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_key.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/new_without_default.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/self_named_constructors.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/trait_bounds.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/utils.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/types/borrowed_box.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/types/mod.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/types/vec_box.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_self.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap_in_result.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/use_self.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/wildcard_imports.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs19
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs13
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/usage.rs6
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-7126.rs6
-rw-r--r--src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed2
-rw-r--r--src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs2
-rw-r--r--src/tools/jsondoclint/src/item_kind.rs3
-rw-r--r--src/tools/jsondoclint/src/validator.rs10
-rw-r--r--src/tools/miri/tests/fail/invalid_bool.rs2
-rw-r--r--src/tools/miri/tests/pass/float.rs2
-rw-r--r--src/tools/miri/tests/pass/u128.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs2
-rw-r--r--src/tools/tidy/src/deps.rs33
959 files changed, 13907 insertions, 11277 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 6693182e0c5..771cef6e4d0 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -297,7 +297,7 @@ jobs:
             os: ubuntu-20.04-xl
           - name: dist-x86_64-apple
             env:
-              SCRIPT: "./x.py dist --host=x86_64-apple-darwin --target=x86_64-apple-darwin"
+              SCRIPT: "./x.py dist bootstrap --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin"
               RUST_CONFIGURE_ARGS: "--enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
               MACOSX_DEPLOYMENT_TARGET: 10.7
@@ -308,7 +308,7 @@ jobs:
             os: macos-latest
           - name: dist-apple-various
             env:
-              SCRIPT: "./x.py dist --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim"
+              SCRIPT: "./x.py dist bootstrap --include-default-paths --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim"
               RUST_CONFIGURE_ARGS: "--enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
               MACOSX_DEPLOYMENT_TARGET: 10.7
@@ -318,7 +318,7 @@ jobs:
             os: macos-latest
           - name: dist-x86_64-apple-alt
             env:
-              SCRIPT: "./x.py dist"
+              SCRIPT: "./x.py dist bootstrap --include-default-paths"
               RUST_CONFIGURE_ARGS: "--enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
               MACOSX_DEPLOYMENT_TARGET: 10.7
@@ -350,7 +350,7 @@ jobs:
             os: macos-latest
           - name: dist-aarch64-apple
             env:
-              SCRIPT: "./x.py dist --stage 2"
+              SCRIPT: "./x.py dist bootstrap --include-default-paths --stage 2"
               RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --host=aarch64-apple-darwin --target=aarch64-apple-darwin --enable-full-tools --enable-sanitizers --enable-profiler --disable-docs --set rust.jemalloc --set llvm.ninja=false"
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
               USE_XCODE_CLANG: 1
@@ -424,19 +424,19 @@ jobs:
           - name: dist-x86_64-msvc
             env:
               RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler"
-              SCRIPT: PGO_HOST=x86_64-pc-windows-msvc src/ci/pgo.sh python x.py dist
+              SCRIPT: PGO_HOST=x86_64-pc-windows-msvc src/ci/pgo.sh python x.py dist bootstrap --include-default-paths
               DIST_REQUIRE_ALL_TOOLS: 1
             os: windows-latest-xl
           - name: dist-i686-msvc
             env:
               RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-msvc --host=i686-pc-windows-msvc --target=i686-pc-windows-msvc,i586-pc-windows-msvc --enable-full-tools --enable-profiler"
-              SCRIPT: python x.py dist
+              SCRIPT: python x.py dist bootstrap --include-default-paths
               DIST_REQUIRE_ALL_TOOLS: 1
             os: windows-latest-xl
           - name: dist-aarch64-msvc
             env:
               RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=aarch64-pc-windows-msvc --enable-full-tools --enable-profiler"
-              SCRIPT: python x.py dist
+              SCRIPT: python x.py dist bootstrap --include-default-paths
               DIST_REQUIRE_ALL_TOOLS: 1
               WINDOWS_SDK_20348_HACK: 1
             os: windows-latest-xl
@@ -444,13 +444,13 @@ jobs:
             env:
               RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler --set llvm.allow-old-toolchain"
               NO_DOWNLOAD_CI_LLVM: 1
-              SCRIPT: python x.py dist
+              SCRIPT: python x.py dist bootstrap --include-default-paths
               CUSTOM_MINGW: 1
               DIST_REQUIRE_ALL_TOOLS: 1
             os: windows-latest-xl
           - name: dist-x86_64-mingw
             env:
-              SCRIPT: python x.py dist
+              SCRIPT: python x.py dist bootstrap --include-default-paths
               RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler --set llvm.allow-old-toolchain"
               NO_DOWNLOAD_CI_LLVM: 1
               CUSTOM_MINGW: 1
@@ -459,7 +459,7 @@ jobs:
           - name: dist-x86_64-msvc-alt
             env:
               RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-extended --enable-profiler"
-              SCRIPT: python x.py dist
+              SCRIPT: python x.py dist bootstrap --include-default-paths
             os: windows-latest-xl
     timeout-minutes: 600
     runs-on: "${{ matrix.os }}"
diff --git a/Cargo.lock b/Cargo.lock
index cec227d2ed6..6b2146ad3ed 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -288,7 +288,7 @@ dependencies = [
 
 [[package]]
 name = "cargo"
-version = "0.66.0"
+version = "0.67.0"
 dependencies = [
  "anyhow",
  "atty",
@@ -330,8 +330,10 @@ dependencies = [
  "pretty_env_logger",
  "rustc-workspace-hack",
  "rustfix",
+ "same-file",
  "semver",
  "serde",
+ "serde-value",
  "serde_ignored",
  "serde_json",
  "shell-escape",
@@ -417,6 +419,7 @@ dependencies = [
  "anyhow",
  "cargo-test-macro",
  "cargo-util",
+ "crates-io",
  "filetime",
  "flate2",
  "git2",
@@ -2419,6 +2422,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "ordered-float"
+version = "2.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
 name = "os_info"
 version = "3.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3263,7 +3275,6 @@ dependencies = [
  "bitflags",
  "cstr",
  "libc",
- "libloading",
  "measureme",
  "object 0.29.0",
  "rustc-demangle",
@@ -3395,6 +3406,7 @@ dependencies = [
  "rustc_errors",
  "rustc_feature",
  "rustc_hir",
+ "rustc_hir_analysis",
  "rustc_hir_pretty",
  "rustc_interface",
  "rustc_lint",
@@ -3408,7 +3420,6 @@ dependencies = [
  "rustc_session",
  "rustc_span",
  "rustc_target",
- "rustc_typeck",
  "serde_json",
  "tracing",
  "winapi",
@@ -3439,6 +3450,8 @@ version = "0.0.0"
 dependencies = [
  "annotate-snippets",
  "atty",
+ "rustc_ast",
+ "rustc_ast_pretty",
  "rustc_data_structures",
  "rustc_error_messages",
  "rustc_hir",
@@ -3514,6 +3527,35 @@ dependencies = [
 ]
 
 [[package]]
+name = "rustc_hir_analysis"
+version = "0.0.0"
+dependencies = [
+ "rustc_arena",
+ "rustc_ast",
+ "rustc_attr",
+ "rustc_data_structures",
+ "rustc_errors",
+ "rustc_feature",
+ "rustc_graphviz",
+ "rustc_hir",
+ "rustc_hir_pretty",
+ "rustc_index",
+ "rustc_infer",
+ "rustc_lint",
+ "rustc_macros",
+ "rustc_middle",
+ "rustc_serialize",
+ "rustc_session",
+ "rustc_span",
+ "rustc_target",
+ "rustc_trait_selection",
+ "rustc_ty_utils",
+ "rustc_type_ir",
+ "smallvec",
+ "tracing",
+]
+
+[[package]]
 name = "rustc_hir_pretty"
 version = "0.0.0"
 dependencies = [
@@ -3592,6 +3634,7 @@ dependencies = [
  "rustc_errors",
  "rustc_expand",
  "rustc_hir",
+ "rustc_hir_analysis",
  "rustc_incremental",
  "rustc_lint",
  "rustc_macros",
@@ -3614,7 +3657,6 @@ dependencies = [
  "rustc_trait_selection",
  "rustc_traits",
  "rustc_ty_utils",
- "rustc_typeck",
  "smallvec",
  "tracing",
  "winapi",
@@ -3924,12 +3966,12 @@ dependencies = [
  "rustc_data_structures",
  "rustc_errors",
  "rustc_hir",
+ "rustc_hir_analysis",
  "rustc_macros",
  "rustc_middle",
  "rustc_session",
  "rustc_span",
  "rustc_trait_selection",
- "rustc_typeck",
  "tracing",
 ]
 
@@ -4214,35 +4256,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "rustc_typeck"
-version = "0.0.0"
-dependencies = [
- "rustc_arena",
- "rustc_ast",
- "rustc_attr",
- "rustc_data_structures",
- "rustc_errors",
- "rustc_feature",
- "rustc_graphviz",
- "rustc_hir",
- "rustc_hir_pretty",
- "rustc_index",
- "rustc_infer",
- "rustc_lint",
- "rustc_macros",
- "rustc_middle",
- "rustc_serialize",
- "rustc_session",
- "rustc_span",
- "rustc_target",
- "rustc_trait_selection",
- "rustc_ty_utils",
- "rustc_type_ir",
- "smallvec",
- "tracing",
-]
-
-[[package]]
 name = "rustc_version"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4439,6 +4452,16 @@ dependencies = [
 ]
 
 [[package]]
+name = "serde-value"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c"
+dependencies = [
+ "ordered-float",
+ "serde",
+]
+
+[[package]]
 name = "serde_derive"
 version = "1.0.143"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 6c514c75a50..0efde1e7b21 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -3046,7 +3046,6 @@ mod size_asserts {
     static_assert_size!(Block, 48);
     static_assert_size!(Expr, 104);
     static_assert_size!(ExprKind, 72);
-    #[cfg(not(bootstrap))]
     static_assert_size!(Fn, 184);
     static_assert_size!(ForeignItem, 96);
     static_assert_size!(ForeignItemKind, 24);
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index bd7a85b07a0..eeb7e56e2b1 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -13,9 +13,7 @@
 #![feature(const_default_impls)]
 #![feature(const_trait_impl)]
 #![feature(if_let_guard)]
-#![cfg_attr(bootstrap, feature(label_break_value))]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(min_specialization)]
 #![feature(negative_impls)]
 #![feature(slice_internals)]
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 97dfb783767..fa6162c5184 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -13,7 +13,7 @@ use rustc_span::symbol::{kw, sym};
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::{self, edition::Edition, Span, DUMMY_SP};
 use std::borrow::Cow;
-use std::{fmt, mem};
+use std::fmt;
 
 #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub enum CommentKind {
@@ -335,11 +335,6 @@ impl Token {
         Token::new(Ident(ident.name, ident.is_raw_guess()), ident.span)
     }
 
-    /// Return this token by value and leave a dummy token in its place.
-    pub fn take(&mut self) -> Self {
-        mem::replace(self, Token::dummy())
-    }
-
     /// For interpolated tokens, returns a span of the fragment to which the interpolated
     /// token refers. For all other tokens this is just a regular span.
     /// It is particularly important to use this for identifiers and lifetimes
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
index 24672efc63c..85306d7184d 100644
--- a/compiler/rustc_ast_lowering/src/asm.rs
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -237,7 +237,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             // Wrap the expression in an AnonConst.
                             let parent_def_id = self.current_hir_id_owner;
                             let node_id = self.next_node_id();
-                            self.create_def(parent_def_id, node_id, DefPathData::AnonConst);
+                            self.create_def(parent_def_id.def_id, node_id, DefPathData::AnonConst);
                             let anon_const = AnonConst { id: node_id, value: P(expr) };
                             hir::InlineAsmOperand::SymFn {
                                 anon_const: self.lower_anon_const(&anon_const),
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 6c09269352c..94137391568 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -359,7 +359,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 let node_id = self.next_node_id();
 
                 // Add a definition for the in-band const def.
-                self.create_def(parent_def_id, node_id, DefPathData::AnonConst);
+                self.create_def(parent_def_id.def_id, node_id, DefPathData::AnonConst);
 
                 let anon_const = AnonConst { id: node_id, value: arg };
                 generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const)));
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index 85846b56762..6d716796343 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -24,7 +24,7 @@ pub(super) struct NodeCollector<'a, 'hir> {
     /// The parent of this node
     parent_node: hir::ItemLocalId,
 
-    owner: LocalDefId,
+    owner: OwnerId,
 
     definitions: &'a definitions::Definitions,
 }
@@ -81,9 +81,9 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
                      current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})",
                     self.source_map.span_to_diagnostic_string(span),
                     node,
-                    self.definitions.def_path(self.owner).to_string_no_crate_verbose(),
+                    self.definitions.def_path(self.owner.def_id).to_string_no_crate_verbose(),
                     self.owner,
-                    self.definitions.def_path(hir_id.owner).to_string_no_crate_verbose(),
+                    self.definitions.def_path(hir_id.owner.def_id).to_string_no_crate_verbose(),
                     hir_id.owner,
                 )
             }
@@ -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);
+        self.insert_nested(item.def_id.def_id);
     }
 
     fn visit_nested_trait_item(&mut self, item_id: TraitItemId) {
-        self.insert_nested(item_id.def_id);
+        self.insert_nested(item_id.def_id.def_id);
     }
 
     fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
-        self.insert_nested(item_id.def_id);
+        self.insert_nested(item_id.def_id.def_id);
     }
 
     fn visit_nested_foreign_item(&mut self, foreign_id: ForeignItemId) {
-        self.insert_nested(foreign_id.def_id);
+        self.insert_nested(foreign_id.def_id.def_id);
     }
 
     fn visit_nested_body(&mut self, id: BodyId) {
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index dfd04fe2974..9a46444d823 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -68,7 +68,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
             bodies: Vec::new(),
             attrs: SortedMap::default(),
             children: FxHashMap::default(),
-            current_hir_id_owner: CRATE_DEF_ID,
+            current_hir_id_owner: hir::CRATE_OWNER_ID,
             item_local_id_counter: hir::ItemLocalId::new(0),
             node_id_to_local_id: Default::default(),
             local_id_to_def_id: SortedMap::new(),
@@ -177,7 +177,8 @@ 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: self.local_def_id(i.id) }];
+        let mut node_ids =
+            smallvec![hir::ItemId { def_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);
         }
@@ -193,7 +194,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
         match tree.kind {
             UseTreeKind::Nested(ref nested_vec) => {
                 for &(ref nested, id) in nested_vec {
-                    vec.push(hir::ItemId { def_id: self.local_def_id(id) });
+                    vec.push(hir::ItemId {
+                        def_id: hir::OwnerId { def_id: self.local_def_id(id) },
+                    });
                     self.lower_item_id_use_tree(nested, id, vec);
                 }
             }
@@ -202,7 +205,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 for (_, &id) in
                     iter::zip(self.expect_full_res_from_use(base_id).skip(1), &[id1, id2])
                 {
-                    vec.push(hir::ItemId { def_id: self.local_def_id(id) });
+                    vec.push(hir::ItemId {
+                        def_id: hir::OwnerId { def_id: self.local_def_id(id) },
+                    });
                 }
             }
         }
@@ -553,7 +558,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         }
 
                         let item = hir::Item {
-                            def_id: new_id,
+                            def_id: hir::OwnerId { def_id: new_id },
                             ident: this.lower_ident(ident),
                             kind,
                             vis_span,
@@ -627,7 +632,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         }
 
                         let item = hir::Item {
-                            def_id: new_hir_id,
+                            def_id: hir::OwnerId { def_id: new_hir_id },
                             ident: this.lower_ident(ident),
                             kind,
                             vis_span,
@@ -689,7 +694,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
     fn lower_foreign_item_ref(&mut self, i: &ForeignItem) -> hir::ForeignItemRef {
         hir::ForeignItemRef {
-            id: hir::ForeignItemId { def_id: self.local_def_id(i.id) },
+            id: hir::ForeignItemId { def_id: hir::OwnerId { def_id: self.local_def_id(i.id) } },
             ident: self.lower_ident(i.ident),
             span: self.lower_span(i.span),
         }
@@ -851,7 +856,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             }
             AssocItemKind::MacCall(..) => unimplemented!(),
         };
-        let id = hir::TraitItemId { def_id: self.local_def_id(i.id) };
+        let id = hir::TraitItemId { def_id: hir::OwnerId { def_id: self.local_def_id(i.id) } };
         hir::TraitItemRef {
             id,
             ident: self.lower_ident(i.ident),
@@ -931,7 +936,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
     fn lower_impl_item_ref(&mut self, i: &AssocItem) -> hir::ImplItemRef {
         hir::ImplItemRef {
-            id: hir::ImplItemId { def_id: self.local_def_id(i.id) },
+            id: hir::ImplItemId { def_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 {
@@ -1050,9 +1055,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
         asyncness: Async,
         body: Option<&Block>,
     ) -> hir::BodyId {
-        let closure_id = match asyncness {
-            Async::Yes { closure_id, .. } => closure_id,
-            Async::No => return self.lower_fn_body_block(span, decl, body),
+        let (closure_id, body) = match (asyncness, body) {
+            (Async::Yes { closure_id, .. }, Some(body)) => (closure_id, body),
+            _ => return self.lower_fn_body_block(span, decl, body),
         };
 
         self.lower_body(|this| {
@@ -1194,16 +1199,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 parameters.push(new_parameter);
             }
 
-            let body_span = body.map_or(span, |b| b.span);
             let async_expr = this.make_async_expr(
                 CaptureBy::Value,
                 closure_id,
                 None,
-                body_span,
+                body.span,
                 hir::AsyncGeneratorKind::Fn,
                 |this| {
                     // Create a block from the user's function body:
-                    let user_body = this.lower_block_expr_opt(body_span, body);
+                    let user_body = this.lower_block_expr(body);
 
                     // Transform into `drop-temps { <user-body> }`, an expression:
                     let desugared_span =
@@ -1235,7 +1239,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
             (
                 this.arena.alloc_from_iter(parameters),
-                this.expr(body_span, async_expr, AttrVec::new()),
+                this.expr(body.span, async_expr, AttrVec::new()),
             )
         })
     }
@@ -1474,6 +1478,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 let bounded_ty =
                     self.ty_path(ty_id, param_span, hir::QPath::Resolved(None, ty_path));
                 Some(hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
+                    hir_id: self.next_id(),
                     bounded_ty: self.arena.alloc(bounded_ty),
                     bounds,
                     span,
@@ -1504,6 +1509,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 ref bounds,
                 span,
             }) => hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
+                hir_id: self.next_id(),
                 bound_generic_params: self.lower_generic_params(bound_generic_params),
                 bounded_ty: self
                     .lower_ty(bounded_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index a11721ba021..275ceed30d7 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -32,7 +32,6 @@
 
 #![feature(box_patterns)]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(never_type)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
@@ -126,7 +125,7 @@ struct LoweringContext<'a, 'hir> {
     is_in_trait_impl: bool,
     is_in_dyn_type: bool,
 
-    current_hir_id_owner: LocalDefId,
+    current_hir_id_owner: hir::OwnerId,
     item_local_id_counter: hir::ItemLocalId,
     local_id_to_def_id: SortedMap<ItemLocalId, LocalDefId>,
     trait_map: FxHashMap<ItemLocalId, Box<[TraitCandidate]>>,
@@ -572,7 +571,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let current_node_ids = std::mem::take(&mut self.node_id_to_local_id);
         let current_id_to_def_id = std::mem::take(&mut self.local_id_to_def_id);
         let current_trait_map = std::mem::take(&mut self.trait_map);
-        let current_owner = std::mem::replace(&mut self.current_hir_id_owner, def_id);
+        let current_owner =
+            std::mem::replace(&mut self.current_hir_id_owner, hir::OwnerId { def_id });
         let current_local_counter =
             std::mem::replace(&mut self.item_local_id_counter, hir::ItemLocalId::new(1));
         let current_impl_trait_defs = std::mem::take(&mut self.impl_trait_defs);
@@ -587,7 +587,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         debug_assert_eq!(_old, None);
 
         let item = f(self);
-        debug_assert_eq!(def_id, item.def_id());
+        debug_assert_eq!(def_id, item.def_id().def_id);
         // `f` should have consumed all the elements in these vectors when constructing `item`.
         debug_assert!(self.impl_trait_defs.is_empty());
         debug_assert!(self.impl_trait_bounds.is_empty());
@@ -786,7 +786,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     /// Mark a span as relative to the current owning item.
     fn lower_span(&self, span: Span) -> Span {
         if self.tcx.sess.opts.unstable_opts.incremental_relative_spans {
-            span.with_parent(Some(self.current_hir_id_owner))
+            span.with_parent(Some(self.current_hir_id_owner.def_id))
         } else {
             // Do not make spans relative when not using incremental compilation.
             span
@@ -812,7 +812,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             LifetimeRes::Fresh { param, .. } => {
                 // Late resolution delegates to us the creation of the `LocalDefId`.
                 let _def_id = self.create_def(
-                    self.current_hir_id_owner,
+                    self.current_hir_id_owner.def_id,
                     param,
                     DefPathData::LifetimeNs(kw::UnderscoreLifetime),
                 );
@@ -1062,7 +1062,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
                     let parent_def_id = self.current_hir_id_owner;
                     let impl_trait_node_id = self.next_node_id();
-                    self.create_def(parent_def_id, impl_trait_node_id, DefPathData::ImplTrait);
+                    self.create_def(
+                        parent_def_id.def_id,
+                        impl_trait_node_id,
+                        DefPathData::ImplTrait,
+                    );
 
                     self.with_dyn_type_scope(false, |this| {
                         let node_id = this.next_node_id();
@@ -1154,7 +1158,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                                 let node_id = self.next_node_id();
 
                                 // Add a definition for the in-band const def.
-                                self.create_def(parent_def_id, node_id, DefPathData::AnonConst);
+                                self.create_def(
+                                    parent_def_id.def_id,
+                                    node_id,
+                                    DefPathData::AnonConst,
+                                );
 
                                 let span = self.lower_span(ty.span);
                                 let path_expr = Expr {
@@ -1551,7 +1559,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         debug!(?lifetimes);
 
         // `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
-        hir::TyKind::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, lifetimes, in_trait)
+        hir::TyKind::OpaqueDef(
+            hir::ItemId { def_id: hir::OwnerId { def_id: opaque_ty_def_id } },
+            lifetimes,
+            in_trait,
+        )
     }
 
     /// Registers a new opaque type with the proper `NodeId`s and
@@ -1567,7 +1579,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: opaque_ty_id,
+            def_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()),
@@ -2018,7 +2030,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: opaque_ty_def_id },
+            hir::ItemId { def_id: hir::OwnerId { def_id: opaque_ty_def_id } },
             generic_args,
             in_trait,
         );
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index b1d10e07ad0..ecf74c76020 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -1415,7 +1415,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     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 traits' associated types and functions, const fns, const impls and its associated functions")
+                            .note("only allowed on bounds on functions, traits' associated types and functions, const impls and its associated functions")
                             .emit();
                     }
                 }
@@ -1523,9 +1523,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             });
         }
 
-        let tilde_const_allowed =
-            matches!(fk.header(), Some(FnHeader { constness: Const::Yes(_), .. }))
-                || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
+        let tilde_const_allowed = matches!(fk.header(), Some(FnHeader { .. }))
+            || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
 
         self.with_tilde_const(tilde_const_allowed, |this| visit::walk_fn(this, fk));
     }
diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs
index 8aa9d57f046..f58fffc9172 100644
--- a/compiler/rustc_ast_passes/src/lib.rs
+++ b/compiler/rustc_ast_passes/src/lib.rs
@@ -9,7 +9,6 @@
 #![feature(if_let_guard)]
 #![feature(iter_is_partitioned)]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![recursion_limit = "256"]
 
 #[macro_use]
diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs
index 52e65a9c774..4580ffcc6d8 100644
--- a/compiler/rustc_attr/src/lib.rs
+++ b/compiler/rustc_attr/src/lib.rs
@@ -5,7 +5,6 @@
 //! to this crate.
 
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 7fff5988785..a1b34e94dbf 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -198,7 +198,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     move_span,
                     move_spans,
                     *moved_place,
-                    Some(used_place),
                     partially_str,
                     loop_message,
                     move_msg,
@@ -369,6 +368,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         let mut visitor = ConditionVisitor { spans: &spans, name: &name, errors: vec![] };
         visitor.visit_body(&body);
 
+        let mut show_assign_sugg = false;
         let isnt_initialized = if let InitializationRequiringAction::PartialAssignment
         | InitializationRequiringAction::Assignment = desired_action
         {
@@ -396,6 +396,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             .count()
             == 0
         {
+            show_assign_sugg = true;
             "isn't initialized"
         } else {
             "is possibly-uninitialized"
@@ -446,10 +447,78 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 }
             }
         }
+
         err.span_label(decl_span, "binding declared here but left uninitialized");
+        if show_assign_sugg {
+            struct LetVisitor {
+                decl_span: Span,
+                sugg_span: Option<Span>,
+            }
+
+            impl<'v> Visitor<'v> for LetVisitor {
+                fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {
+                    if self.sugg_span.is_some() {
+                        return;
+                    }
+                    if let hir::StmtKind::Local(hir::Local {
+                            span, ty, init: None, ..
+                        }) = &ex.kind && span.contains(self.decl_span) {
+                            self.sugg_span = ty.map_or(Some(self.decl_span), |ty| Some(ty.span));
+                    }
+                    hir::intravisit::walk_stmt(self, ex);
+                }
+            }
+
+            let mut visitor = LetVisitor { decl_span, sugg_span: None };
+            visitor.visit_body(&body);
+            if let Some(span) = visitor.sugg_span {
+                self.suggest_assign_value(&mut err, moved_place, span);
+            }
+        }
         err
     }
 
+    fn suggest_assign_value(
+        &self,
+        err: &mut Diagnostic,
+        moved_place: PlaceRef<'tcx>,
+        sugg_span: Span,
+    ) {
+        let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
+        debug!("ty: {:?}, kind: {:?}", ty, ty.kind());
+
+        let tcx = self.infcx.tcx;
+        let implements_default = |ty, param_env| {
+            let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else {
+                return false;
+            };
+            tcx.infer_ctxt().enter(|infcx| {
+                infcx
+                    .type_implements_trait(default_trait, ty, ty::List::empty(), param_env)
+                    .may_apply()
+            })
+        };
+
+        let assign_value = match ty.kind() {
+            ty::Bool => "false",
+            ty::Float(_) => "0.0",
+            ty::Int(_) | ty::Uint(_) => "0",
+            ty::Never | ty::Error(_) => "",
+            ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Vec) => "vec![]",
+            ty::Adt(_, _) if implements_default(ty, self.param_env) => "Default::default()",
+            _ => "todo!()",
+        };
+
+        if !assign_value.is_empty() {
+            err.span_suggestion_verbose(
+                sugg_span.shrink_to_hi(),
+                format!("consider assigning a value"),
+                format!(" = {}", assign_value),
+                Applicability::MaybeIncorrect,
+            );
+        }
+    }
+
     fn suggest_borrow_fn_like(
         &self,
         err: &mut Diagnostic,
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index baabeea5823..7ccb679d88b 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -972,7 +972,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         move_span: Span,
         move_spans: UseSpans<'tcx>,
         moved_place: Place<'tcx>,
-        used_place: Option<PlaceRef<'tcx>>,
         partially_str: &str,
         loop_message: &str,
         move_msg: &str,
@@ -1060,9 +1059,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                                 place_name, partially_str, loop_message
                             ),
                         );
-                        // If we have a `&mut` ref, we need to reborrow.
-                        if let Some(ty::Ref(_, _, hir::Mutability::Mut)) = used_place
-                            .map(|used_place| used_place.ty(self.body, self.infcx.tcx).ty.kind())
+                        // If the moved place was a `&mut` ref, then we can
+                        // suggest to reborrow it where it was moved, so it
+                        // will still be valid by the time we get to the usage.
+                        if let ty::Ref(_, _, hir::Mutability::Mut) =
+                            moved_place.ty(self.body, self.infcx.tcx).ty.kind()
                         {
                             // If we are in a loop this will be suggested later.
                             if !is_loop_move {
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index 8d4c38d3a8e..5a47f45677e 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -401,7 +401,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         };
         if let Some(use_spans) = use_spans {
             self.explain_captures(
-                &mut err, span, span, use_spans, move_place, None, "", "", "", false, true,
+                &mut err, span, span, use_spans, move_place, "", "", "", false, true,
             );
         }
         err
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 202729b4744..8ad40c0aa0a 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -932,7 +932,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 let opt_suggestions = self
                     .infcx
                     .tcx
-                    .typeck(path_segment.hir_id.owner)
+                    .typeck(path_segment.hir_id.owner.def_id)
                     .type_dependent_def_id(*hir_id)
                     .and_then(|def_id| self.infcx.tcx.impl_of_method(def_id))
                     .map(|def_id| self.infcx.tcx.associated_items(def_id))
@@ -1032,7 +1032,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         if look_at_return && hir.get_return_block(closure_id).is_some() {
             // ...otherwise we are probably in the tail expression of the function, point at the
             // return type.
-            match hir.get_by_def_id(hir.get_parent_item(fn_call_id)) {
+            match hir.get_by_def_id(hir.get_parent_item(fn_call_id).def_id) {
                 hir::Node::Item(hir::Item { ident, kind: hir::ItemKind::Fn(sig, ..), .. })
                 | hir::Node::TraitItem(hir::TraitItem {
                     ident,
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 34be2874fcb..43d67bfa729 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -281,7 +281,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         let tcx = self.infcx.tcx;
         match tcx.hir().get_if_local(def_id) {
             Some(Node::ImplItem(impl_item)) => {
-                match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id())) {
+                match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id()).def_id)
+                {
                     Some(Node::Item(Item {
                         kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
                         ..
@@ -291,7 +292,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             }
             Some(Node::TraitItem(trait_item)) => {
                 let trait_did = tcx.hir().get_parent_item(trait_item.hir_id());
-                match tcx.hir().find_by_def_id(trait_did) {
+                match tcx.hir().find_by_def_id(trait_did.def_id) {
                     Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {
                         // The method being called is defined in the `trait`, but the `'static`
                         // obligation comes from the `impl`. Find that `impl` so that we can point
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 6c1eaa809c9..419e6c81791 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -707,7 +707,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                         hir::AsyncGeneratorKind::Block => " of async block",
                         hir::AsyncGeneratorKind::Closure => " of async closure",
                         hir::AsyncGeneratorKind::Fn => {
-                            let parent_item = hir.get_by_def_id(hir.get_parent_item(mir_hir_id));
+                            let parent_item =
+                                hir.get_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
                             let output = &parent_item
                                 .fn_decl()
                                 .expect("generator lowered from async fn should be in fn")
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index cb16bec57ee..a83840e1099 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -3,7 +3,6 @@
 #![allow(rustc::potential_query_instability)]
 #![feature(box_patterns)]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(min_specialization)]
 #![feature(never_type)]
 #![feature(rustc_attrs)]
@@ -134,7 +133,7 @@ fn mir_borrowck<'tcx>(
 
     let opt_closure_req = tcx
         .infer_ctxt()
-        .with_opaque_type_inference(DefiningAnchor::Bind(hir_owner))
+        .with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id))
         .enter(|infcx| {
             let input_body: &Body<'_> = &input_body.borrow();
             let promoted: &IndexVec<_, _> = &promoted.borrow();
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index f1b1c33a105..e0140e281ee 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -362,6 +362,11 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
                     self.region_bound_pairs
                         .insert(ty::OutlivesPredicate(GenericKind::Projection(projection_b), r_a));
                 }
+
+                OutlivesBound::RegionSubOpaque(r_a, def_id, substs) => {
+                    self.region_bound_pairs
+                        .insert(ty::OutlivesPredicate(GenericKind::Opaque(def_id, substs), r_a));
+                }
             }
         }
     }
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 21004871075..b15e2d084ef 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -1,271 +1,42 @@
-use ArgumentType::*;
-use Position::*;
-
-use rustc_ast as ast;
 use rustc_ast::ptr::P;
+use rustc_ast::token;
 use rustc_ast::tokenstream::TokenStream;
-use rustc_ast::visit::{self, Visitor};
-use rustc_ast::{token, BlockCheckMode, UnsafeSource};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_ast::Expr;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{pluralize, Applicability, MultiSpan, PResult};
 use rustc_expand::base::{self, *};
 use rustc_parse_format as parse;
-use rustc_span::symbol::{sym, Ident, Symbol};
+use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::{BytePos, InnerSpan, Span};
-use smallvec::SmallVec;
 
 use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
 use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, LintId};
-use rustc_parse_format::Count;
-use std::borrow::Cow;
-use std::collections::hash_map::Entry;
-
-#[derive(PartialEq)]
-enum ArgumentType {
-    Placeholder(&'static str),
-    Count,
-}
-
-enum Position {
-    Exact(usize),
-    Capture(usize),
-    Named(Symbol, InnerSpan),
-}
-
-/// Indicates how positional named argument (i.e. an named argument which is used by position
-/// instead of by name) is used in format string
-/// * `Arg` is the actual argument to print
-/// * `Width` is width format argument
-/// * `Precision` is precion format argument
-/// Example: `{Arg:Width$.Precision$}
-#[derive(Debug, Eq, PartialEq)]
-enum PositionalNamedArgType {
-    Arg,
-    Width,
-    Precision,
-}
-
-/// Contains information necessary to create a lint for a positional named argument
-#[derive(Debug)]
-struct PositionalNamedArg {
-    ty: PositionalNamedArgType,
-    /// The piece of the using this argument (multiple pieces can use the same argument)
-    cur_piece: usize,
-    /// The InnerSpan for in the string to be replaced with the named argument
-    /// This will be None when the position is implicit
-    inner_span_to_replace: Option<rustc_parse_format::InnerSpan>,
-    /// The name to use instead of the position
-    replacement: Symbol,
-    /// The span for the positional named argument (so the lint can point a message to it)
-    positional_named_arg_span: Span,
-    has_formatting: bool,
-}
-
-impl PositionalNamedArg {
-    /// Determines:
-    /// 1) span to be replaced with the name of the named argument and
-    /// 2) span to be underlined for error messages
-    fn get_positional_arg_spans(&self, cx: &Context<'_, '_>) -> (Option<Span>, Option<Span>) {
-        if let Some(inner_span) = &self.inner_span_to_replace {
-            let span =
-                cx.fmtsp.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end });
-            (Some(span), Some(span))
-        } else if self.ty == PositionalNamedArgType::Arg {
-            // In the case of a named argument whose position is implicit, if the argument *has*
-            // formatting, there will not be a span to replace. Instead, we insert the name after
-            // the `{`, which will be the first character of arg_span. If the argument does *not*
-            // have formatting, there may or may not be a span to replace. This is because
-            // whitespace is allowed in arguments without formatting (such as `format!("{  }", 1);`)
-            // but is not allowed in arguments with formatting (an error will be generated in cases
-            // like `format!("{ :1.1}", 1.0f32);`.
-            // For the message span, if there is formatting, we want to use the opening `{` and the
-            // next character, which will the `:` indicating the start of formatting. If there is
-            // not any formatting, we want to underline the entire span.
-            cx.arg_spans.get(self.cur_piece).map_or((None, None), |arg_span| {
-                if self.has_formatting {
-                    (
-                        Some(arg_span.with_lo(arg_span.lo() + BytePos(1)).shrink_to_lo()),
-                        Some(arg_span.with_hi(arg_span.lo() + BytePos(2))),
-                    )
-                } else {
-                    let replace_start = arg_span.lo() + BytePos(1);
-                    let replace_end = arg_span.hi() - BytePos(1);
-                    let to_replace = arg_span.with_lo(replace_start).with_hi(replace_end);
-                    (Some(to_replace), Some(*arg_span))
-                }
-            })
-        } else {
-            (None, None)
-        }
-    }
-}
-
-/// Encapsulates all the named arguments that have been used positionally
-#[derive(Debug)]
-struct PositionalNamedArgsLint {
-    positional_named_args: Vec<PositionalNamedArg>,
-}
-
-impl PositionalNamedArgsLint {
-    /// For a given positional argument, check if the index is for a named argument.
-    ///
-    /// Since positional arguments are required to come before named arguments, if the positional
-    /// index is greater than or equal to the start of named arguments, we know it's a named
-    /// argument used positionally.
-    ///
-    /// Example:
-    /// println!("{} {} {2}", 0, a=1, b=2);
-    ///
-    /// In this case, the first piece (`{}`) would be ArgumentImplicitlyIs with an index of 0. The
-    /// total number of arguments is 3 and the number of named arguments is 2, so the start of named
-    /// arguments is index 1. Therefore, the index of 0 is okay.
-    ///
-    /// The second piece (`{}`) would be ArgumentImplicitlyIs with an index of 1, which is the start
-    /// of named arguments, and so we should add a lint to use the named argument `a`.
-    ///
-    /// The third piece (`{2}`) would be ArgumentIs with an index of 2, which is greater than the
-    /// start of named arguments, and so we should add a lint to use the named argument `b`.
-    ///
-    /// This same check also works for width and precision formatting when either or both are
-    /// CountIsParam, which contains an index into the arguments.
-    fn maybe_add_positional_named_arg(
-        &mut self,
-        arg: Option<&FormatArg>,
-        ty: PositionalNamedArgType,
-        cur_piece: usize,
-        inner_span_to_replace: Option<rustc_parse_format::InnerSpan>,
-        has_formatting: bool,
-    ) {
-        if let Some(arg) = arg {
-            if let Some(name) = arg.name {
-                self.push(name, ty, cur_piece, inner_span_to_replace, has_formatting)
-            }
-        }
-    }
 
-    /// Construct a PositionalNamedArg struct and push it into the vec of positional
-    /// named arguments.
-    fn push(
-        &mut self,
-        arg_name: Ident,
-        ty: PositionalNamedArgType,
-        cur_piece: usize,
-        inner_span_to_replace: Option<rustc_parse_format::InnerSpan>,
-        has_formatting: bool,
-    ) {
-        // In FormatSpec, `precision_span` starts at the leading `.`, which we want to keep in
-        // the lint suggestion, so increment `start` by 1 when `PositionalArgumentType` is
-        // `Precision`.
-        let inner_span_to_replace = if ty == PositionalNamedArgType::Precision {
-            inner_span_to_replace
-                .map(|is| rustc_parse_format::InnerSpan { start: is.start + 1, end: is.end })
-        } else {
-            inner_span_to_replace
-        };
-        self.positional_named_args.push(PositionalNamedArg {
-            ty,
-            cur_piece,
-            inner_span_to_replace,
-            replacement: arg_name.name,
-            positional_named_arg_span: arg_name.span,
-            has_formatting,
-        });
-    }
-}
-
-struct Context<'a, 'b> {
-    ecx: &'a mut ExtCtxt<'b>,
-    /// The macro's call site. References to unstable formatting internals must
-    /// use this span to pass the stability checker.
-    macsp: Span,
-    /// The span of the format string literal.
-    fmtsp: Span,
-
-    /// List of parsed argument expressions.
-    /// Named expressions are resolved early, and are appended to the end of
-    /// argument expressions.
-    ///
-    /// Example showing the various data structures in motion:
-    ///
-    /// * Original: `"{foo:o} {:o} {foo:x} {0:x} {1:o} {:x} {1:x} {0:o}"`
-    /// * Implicit argument resolution: `"{foo:o} {0:o} {foo:x} {0:x} {1:o} {1:x} {1:x} {0:o}"`
-    /// * Name resolution: `"{2:o} {0:o} {2:x} {0:x} {1:o} {1:x} {1:x} {0:o}"`
-    /// * `arg_types` (in JSON): `[[0, 1, 0], [0, 1, 1], [0, 1]]`
-    /// * `arg_unique_types` (in simplified JSON): `[["o", "x"], ["o", "x"], ["o", "x"]]`
-    /// * `names` (in JSON): `{"foo": 2}`
-    args: Vec<FormatArg>,
-    /// The number of arguments that were added by implicit capturing.
-    num_captured_args: usize,
-    /// Placeholder slot numbers indexed by argument.
-    arg_types: Vec<Vec<usize>>,
-    /// Unique format specs seen for each argument.
-    arg_unique_types: Vec<Vec<ArgumentType>>,
-    /// Map from named arguments to their resolved indices.
-    names: FxHashMap<Symbol, usize>,
-
-    /// The latest consecutive literal strings, or empty if there weren't any.
-    literal: String,
+mod ast;
+use ast::*;
 
-    /// Collection of the compiled `rt::Argument` structures
-    pieces: Vec<P<ast::Expr>>,
-    /// Collection of string literals
-    str_pieces: Vec<P<ast::Expr>>,
-    /// Stays `true` if all formatting parameters are default (as in "{}{}").
-    all_pieces_simple: bool,
+mod expand;
+use expand::expand_parsed_format_args;
 
-    /// Mapping between positional argument references and indices into the
-    /// final generated static argument array. We record the starting indices
-    /// corresponding to each positional argument, and number of references
-    /// consumed so far for each argument, to facilitate correct `Position`
-    /// mapping in `build_piece`. In effect this can be seen as a "flattened"
-    /// version of `arg_unique_types`.
-    ///
-    /// Again with the example described above in docstring for `args`:
-    ///
-    /// * `arg_index_map` (in JSON): `[[0, 1, 0], [2, 3, 3], [4, 5]]`
-    arg_index_map: Vec<Vec<usize>>,
+// The format_args!() macro is expanded in three steps:
+//  1. First, `parse_args` will parse the `(literal, arg, arg, name=arg, name=arg)` syntax,
+//     but doesn't parse the template (the literal) itself.
+//  2. Second, `make_format_args` will parse the template, the format options, resolve argument references,
+//     produce diagnostics, and turn the whole thing into a `FormatArgs` structure.
+//  3. Finally, `expand_parsed_format_args` will turn that `FormatArgs` structure
+//     into the expression that the macro expands to.
 
-    /// Starting offset of count argument slots.
-    count_args_index_offset: usize,
+// See format/ast.rs for the FormatArgs structure and glossary.
 
-    /// Count argument slots and tracking data structures.
-    /// Count arguments are separately tracked for de-duplication in case
-    /// multiple references are made to one argument. For example, in this
-    /// format string:
-    ///
-    /// * Original: `"{:.*} {:.foo$} {1:.*} {:.0$}"`
-    /// * Implicit argument resolution: `"{1:.0$} {2:.foo$} {1:.3$} {4:.0$}"`
-    /// * Name resolution: `"{1:.0$} {2:.5$} {1:.3$} {4:.0$}"`
-    /// * `count_positions` (in JSON): `{0: 0, 5: 1, 3: 2}`
-    /// * `count_args`: `vec![0, 5, 3]`
-    count_args: Vec<usize>,
-    /// Relative slot numbers for count arguments.
-    count_positions: FxHashMap<usize, usize>,
-    /// Number of count slots assigned.
-    count_positions_count: usize,
-
-    /// Current position of the implicit positional arg pointer, as if it
-    /// still existed in this phase of processing.
-    /// Used only for `all_pieces_simple` tracking in `build_piece`.
-    curarg: usize,
-    /// Current piece being evaluated, used for error reporting.
-    curpiece: usize,
-    /// Keep track of invalid references to positional arguments.
-    invalid_refs: Vec<(usize, usize)>,
-    /// Spans of all the formatting arguments, in order.
-    arg_spans: Vec<Span>,
-    /// All the formatting arguments that have formatting flags set, in order for diagnostics.
-    arg_with_formatting: Vec<parse::FormatSpec<'a>>,
-
-    /// Whether this format string came from a string literal, as opposed to a macro.
-    is_literal: bool,
-    unused_names_lint: PositionalNamedArgsLint,
-}
-
-pub struct FormatArg {
-    expr: P<ast::Expr>,
-    name: Option<Ident>,
+// Only used in parse_args and report_invalid_references,
+// to indicate how a referred argument was used.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+enum PositionUsedAs {
+    Placeholder(Option<Span>),
+    Precision,
+    Width,
 }
+use PositionUsedAs::*;
 
 /// Parses the arguments from the given list of tokens, returning the diagnostic
 /// if there's a parse error so we can continue parsing other format!
@@ -274,15 +45,14 @@ pub struct FormatArg {
 /// If parsing succeeds, the return value is:
 ///
 /// ```text
-/// Some((fmtstr, parsed arguments, index map for named arguments))
+/// Ok((fmtstr, parsed arguments))
 /// ```
 fn parse_args<'a>(
     ecx: &mut ExtCtxt<'a>,
     sp: Span,
     tts: TokenStream,
-) -> PResult<'a, (P<ast::Expr>, Vec<FormatArg>, FxHashMap<Symbol, usize>)> {
-    let mut args = Vec::<FormatArg>::new();
-    let mut names = FxHashMap::<Symbol, usize>::default();
+) -> PResult<'a, (P<Expr>, FormatArguments)> {
+    let mut args = FormatArguments::new();
 
     let mut p = ecx.new_parser_from_tts(tts);
 
@@ -311,7 +81,6 @@ fn parse_args<'a>(
     };
 
     let mut first = true;
-    let mut named = false;
 
     while p.token != token::Eof {
         if !p.eat(&token::Comma) {
@@ -343,879 +112,54 @@ fn parse_args<'a>(
         } // accept trailing commas
         match p.token.ident() {
             Some((ident, _)) if p.look_ahead(1, |t| *t == token::Eq) => {
-                named = true;
                 p.bump();
                 p.expect(&token::Eq)?;
-                let e = p.parse_expr()?;
-                if let Some(&prev) = names.get(&ident.name) {
-                    ecx.struct_span_err(e.span, &format!("duplicate argument named `{}`", ident))
-                        .span_label(args[prev].expr.span, "previously here")
-                        .span_label(e.span, "duplicate argument")
-                        .emit();
+                let expr = p.parse_expr()?;
+                if let Some((_, prev)) = args.by_name(ident.name) {
+                    ecx.struct_span_err(
+                        ident.span,
+                        &format!("duplicate argument named `{}`", ident),
+                    )
+                    .span_label(prev.kind.ident().unwrap().span, "previously here")
+                    .span_label(ident.span, "duplicate argument")
+                    .emit();
                     continue;
                 }
-
-                // Resolve names into slots early.
-                // Since all the positional args are already seen at this point
-                // if the input is valid, we can simply append to the positional
-                // args. And remember the names.
-                let slot = args.len();
-                names.insert(ident.name, slot);
-                args.push(FormatArg { expr: e, name: Some(ident) });
+                args.add(FormatArgument { kind: FormatArgumentKind::Named(ident), expr });
             }
             _ => {
-                let e = p.parse_expr()?;
-                if named {
+                let expr = p.parse_expr()?;
+                if !args.named_args().is_empty() {
                     let mut err = ecx.struct_span_err(
-                        e.span,
+                        expr.span,
                         "positional arguments cannot follow named arguments",
                     );
-                    err.span_label(e.span, "positional arguments must be before named arguments");
-                    for &pos in names.values() {
-                        err.span_label(args[pos].expr.span, "named argument");
+                    err.span_label(
+                        expr.span,
+                        "positional arguments must be before named arguments",
+                    );
+                    for arg in args.named_args() {
+                        if let Some(name) = arg.kind.ident() {
+                            err.span_label(name.span.to(arg.expr.span), "named argument");
+                        }
                     }
                     err.emit();
                 }
-                args.push(FormatArg { expr: e, name: None });
+                args.add(FormatArgument { kind: FormatArgumentKind::Normal, expr });
             }
         }
     }
-    Ok((fmtstr, args, names))
+    Ok((fmtstr, args))
 }
 
-impl<'a, 'b> Context<'a, 'b> {
-    /// The number of arguments that were explicitly given.
-    fn num_args(&self) -> usize {
-        self.args.len() - self.num_captured_args
-    }
-
-    fn resolve_name_inplace(&mut self, p: &mut parse::Piece<'_>) {
-        // NOTE: the `unwrap_or` branch is needed in case of invalid format
-        // arguments, e.g., `format_args!("{foo}")`.
-        let lookup = |s: &str| self.names.get(&Symbol::intern(s)).copied().unwrap_or(0);
-
-        match *p {
-            parse::String(_) => {}
-            parse::NextArgument(ref mut arg) => {
-                if let parse::ArgumentNamed(s) = arg.position {
-                    arg.position = parse::ArgumentIs(lookup(s));
-                }
-                if let parse::CountIsName(s, _) = arg.format.width {
-                    arg.format.width = parse::CountIsParam(lookup(s));
-                }
-                if let parse::CountIsName(s, _) = arg.format.precision {
-                    arg.format.precision = parse::CountIsParam(lookup(s));
-                }
-            }
-        }
-    }
-
-    /// Verifies one piece of a parse string, and remembers it if valid.
-    /// All errors are not emitted as fatal so we can continue giving errors
-    /// about this and possibly other format strings.
-    fn verify_piece(&mut self, p: &parse::Piece<'a>) {
-        match *p {
-            parse::String(..) => {}
-            parse::NextArgument(ref arg) => {
-                // width/precision first, if they have implicit positional
-                // parameters it makes more sense to consume them first.
-                self.verify_count(
-                    arg.format.width,
-                    &arg.format.width_span,
-                    PositionalNamedArgType::Width,
-                );
-                self.verify_count(
-                    arg.format.precision,
-                    &arg.format.precision_span,
-                    PositionalNamedArgType::Precision,
-                );
-
-                let has_precision = arg.format.precision != Count::CountImplied;
-                let has_width = arg.format.width != Count::CountImplied;
-
-                if has_precision || has_width {
-                    // push before named params are resolved to aid diagnostics
-                    self.arg_with_formatting.push(arg.format);
-                }
-
-                // argument second, if it's an implicit positional parameter
-                // it's written second, so it should come after width/precision.
-                let pos = match arg.position {
-                    parse::ArgumentIs(i) => {
-                        self.unused_names_lint.maybe_add_positional_named_arg(
-                            self.args.get(i),
-                            PositionalNamedArgType::Arg,
-                            self.curpiece,
-                            Some(arg.position_span),
-                            has_precision || has_width,
-                        );
-
-                        Exact(i)
-                    }
-                    parse::ArgumentImplicitlyIs(i) => {
-                        self.unused_names_lint.maybe_add_positional_named_arg(
-                            self.args.get(i),
-                            PositionalNamedArgType::Arg,
-                            self.curpiece,
-                            None,
-                            has_precision || has_width,
-                        );
-                        Exact(i)
-                    }
-                    parse::ArgumentNamed(s) => {
-                        let symbol = Symbol::intern(s);
-                        let span = arg.position_span;
-                        Named(symbol, InnerSpan::new(span.start, span.end))
-                    }
-                };
-
-                let ty = Placeholder(match arg.format.ty {
-                    "" => "Display",
-                    "?" => "Debug",
-                    "e" => "LowerExp",
-                    "E" => "UpperExp",
-                    "o" => "Octal",
-                    "p" => "Pointer",
-                    "b" => "Binary",
-                    "x" => "LowerHex",
-                    "X" => "UpperHex",
-                    _ => {
-                        let fmtsp = self.fmtsp;
-                        let sp = arg
-                            .format
-                            .ty_span
-                            .map(|sp| fmtsp.from_inner(InnerSpan::new(sp.start, sp.end)));
-                        let mut err = self.ecx.struct_span_err(
-                            sp.unwrap_or(fmtsp),
-                            &format!("unknown format trait `{}`", arg.format.ty),
-                        );
-                        err.note(
-                            "the only appropriate formatting traits are:\n\
-                                - ``, which uses the `Display` trait\n\
-                                - `?`, which uses the `Debug` trait\n\
-                                - `e`, which uses the `LowerExp` trait\n\
-                                - `E`, which uses the `UpperExp` trait\n\
-                                - `o`, which uses the `Octal` trait\n\
-                                - `p`, which uses the `Pointer` trait\n\
-                                - `b`, which uses the `Binary` trait\n\
-                                - `x`, which uses the `LowerHex` trait\n\
-                                - `X`, which uses the `UpperHex` trait",
-                        );
-                        if let Some(sp) = sp {
-                            for (fmt, name) in &[
-                                ("", "Display"),
-                                ("?", "Debug"),
-                                ("e", "LowerExp"),
-                                ("E", "UpperExp"),
-                                ("o", "Octal"),
-                                ("p", "Pointer"),
-                                ("b", "Binary"),
-                                ("x", "LowerHex"),
-                                ("X", "UpperHex"),
-                            ] {
-                                // FIXME: rustfix (`run-rustfix`) fails to apply suggestions.
-                                // > "Cannot replace slice of data that was already replaced"
-                                err.tool_only_span_suggestion(
-                                    sp,
-                                    &format!("use the `{}` trait", name),
-                                    *fmt,
-                                    Applicability::MaybeIncorrect,
-                                );
-                            }
-                        }
-                        err.emit();
-                        "<invalid>"
-                    }
-                });
-                self.verify_arg_type(pos, ty);
-                self.curpiece += 1;
-            }
-        }
-    }
-
-    fn verify_count(
-        &mut self,
-        c: parse::Count<'_>,
-        inner_span: &Option<rustc_parse_format::InnerSpan>,
-        named_arg_type: PositionalNamedArgType,
-    ) {
-        match c {
-            parse::CountImplied | parse::CountIs(..) => {}
-            parse::CountIsParam(i) | parse::CountIsStar(i) => {
-                self.unused_names_lint.maybe_add_positional_named_arg(
-                    self.args.get(i),
-                    named_arg_type,
-                    self.curpiece,
-                    *inner_span,
-                    true,
-                );
-                self.verify_arg_type(Exact(i), Count);
-            }
-            parse::CountIsName(s, span) => {
-                self.verify_arg_type(
-                    Named(Symbol::intern(s), InnerSpan::new(span.start, span.end)),
-                    Count,
-                );
-            }
-        }
-    }
-
-    fn describe_num_args(&self) -> Cow<'_, str> {
-        match self.num_args() {
-            0 => "no arguments were given".into(),
-            1 => "there is 1 argument".into(),
-            x => format!("there are {} arguments", x).into(),
-        }
-    }
-
-    /// Handle invalid references to positional arguments. Output different
-    /// errors for the case where all arguments are positional and for when
-    /// there are named arguments or numbered positional arguments in the
-    /// format string.
-    fn report_invalid_references(&self, numbered_position_args: bool) {
-        let mut e;
-        let sp = if !self.arg_spans.is_empty() {
-            // Point at the formatting arguments.
-            MultiSpan::from_spans(self.arg_spans.clone())
-        } else {
-            MultiSpan::from_span(self.fmtsp)
-        };
-        let refs =
-            self.invalid_refs.iter().map(|(r, pos)| (r.to_string(), self.arg_spans.get(*pos)));
-
-        let mut zero_based_note = false;
-
-        let count = self.pieces.len()
-            + self
-                .arg_with_formatting
-                .iter()
-                .filter(|fmt| matches!(fmt.precision, parse::CountIsStar(_)))
-                .count();
-        if self.names.is_empty() && !numbered_position_args && count != self.num_args() {
-            e = self.ecx.struct_span_err(
-                sp,
-                &format!(
-                    "{} positional argument{} in format string, but {}",
-                    count,
-                    pluralize!(count),
-                    self.describe_num_args(),
-                ),
-            );
-            for arg in &self.args {
-                // Point at the arguments that will be formatted.
-                e.span_label(arg.expr.span, "");
-            }
-        } else {
-            let (mut refs, spans): (Vec<_>, Vec<_>) = refs.unzip();
-            // Avoid `invalid reference to positional arguments 7 and 7 (there is 1 argument)`
-            // for `println!("{7:7$}", 1);`
-            refs.sort();
-            refs.dedup();
-            let spans: Vec<_> = spans.into_iter().filter_map(|sp| sp.copied()).collect();
-            let sp = if self.arg_spans.is_empty() || spans.is_empty() {
-                MultiSpan::from_span(self.fmtsp)
-            } else {
-                MultiSpan::from_spans(spans)
-            };
-            let arg_list = if refs.len() == 1 {
-                format!("argument {}", refs[0])
-            } else {
-                let reg = refs.pop().unwrap();
-                format!("arguments {head} and {tail}", head = refs.join(", "), tail = reg)
-            };
-
-            e = self.ecx.struct_span_err(
-                sp,
-                &format!(
-                    "invalid reference to positional {} ({})",
-                    arg_list,
-                    self.describe_num_args()
-                ),
-            );
-            zero_based_note = true;
-        };
-
-        for fmt in &self.arg_with_formatting {
-            if let Some(span) = fmt.precision_span {
-                let span = self.fmtsp.from_inner(InnerSpan::new(span.start, span.end));
-                match fmt.precision {
-                    parse::CountIsParam(pos) if pos >= self.num_args() => {
-                        e.span_label(
-                            span,
-                            &format!(
-                                "this precision flag expects an `usize` argument at position {}, \
-                             but {}",
-                                pos,
-                                self.describe_num_args(),
-                            ),
-                        );
-                        zero_based_note = true;
-                    }
-                    parse::CountIsStar(pos) => {
-                        let count = self.pieces.len()
-                            + self
-                                .arg_with_formatting
-                                .iter()
-                                .filter(|fmt| matches!(fmt.precision, parse::CountIsStar(_)))
-                                .count();
-                        e.span_label(
-                            span,
-                            &format!(
-                            "this precision flag adds an extra required argument at position {}, \
-                             which is why there {} expected",
-                            pos,
-                            if count == 1 {
-                                "is 1 argument".to_string()
-                            } else {
-                                format!("are {} arguments", count)
-                            },
-                        ),
-                        );
-                        if let Some(arg) = self.args.get(pos) {
-                            e.span_label(
-                                arg.expr.span,
-                                "this parameter corresponds to the precision flag",
-                            );
-                        }
-                        zero_based_note = true;
-                    }
-                    _ => {}
-                }
-            }
-            if let Some(span) = fmt.width_span {
-                let span = self.fmtsp.from_inner(InnerSpan::new(span.start, span.end));
-                match fmt.width {
-                    parse::CountIsParam(pos) if pos >= self.num_args() => {
-                        e.span_label(
-                            span,
-                            &format!(
-                                "this width flag expects an `usize` argument at position {}, \
-                             but {}",
-                                pos,
-                                self.describe_num_args(),
-                            ),
-                        );
-                        zero_based_note = true;
-                    }
-                    _ => {}
-                }
-            }
-        }
-        if zero_based_note {
-            e.note("positional arguments are zero-based");
-        }
-        if !self.arg_with_formatting.is_empty() {
-            e.note(
-                "for information about formatting flags, visit \
-                    https://doc.rust-lang.org/std/fmt/index.html",
-            );
-        }
-
-        e.emit();
-    }
-
-    /// Actually verifies and tracks a given format placeholder
-    /// (a.k.a. argument).
-    fn verify_arg_type(&mut self, arg: Position, ty: ArgumentType) {
-        if let Exact(arg) = arg {
-            if arg >= self.num_args() {
-                self.invalid_refs.push((arg, self.curpiece));
-                return;
-            }
-        }
-
-        match arg {
-            Exact(arg) | Capture(arg) => {
-                match ty {
-                    Placeholder(_) => {
-                        // record every (position, type) combination only once
-                        let seen_ty = &mut self.arg_unique_types[arg];
-                        let i = seen_ty.iter().position(|x| *x == ty).unwrap_or_else(|| {
-                            let i = seen_ty.len();
-                            seen_ty.push(ty);
-                            i
-                        });
-                        self.arg_types[arg].push(i);
-                    }
-                    Count => {
-                        if let Entry::Vacant(e) = self.count_positions.entry(arg) {
-                            let i = self.count_positions_count;
-                            e.insert(i);
-                            self.count_args.push(arg);
-                            self.count_positions_count += 1;
-                        }
-                    }
-                }
-            }
-
-            Named(name, span) => {
-                match self.names.get(&name) {
-                    Some(&idx) => {
-                        // Treat as positional arg.
-                        self.verify_arg_type(Capture(idx), ty)
-                    }
-                    None => {
-                        // For the moment capturing variables from format strings expanded from macros is
-                        // disabled (see RFC #2795)
-                        if self.is_literal {
-                            // Treat this name as a variable to capture from the surrounding scope
-                            let idx = self.args.len();
-                            self.arg_types.push(Vec::new());
-                            self.arg_unique_types.push(Vec::new());
-                            let span = if self.is_literal {
-                                self.fmtsp.from_inner(span)
-                            } else {
-                                self.fmtsp
-                            };
-                            self.num_captured_args += 1;
-                            self.args.push(FormatArg {
-                                expr: self.ecx.expr_ident(span, Ident::new(name, span)),
-                                name: Some(Ident::new(name, span)),
-                            });
-                            self.names.insert(name, idx);
-                            self.verify_arg_type(Capture(idx), ty)
-                        } else {
-                            let msg = format!("there is no argument named `{}`", name);
-                            let sp = if self.is_literal {
-                                self.fmtsp.from_inner(span)
-                            } else {
-                                self.fmtsp
-                            };
-                            let mut err = self.ecx.struct_span_err(sp, &msg);
-
-                            err.note(&format!(
-                                "did you intend to capture a variable `{}` from \
-                                 the surrounding scope?",
-                                name
-                            ));
-                            err.note(
-                                "to avoid ambiguity, `format_args!` cannot capture variables \
-                                 when the format string is expanded from a macro",
-                            );
-
-                            err.emit();
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    /// Builds the mapping between format placeholders and argument objects.
-    fn build_index_map(&mut self) {
-        // NOTE: Keep the ordering the same as `into_expr`'s expansion would do!
-        let args_len = self.args.len();
-        self.arg_index_map.reserve(args_len);
-
-        let mut sofar = 0usize;
-
-        // Map the arguments
-        for i in 0..args_len {
-            let arg_types = &self.arg_types[i];
-            let arg_offsets = arg_types.iter().map(|offset| sofar + *offset).collect::<Vec<_>>();
-            self.arg_index_map.push(arg_offsets);
-            sofar += self.arg_unique_types[i].len();
-        }
-
-        // Record starting index for counts, which appear just after arguments
-        self.count_args_index_offset = sofar;
-    }
-
-    fn rtpath(ecx: &ExtCtxt<'_>, s: Symbol) -> Vec<Ident> {
-        ecx.std_path(&[sym::fmt, sym::rt, sym::v1, s])
-    }
-
-    fn build_count(&self, c: parse::Count<'_>) -> P<ast::Expr> {
-        let sp = self.macsp;
-        let count = |c, arg| {
-            let mut path = Context::rtpath(self.ecx, sym::Count);
-            path.push(Ident::new(c, sp));
-            match arg {
-                Some(arg) => self.ecx.expr_call_global(sp, path, vec![arg]),
-                None => self.ecx.expr_path(self.ecx.path_global(sp, path)),
-            }
-        };
-        match c {
-            parse::CountIs(i) => count(sym::Is, Some(self.ecx.expr_usize(sp, i))),
-            parse::CountIsParam(i) | parse::CountIsStar(i) => {
-                // This needs mapping too, as `i` is referring to a macro
-                // argument. If `i` is not found in `count_positions` then
-                // the error had already been emitted elsewhere.
-                let i = self.count_positions.get(&i).cloned().unwrap_or(0)
-                    + self.count_args_index_offset;
-                count(sym::Param, Some(self.ecx.expr_usize(sp, i)))
-            }
-            parse::CountImplied => count(sym::Implied, None),
-            // should never be the case, names are already resolved
-            parse::CountIsName(..) => panic!("should never happen"),
-        }
-    }
-
-    /// Build a literal expression from the accumulated string literals
-    fn build_literal_string(&mut self) -> P<ast::Expr> {
-        let sp = self.fmtsp;
-        let s = Symbol::intern(&self.literal);
-        self.literal.clear();
-        self.ecx.expr_str(sp, s)
-    }
-
-    /// Builds a static `rt::Argument` from a `parse::Piece` or append
-    /// to the `literal` string.
-    fn build_piece(
-        &mut self,
-        piece: &parse::Piece<'a>,
-        arg_index_consumed: &mut Vec<usize>,
-    ) -> Option<P<ast::Expr>> {
-        let sp = self.macsp;
-        match *piece {
-            parse::String(s) => {
-                self.literal.push_str(s);
-                None
-            }
-            parse::NextArgument(ref arg) => {
-                // Build the position
-                let pos = {
-                    match arg.position {
-                        parse::ArgumentIs(i, ..) | parse::ArgumentImplicitlyIs(i) => {
-                            // Map to index in final generated argument array
-                            // in case of multiple types specified
-                            let arg_idx = match arg_index_consumed.get_mut(i) {
-                                None => 0, // error already emitted elsewhere
-                                Some(offset) => {
-                                    let idx_map = &self.arg_index_map[i];
-                                    // unwrap_or branch: error already emitted elsewhere
-                                    let arg_idx = *idx_map.get(*offset).unwrap_or(&0);
-                                    *offset += 1;
-                                    arg_idx
-                                }
-                            };
-                            self.ecx.expr_usize(sp, arg_idx)
-                        }
-
-                        // should never be the case, because names are already
-                        // resolved.
-                        parse::ArgumentNamed(..) => panic!("should never happen"),
-                    }
-                };
-
-                let simple_arg = parse::Argument {
-                    position: {
-                        // We don't have ArgumentNext any more, so we have to
-                        // track the current argument ourselves.
-                        let i = self.curarg;
-                        self.curarg += 1;
-                        parse::ArgumentIs(i)
-                    },
-                    position_span: arg.position_span,
-                    format: parse::FormatSpec {
-                        fill: None,
-                        align: parse::AlignUnknown,
-                        flags: 0,
-                        precision: parse::CountImplied,
-                        precision_span: arg.format.precision_span,
-                        width: parse::CountImplied,
-                        width_span: arg.format.width_span,
-                        ty: arg.format.ty,
-                        ty_span: arg.format.ty_span,
-                    },
-                };
-
-                let fill = arg.format.fill.unwrap_or(' ');
-                let pos_simple = arg.position.index() == simple_arg.position.index();
-
-                if !pos_simple || arg.format != simple_arg.format {
-                    self.all_pieces_simple = false;
-                }
-
-                // Build the format
-                let fill = self.ecx.expr_char(sp, fill);
-                let align = |name| {
-                    let mut p = Context::rtpath(self.ecx, sym::Alignment);
-                    p.push(Ident::new(name, sp));
-                    self.ecx.path_global(sp, p)
-                };
-                let align = match arg.format.align {
-                    parse::AlignLeft => align(sym::Left),
-                    parse::AlignRight => align(sym::Right),
-                    parse::AlignCenter => align(sym::Center),
-                    parse::AlignUnknown => align(sym::Unknown),
-                };
-                let align = self.ecx.expr_path(align);
-                let flags = self.ecx.expr_u32(sp, arg.format.flags);
-                let prec = self.build_count(arg.format.precision);
-                let width = self.build_count(arg.format.width);
-                let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, sym::FormatSpec));
-                let fmt = self.ecx.expr_struct(
-                    sp,
-                    path,
-                    vec![
-                        self.ecx.field_imm(sp, Ident::new(sym::fill, sp), fill),
-                        self.ecx.field_imm(sp, Ident::new(sym::align, sp), align),
-                        self.ecx.field_imm(sp, Ident::new(sym::flags, sp), flags),
-                        self.ecx.field_imm(sp, Ident::new(sym::precision, sp), prec),
-                        self.ecx.field_imm(sp, Ident::new(sym::width, sp), width),
-                    ],
-                );
-
-                let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, sym::Argument));
-                Some(self.ecx.expr_struct(
-                    sp,
-                    path,
-                    vec![
-                        self.ecx.field_imm(sp, Ident::new(sym::position, sp), pos),
-                        self.ecx.field_imm(sp, Ident::new(sym::format, sp), fmt),
-                    ],
-                ))
-            }
-        }
-    }
-
-    /// Actually builds the expression which the format_args! block will be
-    /// expanded to.
-    fn into_expr(self) -> P<ast::Expr> {
-        let mut original_args = self.args;
-        let mut fmt_args = Vec::with_capacity(
-            self.arg_unique_types.iter().map(|v| v.len()).sum::<usize>() + self.count_args.len(),
-        );
-
-        // First, build up the static array which will become our precompiled
-        // format "string"
-        let pieces = self.ecx.expr_array_ref(self.fmtsp, self.str_pieces);
-
-        // We need to construct a &[ArgumentV1] to pass into the fmt::Arguments
-        // constructor. In general the expressions in this slice might be
-        // permuted from their order in original_args (such as in the case of
-        // "{1} {0}"), or may have multiple entries referring to the same
-        // element of original_args ("{0} {0}").
-        //
-        // The following vector has one item per element of our output slice,
-        // identifying the index of which element of original_args it's passing,
-        // and that argument's type.
-        let mut fmt_arg_index_and_ty = SmallVec::<[(usize, &ArgumentType); 8]>::new();
-        for (i, unique_types) in self.arg_unique_types.iter().enumerate() {
-            fmt_arg_index_and_ty.extend(unique_types.iter().map(|ty| (i, ty)));
-        }
-        fmt_arg_index_and_ty.extend(self.count_args.iter().map(|&i| (i, &Count)));
-
-        // Figure out whether there are permuted or repeated elements. If not,
-        // we can generate simpler code.
-        //
-        // The sequence has no indices out of order or repeated if: for every
-        // adjacent pair of elements, the first one's index is less than the
-        // second one's index.
-        let nicely_ordered =
-            fmt_arg_index_and_ty.array_windows().all(|[(i, _i_ty), (j, _j_ty)]| i < j);
-
-        // We want to emit:
-        //
-        //     [ArgumentV1::new(&$arg0, …), ArgumentV1::new(&$arg1, …), …]
-        //
-        // However, it's only legal to do so if $arg0, $arg1, … were written in
-        // exactly that order by the programmer. When arguments are permuted, we
-        // want them evaluated in the order written by the programmer, not in
-        // the order provided to fmt::Arguments. When arguments are repeated, we
-        // want the expression evaluated only once.
-        //
-        // Further, if any arg _after the first one_ contains a yield point such
-        // as `await` or `yield`, the above short form is inconvenient for the
-        // caller because it would keep a temporary of type ArgumentV1 alive
-        // across the yield point. ArgumentV1 can't implement Send since it
-        // holds a type-erased arbitrary type.
-        //
-        // Thus in the not nicely ordered case, and in the yielding case, we
-        // emit the following instead:
-        //
-        //     match (&$arg0, &$arg1, …) {
-        //         args => [ArgumentV1::new(args.$i, …), ArgumentV1::new(args.$j, …), …]
-        //     }
-        //
-        // for the sequence of indices $i, $j, … governed by fmt_arg_index_and_ty.
-        // This more verbose representation ensures that all arguments are
-        // evaluated a single time each, in the order written by the programmer,
-        // and that the surrounding future/generator (if any) is Send whenever
-        // possible.
-        let no_need_for_match = nicely_ordered
-            && !original_args.iter().skip(1).any(|arg| may_contain_yield_point(&arg.expr));
-
-        for (arg_index, arg_ty) in fmt_arg_index_and_ty {
-            let e = &mut original_args[arg_index].expr;
-            let span = e.span;
-            let arg = if no_need_for_match {
-                let expansion_span = e.span.with_ctxt(self.macsp.ctxt());
-                // The indices are strictly ordered so e has not been taken yet.
-                self.ecx.expr_addr_of(expansion_span, P(e.take()))
-            } else {
-                let def_site = self.ecx.with_def_site_ctxt(span);
-                let args_tuple = self.ecx.expr_ident(def_site, Ident::new(sym::args, def_site));
-                let member = Ident::new(sym::integer(arg_index), def_site);
-                self.ecx.expr(def_site, ast::ExprKind::Field(args_tuple, member))
-            };
-            fmt_args.push(Context::format_arg(self.ecx, self.macsp, span, arg_ty, arg));
-        }
-
-        let args_array = self.ecx.expr_array(self.macsp, fmt_args);
-        let args_slice = self.ecx.expr_addr_of(
-            self.macsp,
-            if no_need_for_match {
-                args_array
-            } else {
-                // In the !no_need_for_match case, none of the exprs were moved
-                // away in the previous loop.
-                //
-                // This uses the arg span for `&arg` so that borrowck errors
-                // point to the specific expression passed to the macro (the
-                // span is otherwise unavailable in the MIR used by borrowck).
-                let heads = original_args
-                    .into_iter()
-                    .map(|arg| {
-                        self.ecx.expr_addr_of(arg.expr.span.with_ctxt(self.macsp.ctxt()), arg.expr)
-                    })
-                    .collect();
-
-                let pat = self.ecx.pat_ident(self.macsp, Ident::new(sym::args, self.macsp));
-                let arm = self.ecx.arm(self.macsp, pat, args_array);
-                let head = self.ecx.expr(self.macsp, ast::ExprKind::Tup(heads));
-                self.ecx.expr_match(self.macsp, head, vec![arm])
-            },
-        );
-
-        // Now create the fmt::Arguments struct with all our locals we created.
-        let (fn_name, fn_args) = if self.all_pieces_simple {
-            ("new_v1", vec![pieces, args_slice])
-        } else {
-            // Build up the static array which will store our precompiled
-            // nonstandard placeholders, if there are any.
-            let fmt = self.ecx.expr_array_ref(self.macsp, self.pieces);
-
-            let path = self.ecx.std_path(&[sym::fmt, sym::UnsafeArg, sym::new]);
-            let unsafe_arg = self.ecx.expr_call_global(self.macsp, path, Vec::new());
-            let unsafe_expr = self.ecx.expr_block(P(ast::Block {
-                stmts: vec![self.ecx.stmt_expr(unsafe_arg)],
-                id: ast::DUMMY_NODE_ID,
-                rules: BlockCheckMode::Unsafe(UnsafeSource::CompilerGenerated),
-                span: self.macsp,
-                tokens: None,
-                could_be_bare_literal: false,
-            }));
-
-            ("new_v1_formatted", vec![pieces, args_slice, fmt, unsafe_expr])
-        };
-
-        let path = self.ecx.std_path(&[sym::fmt, sym::Arguments, Symbol::intern(fn_name)]);
-        self.ecx.expr_call_global(self.macsp, path, fn_args)
-    }
-
-    fn format_arg(
-        ecx: &ExtCtxt<'_>,
-        macsp: Span,
-        mut sp: Span,
-        ty: &ArgumentType,
-        arg: P<ast::Expr>,
-    ) -> P<ast::Expr> {
-        sp = ecx.with_def_site_ctxt(sp);
-        let trait_ = match *ty {
-            Placeholder(trait_) if trait_ == "<invalid>" => return DummyResult::raw_expr(sp, true),
-            Placeholder(trait_) => trait_,
-            Count => {
-                let path = ecx.std_path(&[sym::fmt, sym::ArgumentV1, sym::from_usize]);
-                return ecx.expr_call_global(macsp, path, vec![arg]);
-            }
-        };
-        let new_fn_name = match trait_ {
-            "Display" => "new_display",
-            "Debug" => "new_debug",
-            "LowerExp" => "new_lower_exp",
-            "UpperExp" => "new_upper_exp",
-            "Octal" => "new_octal",
-            "Pointer" => "new_pointer",
-            "Binary" => "new_binary",
-            "LowerHex" => "new_lower_hex",
-            "UpperHex" => "new_upper_hex",
-            _ => unreachable!(),
-        };
-
-        let path = ecx.std_path(&[sym::fmt, sym::ArgumentV1, Symbol::intern(new_fn_name)]);
-        ecx.expr_call_global(sp, path, vec![arg])
-    }
-}
-
-fn expand_format_args_impl<'cx>(
-    ecx: &'cx mut ExtCtxt<'_>,
-    mut sp: Span,
-    tts: TokenStream,
-    nl: bool,
-) -> Box<dyn base::MacResult + 'cx> {
-    sp = ecx.with_def_site_ctxt(sp);
-    match parse_args(ecx, sp, tts) {
-        Ok((efmt, args, names)) => {
-            MacEager::expr(expand_preparsed_format_args(ecx, sp, efmt, args, names, nl))
-        }
-        Err(mut err) => {
-            err.emit();
-            DummyResult::any(sp)
-        }
-    }
-}
-
-pub fn expand_format_args<'cx>(
-    ecx: &'cx mut ExtCtxt<'_>,
-    sp: Span,
-    tts: TokenStream,
-) -> Box<dyn base::MacResult + 'cx> {
-    expand_format_args_impl(ecx, sp, tts, false)
-}
-
-pub fn expand_format_args_nl<'cx>(
-    ecx: &'cx mut ExtCtxt<'_>,
-    sp: Span,
-    tts: TokenStream,
-) -> Box<dyn base::MacResult + 'cx> {
-    expand_format_args_impl(ecx, sp, tts, true)
-}
-
-fn create_lints_for_named_arguments_used_positionally(cx: &mut Context<'_, '_>) {
-    for named_arg in &cx.unused_names_lint.positional_named_args {
-        let (position_sp_to_replace, position_sp_for_msg) = named_arg.get_positional_arg_spans(cx);
-
-        let msg = format!("named argument `{}` is not used by name", named_arg.replacement);
-
-        cx.ecx.buffered_early_lint.push(BufferedEarlyLint {
-            span: MultiSpan::from_span(named_arg.positional_named_arg_span),
-            msg: msg.into(),
-            node_id: ast::CRATE_NODE_ID,
-            lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY),
-            diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally {
-                position_sp_to_replace,
-                position_sp_for_msg,
-                named_arg_sp: named_arg.positional_named_arg_span,
-                named_arg_name: named_arg.replacement.to_string(),
-                is_formatting_arg: named_arg.ty != PositionalNamedArgType::Arg,
-            },
-        });
-    }
-}
-
-/// Take the various parts of `format_args!(efmt, args..., name=names...)`
-/// and construct the appropriate formatting expression.
-pub fn expand_preparsed_format_args(
+pub fn make_format_args(
     ecx: &mut ExtCtxt<'_>,
-    sp: Span,
-    efmt: P<ast::Expr>,
-    args: Vec<FormatArg>,
-    names: FxHashMap<Symbol, usize>,
+    efmt: P<Expr>,
+    mut args: FormatArguments,
     append_newline: bool,
-) -> P<ast::Expr> {
-    // NOTE: this verbose way of initializing `Vec<Vec<ArgumentType>>` is because
-    // `ArgumentType` does not derive `Clone`.
-    let arg_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect();
-    let arg_unique_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect();
-
-    let mut macsp = ecx.call_site();
-    macsp = ecx.with_def_site_ctxt(macsp);
-
+) -> Result<FormatArgs, ()> {
     let msg = "format argument must be a string literal";
-    let fmt_sp = efmt.span;
-    let efmt_kind_is_lit: bool = matches!(efmt.kind, ast::ExprKind::Lit(_));
+    let fmt_span = efmt.span;
     let (fmt_str, fmt_style, fmt_span) = match expr_to_spanned_string(ecx, efmt, msg) {
         Ok(mut fmt) if append_newline => {
             fmt.0 = Symbol::intern(&format!("{}\n", fmt.0));
@@ -1224,13 +168,13 @@ pub fn expand_preparsed_format_args(
         Ok(fmt) => fmt,
         Err(err) => {
             if let Some((mut err, suggested)) = err {
-                let sugg_fmt = match args.len() {
+                let sugg_fmt = match args.explicit_args().len() {
                     0 => "{}".to_string(),
-                    _ => format!("{}{{}}", "{} ".repeat(args.len())),
+                    _ => format!("{}{{}}", "{} ".repeat(args.explicit_args().len())),
                 };
                 if !suggested {
                     err.span_suggestion(
-                        fmt_sp.shrink_to_lo(),
+                        fmt_span.shrink_to_lo(),
                         "you might be missing a string literal to format with",
                         format!("\"{}\", ", sugg_fmt),
                         Applicability::MaybeIncorrect,
@@ -1238,17 +182,17 @@ pub fn expand_preparsed_format_args(
                 }
                 err.emit();
             }
-            return DummyResult::raw_expr(sp, true);
+            return Err(());
         }
     };
 
     let str_style = match fmt_style {
-        ast::StrStyle::Cooked => None,
-        ast::StrStyle::Raw(raw) => Some(raw as usize),
+        rustc_ast::StrStyle::Cooked => None,
+        rustc_ast::StrStyle::Raw(raw) => Some(raw as usize),
     };
 
     let fmt_str = fmt_str.as_str(); // for the suggestions below
-    let fmt_snippet = ecx.source_map().span_to_snippet(fmt_sp).ok();
+    let fmt_snippet = ecx.source_map().span_to_snippet(fmt_span).ok();
     let mut parser = parse::Parser::new(
         fmt_str,
         str_style,
@@ -1257,18 +201,20 @@ pub fn expand_preparsed_format_args(
         parse::ParseMode::Format,
     );
 
-    let mut unverified_pieces = Vec::new();
+    let mut pieces = Vec::new();
     while let Some(piece) = parser.next() {
         if !parser.errors.is_empty() {
             break;
         } else {
-            unverified_pieces.push(piece);
+            pieces.push(piece);
         }
     }
 
+    let is_literal = parser.is_literal;
+
     if !parser.errors.is_empty() {
         let err = parser.errors.remove(0);
-        let sp = if efmt_kind_is_lit {
+        let sp = if is_literal {
             fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end))
         } else {
             // The format string could be another macro invocation, e.g.:
@@ -1286,25 +232,21 @@ pub fn expand_preparsed_format_args(
         if let Some(note) = err.note {
             e.note(&note);
         }
-        if let Some((label, span)) = err.secondary_label {
-            if efmt_kind_is_lit {
-                e.span_label(fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label);
-            }
+        if let Some((label, span)) = err.secondary_label && is_literal {
+            e.span_label(fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label);
         }
         if err.should_be_replaced_with_positional_argument {
             let captured_arg_span =
                 fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end));
-            let n_positional_args =
-                args.iter().rposition(|arg| arg.name.is_none()).map_or(0, |i| i + 1);
             if let Ok(arg) = ecx.source_map().span_to_snippet(captured_arg_span) {
-                let span = match args[..n_positional_args].last() {
+                let span = match args.unnamed_args().last() {
                     Some(arg) => arg.expr.span,
-                    None => fmt_sp,
+                    None => fmt_span,
                 };
                 e.multipart_suggestion_verbose(
                     "consider using a positional formatting argument instead",
                     vec![
-                        (captured_arg_span, n_positional_args.to_string()),
+                        (captured_arg_span, args.unnamed_args().len().to_string()),
                         (span.shrink_to_hi(), format!(", {}", arg)),
                     ],
                     Applicability::MachineApplicable,
@@ -1312,241 +254,626 @@ pub fn expand_preparsed_format_args(
             }
         }
         e.emit();
-        return DummyResult::raw_expr(sp, true);
+        return Err(());
     }
 
-    let arg_spans = parser
-        .arg_places
-        .iter()
-        .map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end)))
-        .collect();
+    let to_span = |inner_span: rustc_parse_format::InnerSpan| {
+        is_literal.then(|| {
+            fmt_span.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end })
+        })
+    };
+
+    let mut used = vec![false; args.explicit_args().len()];
+    let mut invalid_refs = Vec::new();
+    let mut numeric_refences_to_named_arg = Vec::new();
 
-    let mut cx = Context {
-        ecx,
-        args,
-        num_captured_args: 0,
-        arg_types,
-        arg_unique_types,
-        names,
-        curarg: 0,
-        curpiece: 0,
-        arg_index_map: Vec::new(),
-        count_args: Vec::new(),
-        count_positions: FxHashMap::default(),
-        count_positions_count: 0,
-        count_args_index_offset: 0,
-        literal: String::new(),
-        pieces: Vec::with_capacity(unverified_pieces.len()),
-        str_pieces: Vec::with_capacity(unverified_pieces.len()),
-        all_pieces_simple: true,
-        macsp,
-        fmtsp: fmt_span,
-        invalid_refs: Vec::new(),
-        arg_spans,
-        arg_with_formatting: Vec::new(),
-        is_literal: parser.is_literal,
-        unused_names_lint: PositionalNamedArgsLint { positional_named_args: vec![] },
+    enum ArgRef<'a> {
+        Index(usize),
+        Name(&'a str, Option<Span>),
+    }
+    use ArgRef::*;
+
+    let mut lookup_arg = |arg: ArgRef<'_>,
+                          span: Option<Span>,
+                          used_as: PositionUsedAs,
+                          kind: FormatArgPositionKind|
+     -> FormatArgPosition {
+        let index = match arg {
+            Index(index) => {
+                if let Some(arg) = args.by_index(index) {
+                    used[index] = true;
+                    if arg.kind.ident().is_some() {
+                        // This was a named argument, but it was used as a positional argument.
+                        numeric_refences_to_named_arg.push((index, span, used_as));
+                    }
+                    Ok(index)
+                } else {
+                    // Doesn't exist as an explicit argument.
+                    invalid_refs.push((index, span, used_as, kind));
+                    Err(index)
+                }
+            }
+            Name(name, span) => {
+                let name = Symbol::intern(name);
+                if let Some((index, _)) = args.by_name(name) {
+                    // Name found in `args`, so we resolve it to its index.
+                    if index < args.explicit_args().len() {
+                        // Mark it as used, if it was an explicit argument.
+                        used[index] = true;
+                    }
+                    Ok(index)
+                } else {
+                    // Name not found in `args`, so we add it as an implicitly captured argument.
+                    let span = span.unwrap_or(fmt_span);
+                    let ident = Ident::new(name, span);
+                    let expr = if is_literal {
+                        ecx.expr_ident(span, ident)
+                    } else {
+                        // For the moment capturing variables from format strings expanded from macros is
+                        // disabled (see RFC #2795)
+                        ecx.struct_span_err(span, &format!("there is no argument named `{name}`"))
+                            .note(format!("did you intend to capture a variable `{name}` from the surrounding scope?"))
+                            .note("to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro")
+                            .emit();
+                        DummyResult::raw_expr(span, true)
+                    };
+                    Ok(args.add(FormatArgument { kind: FormatArgumentKind::Captured(ident), expr }))
+                }
+            }
+        };
+        FormatArgPosition { index, kind, span }
     };
 
-    // This needs to happen *after* the Parser has consumed all pieces to create all the spans
-    let pieces = unverified_pieces
-        .into_iter()
-        .map(|mut piece| {
-            cx.verify_piece(&piece);
-            cx.resolve_name_inplace(&mut piece);
-            piece
-        })
-        .collect::<Vec<_>>();
+    let mut template = Vec::new();
+    let mut unfinished_literal = String::new();
+    let mut placeholder_index = 0;
 
-    let numbered_position_args = pieces.iter().any(|arg: &parse::Piece<'_>| match *arg {
-        parse::String(_) => false,
-        parse::NextArgument(arg) => matches!(arg.position, parse::Position::ArgumentIs(..)),
-    });
+    for piece in pieces {
+        match piece {
+            parse::Piece::String(s) => {
+                unfinished_literal.push_str(s);
+            }
+            parse::Piece::NextArgument(parse::Argument { position, position_span, format }) => {
+                if !unfinished_literal.is_empty() {
+                    template.push(FormatArgsPiece::Literal(Symbol::intern(&unfinished_literal)));
+                    unfinished_literal.clear();
+                }
 
-    cx.build_index_map();
+                let span = parser.arg_places.get(placeholder_index).and_then(|&s| to_span(s));
+                placeholder_index += 1;
+
+                let position_span = to_span(position_span);
+                let argument = match position {
+                    parse::ArgumentImplicitlyIs(i) => lookup_arg(
+                        Index(i),
+                        position_span,
+                        Placeholder(span),
+                        FormatArgPositionKind::Implicit,
+                    ),
+                    parse::ArgumentIs(i) => lookup_arg(
+                        Index(i),
+                        position_span,
+                        Placeholder(span),
+                        FormatArgPositionKind::Number,
+                    ),
+                    parse::ArgumentNamed(name) => lookup_arg(
+                        Name(name, position_span),
+                        position_span,
+                        Placeholder(span),
+                        FormatArgPositionKind::Named,
+                    ),
+                };
 
-    let mut arg_index_consumed = vec![0usize; cx.arg_index_map.len()];
+                let alignment = match format.align {
+                    parse::AlignUnknown => None,
+                    parse::AlignLeft => Some(FormatAlignment::Left),
+                    parse::AlignRight => Some(FormatAlignment::Right),
+                    parse::AlignCenter => Some(FormatAlignment::Center),
+                };
 
-    for piece in pieces {
-        if let Some(piece) = cx.build_piece(&piece, &mut arg_index_consumed) {
-            let s = cx.build_literal_string();
-            cx.str_pieces.push(s);
-            cx.pieces.push(piece);
+                let format_trait = match format.ty {
+                    "" => FormatTrait::Display,
+                    "?" => FormatTrait::Debug,
+                    "e" => FormatTrait::LowerExp,
+                    "E" => FormatTrait::UpperExp,
+                    "o" => FormatTrait::Octal,
+                    "p" => FormatTrait::Pointer,
+                    "b" => FormatTrait::Binary,
+                    "x" => FormatTrait::LowerHex,
+                    "X" => FormatTrait::UpperHex,
+                    _ => {
+                        invalid_placeholder_type_error(ecx, format.ty, format.ty_span, fmt_span);
+                        FormatTrait::Display
+                    }
+                };
+
+                let precision_span = format.precision_span.and_then(to_span);
+                let precision = match format.precision {
+                    parse::CountIs(n) => Some(FormatCount::Literal(n)),
+                    parse::CountIsName(name, name_span) => Some(FormatCount::Argument(lookup_arg(
+                        Name(name, to_span(name_span)),
+                        precision_span,
+                        Precision,
+                        FormatArgPositionKind::Named,
+                    ))),
+                    parse::CountIsParam(i) => Some(FormatCount::Argument(lookup_arg(
+                        Index(i),
+                        precision_span,
+                        Precision,
+                        FormatArgPositionKind::Number,
+                    ))),
+                    parse::CountIsStar(i) => Some(FormatCount::Argument(lookup_arg(
+                        Index(i),
+                        precision_span,
+                        Precision,
+                        FormatArgPositionKind::Implicit,
+                    ))),
+                    parse::CountImplied => None,
+                };
+
+                let width_span = format.width_span.and_then(to_span);
+                let width = match format.width {
+                    parse::CountIs(n) => Some(FormatCount::Literal(n)),
+                    parse::CountIsName(name, name_span) => Some(FormatCount::Argument(lookup_arg(
+                        Name(name, to_span(name_span)),
+                        width_span,
+                        Width,
+                        FormatArgPositionKind::Named,
+                    ))),
+                    parse::CountIsParam(i) => Some(FormatCount::Argument(lookup_arg(
+                        Index(i),
+                        width_span,
+                        Width,
+                        FormatArgPositionKind::Number,
+                    ))),
+                    parse::CountIsStar(_) => unreachable!(),
+                    parse::CountImplied => None,
+                };
+
+                template.push(FormatArgsPiece::Placeholder(FormatPlaceholder {
+                    argument,
+                    span,
+                    format_trait,
+                    format_options: FormatOptions {
+                        fill: format.fill,
+                        alignment,
+                        flags: format.flags,
+                        precision,
+                        width,
+                    },
+                }));
+            }
         }
     }
 
-    if !cx.literal.is_empty() {
-        let s = cx.build_literal_string();
-        cx.str_pieces.push(s);
+    if !unfinished_literal.is_empty() {
+        template.push(FormatArgsPiece::Literal(Symbol::intern(&unfinished_literal)));
     }
 
-    if !cx.invalid_refs.is_empty() {
-        cx.report_invalid_references(numbered_position_args);
+    if !invalid_refs.is_empty() {
+        report_invalid_references(ecx, &invalid_refs, &template, fmt_span, &args, parser);
     }
 
-    // Make sure that all arguments were used and all arguments have types.
-    let errs = cx
-        .arg_types
+    let unused = used
         .iter()
         .enumerate()
-        .filter(|(i, ty)| ty.is_empty() && !cx.count_positions.contains_key(&i))
+        .filter(|&(_, used)| !used)
         .map(|(i, _)| {
-            let msg = if cx.args[i].name.is_some() {
+            let msg = if let FormatArgumentKind::Named(_) = args.explicit_args()[i].kind {
                 "named argument never used"
             } else {
                 "argument never used"
             };
-            (cx.args[i].expr.span, msg)
+            (args.explicit_args()[i].expr.span, msg)
         })
         .collect::<Vec<_>>();
 
-    let errs_len = errs.len();
-    if !errs.is_empty() {
-        let args_used = cx.arg_types.len() - errs_len;
-        let args_unused = errs_len;
+    if !unused.is_empty() {
+        // If there's a lot of unused arguments,
+        // let's check if this format arguments looks like another syntax (printf / shell).
+        let detect_foreign_fmt = unused.len() > args.explicit_args().len() / 2;
+        report_missing_placeholders(ecx, unused, detect_foreign_fmt, str_style, fmt_str, fmt_span);
+    }
 
-        let mut diag = {
-            if let [(sp, msg)] = &errs[..] {
-                let mut diag = cx.ecx.struct_span_err(*sp, *msg);
-                diag.span_label(*sp, *msg);
-                diag
-            } else {
-                let mut diag = cx.ecx.struct_span_err(
-                    errs.iter().map(|&(sp, _)| sp).collect::<Vec<Span>>(),
-                    "multiple unused formatting arguments",
-                );
-                diag.span_label(cx.fmtsp, "multiple missing formatting specifiers");
-                for (sp, msg) in errs {
-                    diag.span_label(sp, msg);
+    // Only check for unused named argument names if there are no other errors to avoid causing
+    // too much noise in output errors, such as when a named argument is entirely unused.
+    if invalid_refs.is_empty() && ecx.sess.err_count() == 0 {
+        for &(index, span, used_as) in &numeric_refences_to_named_arg {
+            let (position_sp_to_replace, position_sp_for_msg) = match used_as {
+                Placeholder(pspan) => (span, pspan),
+                Precision => {
+                    // Strip the leading `.` for precision.
+                    let span = span.map(|span| span.with_lo(span.lo() + BytePos(1)));
+                    (span, span)
                 }
-                diag
-            }
-        };
+                Width => (span, span),
+            };
+            let arg_name = args.explicit_args()[index].kind.ident().unwrap();
+            ecx.buffered_early_lint.push(BufferedEarlyLint {
+                span: arg_name.span.into(),
+                msg: format!("named argument `{}` is not used by name", arg_name.name).into(),
+                node_id: rustc_ast::CRATE_NODE_ID,
+                lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY),
+                diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally {
+                    position_sp_to_replace,
+                    position_sp_for_msg,
+                    named_arg_sp: arg_name.span,
+                    named_arg_name: arg_name.name.to_string(),
+                    is_formatting_arg: matches!(used_as, Width | Precision),
+                },
+            });
+        }
+    }
 
-        // Used to ensure we only report translations for *one* kind of foreign format.
-        let mut found_foreign = false;
-        // Decide if we want to look for foreign formatting directives.
-        if args_used < args_unused {
-            use super::format_foreign as foreign;
+    Ok(FormatArgs { span: fmt_span, template, arguments: args })
+}
 
-            // The set of foreign substitutions we've explained.  This prevents spamming the user
-            // with `%d should be written as {}` over and over again.
-            let mut explained = FxHashSet::default();
+fn invalid_placeholder_type_error(
+    ecx: &ExtCtxt<'_>,
+    ty: &str,
+    ty_span: Option<rustc_parse_format::InnerSpan>,
+    fmt_span: Span,
+) {
+    let sp = ty_span.map(|sp| fmt_span.from_inner(InnerSpan::new(sp.start, sp.end)));
+    let mut err =
+        ecx.struct_span_err(sp.unwrap_or(fmt_span), &format!("unknown format trait `{}`", ty));
+    err.note(
+        "the only appropriate formatting traits are:\n\
+                                - ``, which uses the `Display` trait\n\
+                                - `?`, which uses the `Debug` trait\n\
+                                - `e`, which uses the `LowerExp` trait\n\
+                                - `E`, which uses the `UpperExp` trait\n\
+                                - `o`, which uses the `Octal` trait\n\
+                                - `p`, which uses the `Pointer` trait\n\
+                                - `b`, which uses the `Binary` trait\n\
+                                - `x`, which uses the `LowerHex` trait\n\
+                                - `X`, which uses the `UpperHex` trait",
+    );
+    if let Some(sp) = sp {
+        for (fmt, name) in &[
+            ("", "Display"),
+            ("?", "Debug"),
+            ("e", "LowerExp"),
+            ("E", "UpperExp"),
+            ("o", "Octal"),
+            ("p", "Pointer"),
+            ("b", "Binary"),
+            ("x", "LowerHex"),
+            ("X", "UpperHex"),
+        ] {
+            err.tool_only_span_suggestion(
+                sp,
+                &format!("use the `{}` trait", name),
+                *fmt,
+                Applicability::MaybeIncorrect,
+            );
+        }
+    }
+    err.emit();
+}
 
-            macro_rules! check_foreign {
-                ($kind:ident) => {{
-                    let mut show_doc_note = false;
+fn report_missing_placeholders(
+    ecx: &mut ExtCtxt<'_>,
+    unused: Vec<(Span, &str)>,
+    detect_foreign_fmt: bool,
+    str_style: Option<usize>,
+    fmt_str: &str,
+    fmt_span: Span,
+) {
+    let mut diag = if let &[(span, msg)] = &unused[..] {
+        let mut diag = ecx.struct_span_err(span, msg);
+        diag.span_label(span, msg);
+        diag
+    } else {
+        let mut diag = ecx.struct_span_err(
+            unused.iter().map(|&(sp, _)| sp).collect::<Vec<Span>>(),
+            "multiple unused formatting arguments",
+        );
+        diag.span_label(fmt_span, "multiple missing formatting specifiers");
+        for &(span, msg) in &unused {
+            diag.span_label(span, msg);
+        }
+        diag
+    };
 
-                    let mut suggestions = vec![];
-                    // account for `"` and account for raw strings `r#`
-                    let padding = str_style.map(|i| i + 2).unwrap_or(1);
-                    for sub in foreign::$kind::iter_subs(fmt_str, padding) {
-                        let (trn, success) = match sub.translate() {
-                            Ok(trn) => (trn, true),
-                            Err(Some(msg)) => (msg, false),
+    // Used to ensure we only report translations for *one* kind of foreign format.
+    let mut found_foreign = false;
+
+    // Decide if we want to look for foreign formatting directives.
+    if detect_foreign_fmt {
+        use super::format_foreign as foreign;
+
+        // The set of foreign substitutions we've explained.  This prevents spamming the user
+        // with `%d should be written as {}` over and over again.
+        let mut explained = FxHashSet::default();
+
+        macro_rules! check_foreign {
+            ($kind:ident) => {{
+                let mut show_doc_note = false;
+
+                let mut suggestions = vec![];
+                // account for `"` and account for raw strings `r#`
+                let padding = str_style.map(|i| i + 2).unwrap_or(1);
+                for sub in foreign::$kind::iter_subs(fmt_str, padding) {
+                    let (trn, success) = match sub.translate() {
+                        Ok(trn) => (trn, true),
+                        Err(Some(msg)) => (msg, false),
+
+                        // If it has no translation, don't call it out specifically.
+                        _ => continue,
+                    };
+
+                    let pos = sub.position();
+                    let sub = String::from(sub.as_str());
+                    if explained.contains(&sub) {
+                        continue;
+                    }
+                    explained.insert(sub.clone());
 
-                            // If it has no translation, don't call it out specifically.
-                            _ => continue,
-                        };
+                    if !found_foreign {
+                        found_foreign = true;
+                        show_doc_note = true;
+                    }
 
-                        let pos = sub.position();
-                        let sub = String::from(sub.as_str());
-                        if explained.contains(&sub) {
-                            continue;
-                        }
-                        explained.insert(sub.clone());
+                    if let Some(inner_sp) = pos {
+                        let sp = fmt_span.from_inner(inner_sp);
 
-                        if !found_foreign {
-                            found_foreign = true;
-                            show_doc_note = true;
+                        if success {
+                            suggestions.push((sp, trn));
+                        } else {
+                            diag.span_note(
+                                sp,
+                                &format!("format specifiers use curly braces, and {}", trn),
+                            );
                         }
-
-                        if let Some(inner_sp) = pos {
-                            let sp = fmt_sp.from_inner(inner_sp);
-
-                            if success {
-                                suggestions.push((sp, trn));
-                            } else {
-                                diag.span_note(
-                                    sp,
-                                    &format!("format specifiers use curly braces, and {}", trn),
-                                );
-                            }
+                    } else {
+                        if success {
+                            diag.help(&format!("`{}` should be written as `{}`", sub, trn));
                         } else {
-                            if success {
-                                diag.help(&format!("`{}` should be written as `{}`", sub, trn));
-                            } else {
-                                diag.note(&format!(
-                                    "`{}` should use curly braces, and {}",
-                                    sub, trn
-                                ));
-                            }
+                            diag.note(&format!("`{}` should use curly braces, and {}", sub, trn));
                         }
                     }
+                }
 
-                    if show_doc_note {
-                        diag.note(concat!(
-                            stringify!($kind),
-                            " formatting not supported; see the documentation for `std::fmt`",
-                        ));
-                    }
-                    if suggestions.len() > 0 {
-                        diag.multipart_suggestion(
-                            "format specifiers use curly braces",
-                            suggestions,
-                            Applicability::MachineApplicable,
-                        );
-                    }
-                }};
-            }
-
-            check_foreign!(printf);
-            if !found_foreign {
-                check_foreign!(shell);
-            }
-        }
-        if !found_foreign && errs_len == 1 {
-            diag.span_label(cx.fmtsp, "formatting specifier missing");
+                if show_doc_note {
+                    diag.note(concat!(
+                        stringify!($kind),
+                        " formatting not supported; see the documentation for `std::fmt`",
+                    ));
+                }
+                if suggestions.len() > 0 {
+                    diag.multipart_suggestion(
+                        "format specifiers use curly braces",
+                        suggestions,
+                        Applicability::MachineApplicable,
+                    );
+                }
+            }};
         }
 
-        diag.emit();
-    } else if cx.invalid_refs.is_empty() && cx.ecx.sess.err_count() == 0 {
-        // Only check for unused named argument names if there are no other errors to avoid causing
-        // too much noise in output errors, such as when a named argument is entirely unused.
-        create_lints_for_named_arguments_used_positionally(&mut cx);
+        check_foreign!(printf);
+        if !found_foreign {
+            check_foreign!(shell);
+        }
+    }
+    if !found_foreign && unused.len() == 1 {
+        diag.span_label(fmt_span, "formatting specifier missing");
     }
 
-    cx.into_expr()
+    diag.emit();
 }
 
-fn may_contain_yield_point(e: &ast::Expr) -> bool {
-    struct MayContainYieldPoint(bool);
+/// Handle invalid references to positional arguments. Output different
+/// errors for the case where all arguments are positional and for when
+/// there are named arguments or numbered positional arguments in the
+/// format string.
+fn report_invalid_references(
+    ecx: &mut ExtCtxt<'_>,
+    invalid_refs: &[(usize, Option<Span>, PositionUsedAs, FormatArgPositionKind)],
+    template: &[FormatArgsPiece],
+    fmt_span: Span,
+    args: &FormatArguments,
+    parser: parse::Parser<'_>,
+) {
+    let num_args_desc = match args.explicit_args().len() {
+        0 => "no arguments were given".to_string(),
+        1 => "there is 1 argument".to_string(),
+        n => format!("there are {} arguments", n),
+    };
+
+    let mut e;
 
-    impl Visitor<'_> for MayContainYieldPoint {
-        fn visit_expr(&mut self, e: &ast::Expr) {
-            if let ast::ExprKind::Await(_) | ast::ExprKind::Yield(_) = e.kind {
-                self.0 = true;
-            } else {
-                visit::walk_expr(self, e);
+    if template.iter().all(|piece| match piece {
+        FormatArgsPiece::Placeholder(FormatPlaceholder {
+            argument: FormatArgPosition { kind: FormatArgPositionKind::Number, .. },
+            ..
+        }) => false,
+        FormatArgsPiece::Placeholder(FormatPlaceholder {
+            format_options:
+                FormatOptions {
+                    precision:
+                        Some(FormatCount::Argument(FormatArgPosition {
+                            kind: FormatArgPositionKind::Number,
+                            ..
+                        })),
+                    ..
+                }
+                | FormatOptions {
+                    width:
+                        Some(FormatCount::Argument(FormatArgPosition {
+                            kind: FormatArgPositionKind::Number,
+                            ..
+                        })),
+                    ..
+                },
+            ..
+        }) => false,
+        _ => true,
+    }) {
+        // There are no numeric positions.
+        // Collect all the implicit positions:
+        let mut spans = Vec::new();
+        let mut num_placeholders = 0;
+        for piece in template {
+            let mut placeholder = None;
+            // `{arg:.*}`
+            if let FormatArgsPiece::Placeholder(FormatPlaceholder {
+                format_options:
+                    FormatOptions {
+                        precision:
+                            Some(FormatCount::Argument(FormatArgPosition {
+                                span,
+                                kind: FormatArgPositionKind::Implicit,
+                                ..
+                            })),
+                        ..
+                    },
+                ..
+            }) = piece
+            {
+                placeholder = *span;
+                num_placeholders += 1;
             }
+            // `{}`
+            if let FormatArgsPiece::Placeholder(FormatPlaceholder {
+                argument: FormatArgPosition { kind: FormatArgPositionKind::Implicit, .. },
+                span,
+                ..
+            }) = piece
+            {
+                placeholder = *span;
+                num_placeholders += 1;
+            }
+            // For `{:.*}`, we only push one span.
+            spans.extend(placeholder);
         }
-
-        fn visit_mac_call(&mut self, _: &ast::MacCall) {
-            self.0 = true;
+        let span = if spans.is_empty() {
+            MultiSpan::from_span(fmt_span)
+        } else {
+            MultiSpan::from_spans(spans)
+        };
+        e = ecx.struct_span_err(
+            span,
+            &format!(
+                "{} positional argument{} in format string, but {}",
+                num_placeholders,
+                pluralize!(num_placeholders),
+                num_args_desc,
+            ),
+        );
+        for arg in args.explicit_args() {
+            e.span_label(arg.expr.span, "");
+        }
+        // Point out `{:.*}` placeholders: those take an extra argument.
+        let mut has_precision_star = false;
+        for piece in template {
+            if let FormatArgsPiece::Placeholder(FormatPlaceholder {
+                format_options:
+                    FormatOptions {
+                        precision:
+                            Some(FormatCount::Argument(FormatArgPosition {
+                                index,
+                                span: Some(span),
+                                kind: FormatArgPositionKind::Implicit,
+                                ..
+                            })),
+                        ..
+                    },
+                ..
+            }) = piece
+            {
+                let (Ok(index) | Err(index)) = index;
+                has_precision_star = true;
+                e.span_label(
+                    *span,
+                    &format!(
+                        "this precision flag adds an extra required argument at position {}, which is why there {} expected",
+                        index,
+                        if num_placeholders == 1 {
+                            "is 1 argument".to_string()
+                        } else {
+                            format!("are {} arguments", num_placeholders)
+                        },
+                    ),
+                );
+            }
+        }
+        if has_precision_star {
+            e.note("positional arguments are zero-based");
         }
+    } else {
+        let mut indexes: Vec<_> = invalid_refs.iter().map(|&(index, _, _, _)| index).collect();
+        // Avoid `invalid reference to positional arguments 7 and 7 (there is 1 argument)`
+        // for `println!("{7:7$}", 1);`
+        indexes.sort();
+        indexes.dedup();
+        let span: MultiSpan = if !parser.is_literal || parser.arg_places.is_empty() {
+            MultiSpan::from_span(fmt_span)
+        } else {
+            MultiSpan::from_spans(invalid_refs.iter().filter_map(|&(_, span, _, _)| span).collect())
+        };
+        let arg_list = if let &[index] = &indexes[..] {
+            format!("argument {index}")
+        } else {
+            let tail = indexes.pop().unwrap();
+            format!(
+                "arguments {head} and {tail}",
+                head = indexes.into_iter().map(|i| i.to_string()).collect::<Vec<_>>().join(", ")
+            )
+        };
+        e = ecx.struct_span_err(
+            span,
+            &format!("invalid reference to positional {} ({})", arg_list, num_args_desc),
+        );
+        e.note("positional arguments are zero-based");
+    }
 
-        fn visit_attribute(&mut self, _: &ast::Attribute) {
-            // Conservatively assume this may be a proc macro attribute in
-            // expression position.
-            self.0 = true;
+    if template.iter().any(|piece| match piece {
+        FormatArgsPiece::Placeholder(FormatPlaceholder { format_options: f, .. }) => {
+            *f != FormatOptions::default()
         }
+        _ => false,
+    }) {
+        e.note("for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html");
+    }
+
+    e.emit();
+}
 
-        fn visit_item(&mut self, _: &ast::Item) {
-            // Do not recurse into nested items.
+fn expand_format_args_impl<'cx>(
+    ecx: &'cx mut ExtCtxt<'_>,
+    mut sp: Span,
+    tts: TokenStream,
+    nl: bool,
+) -> Box<dyn base::MacResult + 'cx> {
+    sp = ecx.with_def_site_ctxt(sp);
+    match parse_args(ecx, sp, tts) {
+        Ok((efmt, args)) => {
+            if let Ok(format_args) = make_format_args(ecx, efmt, args, nl) {
+                MacEager::expr(expand_parsed_format_args(ecx, format_args))
+            } else {
+                MacEager::expr(DummyResult::raw_expr(sp, true))
+            }
+        }
+        Err(mut err) => {
+            err.emit();
+            DummyResult::any(sp)
         }
     }
+}
+
+pub fn expand_format_args<'cx>(
+    ecx: &'cx mut ExtCtxt<'_>,
+    sp: Span,
+    tts: TokenStream,
+) -> Box<dyn base::MacResult + 'cx> {
+    expand_format_args_impl(ecx, sp, tts, false)
+}
 
-    let mut visitor = MayContainYieldPoint(false);
-    visitor.visit_expr(e);
-    visitor.0
+pub fn expand_format_args_nl<'cx>(
+    ecx: &'cx mut ExtCtxt<'_>,
+    sp: Span,
+    tts: TokenStream,
+) -> Box<dyn base::MacResult + 'cx> {
+    expand_format_args_impl(ecx, sp, tts, true)
 }
diff --git a/compiler/rustc_builtin_macros/src/format/ast.rs b/compiler/rustc_builtin_macros/src/format/ast.rs
new file mode 100644
index 00000000000..01dbffa21b8
--- /dev/null
+++ b/compiler/rustc_builtin_macros/src/format/ast.rs
@@ -0,0 +1,240 @@
+use rustc_ast::ptr::P;
+use rustc_ast::Expr;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::Span;
+
+// Definitions:
+//
+// format_args!("hello {abc:.xyz$}!!", abc="world");
+// └──────────────────────────────────────────────┘
+//                     FormatArgs
+//
+// format_args!("hello {abc:.xyz$}!!", abc="world");
+//                                     └─────────┘
+//                                      argument
+//
+// format_args!("hello {abc:.xyz$}!!", abc="world");
+//              └───────────────────┘
+//                     template
+//
+// format_args!("hello {abc:.xyz$}!!", abc="world");
+//               └────┘└─────────┘└┘
+//                      pieces
+//
+// format_args!("hello {abc:.xyz$}!!", abc="world");
+//               └────┘           └┘
+//                   literal pieces
+//
+// format_args!("hello {abc:.xyz$}!!", abc="world");
+//                     └─────────┘
+//                     placeholder
+//
+// format_args!("hello {abc:.xyz$}!!", abc="world");
+//                      └─┘  └─┘
+//                      positions (could be names, numbers, empty, or `*`)
+
+/// (Parsed) format args.
+///
+/// Basically the "AST" for a complete `format_args!()`.
+///
+/// E.g., `format_args!("hello {name}");`.
+#[derive(Clone, Debug)]
+pub struct FormatArgs {
+    pub span: Span,
+    pub template: Vec<FormatArgsPiece>,
+    pub arguments: FormatArguments,
+}
+
+/// A piece of a format template string.
+///
+/// E.g. "hello" or "{name}".
+#[derive(Clone, Debug)]
+pub enum FormatArgsPiece {
+    Literal(Symbol),
+    Placeholder(FormatPlaceholder),
+}
+
+/// The arguments to format_args!().
+///
+/// E.g. `1, 2, name="ferris", n=3`,
+/// but also implicit captured arguments like `x` in `format_args!("{x}")`.
+#[derive(Clone, Debug)]
+pub struct FormatArguments {
+    arguments: Vec<FormatArgument>,
+    num_unnamed_args: usize,
+    num_explicit_args: usize,
+    names: FxHashMap<Symbol, usize>,
+}
+
+impl FormatArguments {
+    pub fn new() -> Self {
+        Self {
+            arguments: Vec::new(),
+            names: FxHashMap::default(),
+            num_unnamed_args: 0,
+            num_explicit_args: 0,
+        }
+    }
+
+    pub fn add(&mut self, arg: FormatArgument) -> usize {
+        let index = self.arguments.len();
+        if let Some(name) = arg.kind.ident() {
+            self.names.insert(name.name, index);
+        } else if self.names.is_empty() {
+            // Only count the unnamed args before the first named arg.
+            // (Any later ones are errors.)
+            self.num_unnamed_args += 1;
+        }
+        if !matches!(arg.kind, FormatArgumentKind::Captured(..)) {
+            // This is an explicit argument.
+            // Make sure that all arguments so far are explcit.
+            assert_eq!(
+                self.num_explicit_args,
+                self.arguments.len(),
+                "captured arguments must be added last"
+            );
+            self.num_explicit_args += 1;
+        }
+        self.arguments.push(arg);
+        index
+    }
+
+    pub fn by_name(&self, name: Symbol) -> Option<(usize, &FormatArgument)> {
+        let i = *self.names.get(&name)?;
+        Some((i, &self.arguments[i]))
+    }
+
+    pub fn by_index(&self, i: usize) -> Option<&FormatArgument> {
+        (i < self.num_explicit_args).then(|| &self.arguments[i])
+    }
+
+    pub fn unnamed_args(&self) -> &[FormatArgument] {
+        &self.arguments[..self.num_unnamed_args]
+    }
+
+    pub fn named_args(&self) -> &[FormatArgument] {
+        &self.arguments[self.num_unnamed_args..self.num_explicit_args]
+    }
+
+    pub fn explicit_args(&self) -> &[FormatArgument] {
+        &self.arguments[..self.num_explicit_args]
+    }
+
+    pub fn into_vec(self) -> Vec<FormatArgument> {
+        self.arguments
+    }
+}
+
+#[derive(Clone, Debug)]
+pub struct FormatArgument {
+    pub kind: FormatArgumentKind,
+    pub expr: P<Expr>,
+}
+
+#[derive(Clone, Debug)]
+pub enum FormatArgumentKind {
+    /// `format_args(…, arg)`
+    Normal,
+    /// `format_args(…, arg = 1)`
+    Named(Ident),
+    /// `format_args("… {arg} …")`
+    Captured(Ident),
+}
+
+impl FormatArgumentKind {
+    pub fn ident(&self) -> Option<Ident> {
+        match self {
+            &Self::Normal => None,
+            &Self::Named(id) => Some(id),
+            &Self::Captured(id) => Some(id),
+        }
+    }
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct FormatPlaceholder {
+    /// Index into [`FormatArgs::arguments`].
+    pub argument: FormatArgPosition,
+    /// The span inside the format string for the full `{…}` placeholder.
+    pub span: Option<Span>,
+    /// `{}`, `{:?}`, or `{:x}`, etc.
+    pub format_trait: FormatTrait,
+    /// `{}` or `{:.5}` or `{:-^20}`, etc.
+    pub format_options: FormatOptions,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct FormatArgPosition {
+    /// Which argument this position refers to (Ok),
+    /// or would've referred to if it existed (Err).
+    pub index: Result<usize, usize>,
+    /// What kind of position this is. See [`FormatArgPositionKind`].
+    pub kind: FormatArgPositionKind,
+    /// The span of the name or number.
+    pub span: Option<Span>,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum FormatArgPositionKind {
+    /// `{}` or `{:.*}`
+    Implicit,
+    /// `{1}` or `{:1$}` or `{:.1$}`
+    Number,
+    /// `{a}` or `{:a$}` or `{:.a$}`
+    Named,
+}
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub enum FormatTrait {
+    /// `{}`
+    Display,
+    /// `{:?}`
+    Debug,
+    /// `{:e}`
+    LowerExp,
+    /// `{:E}`
+    UpperExp,
+    /// `{:o}`
+    Octal,
+    /// `{:p}`
+    Pointer,
+    /// `{:b}`
+    Binary,
+    /// `{:x}`
+    LowerHex,
+    /// `{:X}`
+    UpperHex,
+}
+
+#[derive(Clone, Debug, Default, PartialEq, Eq)]
+pub struct FormatOptions {
+    /// The width. E.g. `{:5}` or `{:width$}`.
+    pub width: Option<FormatCount>,
+    /// The precision. E.g. `{:.5}` or `{:.precision$}`.
+    pub precision: Option<FormatCount>,
+    /// The alignment. E.g. `{:>}` or `{:<}` or `{:^}`.
+    pub alignment: Option<FormatAlignment>,
+    /// The fill character. E.g. the `.` in `{:.>10}`.
+    pub fill: Option<char>,
+    /// The `+`, `-`, `0`, `#`, `x?` and `X?` flags.
+    pub flags: u32,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum FormatAlignment {
+    /// `{:<}`
+    Left,
+    /// `{:>}`
+    Right,
+    /// `{:^}`
+    Center,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum FormatCount {
+    /// `{:5}` or `{:.5}`
+    Literal(usize),
+    /// `{:.*}`, `{:.5$}`, or `{:a$}`, etc.
+    Argument(FormatArgPosition),
+}
diff --git a/compiler/rustc_builtin_macros/src/format/expand.rs b/compiler/rustc_builtin_macros/src/format/expand.rs
new file mode 100644
index 00000000000..9dde5efcb28
--- /dev/null
+++ b/compiler/rustc_builtin_macros/src/format/expand.rs
@@ -0,0 +1,353 @@
+use super::*;
+use rustc_ast as ast;
+use rustc_ast::visit::{self, Visitor};
+use rustc_ast::{BlockCheckMode, UnsafeSource};
+use rustc_data_structures::fx::FxIndexSet;
+use rustc_span::{sym, symbol::kw};
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+enum ArgumentType {
+    Format(FormatTrait),
+    Usize,
+}
+
+fn make_argument(ecx: &ExtCtxt<'_>, sp: Span, arg: P<ast::Expr>, ty: ArgumentType) -> P<ast::Expr> {
+    // Generate:
+    //     ::core::fmt::ArgumentV1::new_…(arg)
+    use ArgumentType::*;
+    use FormatTrait::*;
+    ecx.expr_call_global(
+        sp,
+        ecx.std_path(&[
+            sym::fmt,
+            sym::ArgumentV1,
+            match ty {
+                Format(Display) => sym::new_display,
+                Format(Debug) => sym::new_debug,
+                Format(LowerExp) => sym::new_lower_exp,
+                Format(UpperExp) => sym::new_upper_exp,
+                Format(Octal) => sym::new_octal,
+                Format(Pointer) => sym::new_pointer,
+                Format(Binary) => sym::new_binary,
+                Format(LowerHex) => sym::new_lower_hex,
+                Format(UpperHex) => sym::new_upper_hex,
+                Usize => sym::from_usize,
+            },
+        ]),
+        vec![arg],
+    )
+}
+
+fn make_count(
+    ecx: &ExtCtxt<'_>,
+    sp: Span,
+    count: &Option<FormatCount>,
+    argmap: &mut FxIndexSet<(usize, ArgumentType)>,
+) -> P<ast::Expr> {
+    // Generate:
+    //     ::core::fmt::rt::v1::Count::…(…)
+    match count {
+        Some(FormatCount::Literal(n)) => ecx.expr_call_global(
+            sp,
+            ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Count, sym::Is]),
+            vec![ecx.expr_usize(sp, *n)],
+        ),
+        Some(FormatCount::Argument(arg)) => {
+            if let Ok(arg_index) = arg.index {
+                let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize));
+                ecx.expr_call_global(
+                    sp,
+                    ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Count, sym::Param]),
+                    vec![ecx.expr_usize(sp, i)],
+                )
+            } else {
+                DummyResult::raw_expr(sp, true)
+            }
+        }
+        None => ecx.expr_path(ecx.path_global(
+            sp,
+            ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Count, sym::Implied]),
+        )),
+    }
+}
+
+fn make_format_spec(
+    ecx: &ExtCtxt<'_>,
+    sp: Span,
+    placeholder: &FormatPlaceholder,
+    argmap: &mut FxIndexSet<(usize, ArgumentType)>,
+) -> P<ast::Expr> {
+    // Generate:
+    //     ::core::fmt::rt::v1::Argument {
+    //         position: 0usize,
+    //         format: ::core::fmt::rt::v1::FormatSpec {
+    //             fill: ' ',
+    //             align: ::core::fmt::rt::v1::Alignment::Unknown,
+    //             flags: 0u32,
+    //             precision: ::core::fmt::rt::v1::Count::Implied,
+    //             width: ::core::fmt::rt::v1::Count::Implied,
+    //         },
+    //     }
+    let position = match placeholder.argument.index {
+        Ok(arg_index) => {
+            let (i, _) =
+                argmap.insert_full((arg_index, ArgumentType::Format(placeholder.format_trait)));
+            ecx.expr_usize(sp, i)
+        }
+        Err(_) => DummyResult::raw_expr(sp, true),
+    };
+    let fill = ecx.expr_char(sp, placeholder.format_options.fill.unwrap_or(' '));
+    let align = ecx.expr_path(ecx.path_global(
+        sp,
+        ecx.std_path(&[
+            sym::fmt,
+            sym::rt,
+            sym::v1,
+            sym::Alignment,
+            match placeholder.format_options.alignment {
+                Some(FormatAlignment::Left) => sym::Left,
+                Some(FormatAlignment::Right) => sym::Right,
+                Some(FormatAlignment::Center) => sym::Center,
+                None => sym::Unknown,
+            },
+        ]),
+    ));
+    let flags = ecx.expr_u32(sp, placeholder.format_options.flags);
+    let prec = make_count(ecx, sp, &placeholder.format_options.precision, argmap);
+    let width = make_count(ecx, sp, &placeholder.format_options.width, argmap);
+    ecx.expr_struct(
+        sp,
+        ecx.path_global(sp, ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Argument])),
+        vec![
+            ecx.field_imm(sp, Ident::new(sym::position, sp), position),
+            ecx.field_imm(
+                sp,
+                Ident::new(sym::format, sp),
+                ecx.expr_struct(
+                    sp,
+                    ecx.path_global(
+                        sp,
+                        ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::FormatSpec]),
+                    ),
+                    vec![
+                        ecx.field_imm(sp, Ident::new(sym::fill, sp), fill),
+                        ecx.field_imm(sp, Ident::new(sym::align, sp), align),
+                        ecx.field_imm(sp, Ident::new(sym::flags, sp), flags),
+                        ecx.field_imm(sp, Ident::new(sym::precision, sp), prec),
+                        ecx.field_imm(sp, Ident::new(sym::width, sp), width),
+                    ],
+                ),
+            ),
+        ],
+    )
+}
+
+pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<ast::Expr> {
+    let macsp = ecx.with_def_site_ctxt(ecx.call_site());
+
+    let lit_pieces = ecx.expr_array_ref(
+        fmt.span,
+        fmt.template
+            .iter()
+            .enumerate()
+            .filter_map(|(i, piece)| match piece {
+                &FormatArgsPiece::Literal(s) => Some(ecx.expr_str(fmt.span, s)),
+                &FormatArgsPiece::Placeholder(_) => {
+                    // Inject empty string before placeholders when not already preceded by a literal piece.
+                    if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_)) {
+                        Some(ecx.expr_str(fmt.span, kw::Empty))
+                    } else {
+                        None
+                    }
+                }
+            })
+            .collect(),
+    );
+
+    // Whether we'll use the `Arguments::new_v1_formatted` form (true),
+    // or the `Arguments::new_v1` form (false).
+    let mut use_format_options = false;
+
+    // Create a list of all _unique_ (argument, format trait) combinations.
+    // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)]
+    let mut argmap = FxIndexSet::default();
+    for piece in &fmt.template {
+        let FormatArgsPiece::Placeholder(placeholder) = piece else { continue };
+        if placeholder.format_options != Default::default() {
+            // Can't use basic form if there's any formatting options.
+            use_format_options = true;
+        }
+        if let Ok(index) = placeholder.argument.index {
+            if !argmap.insert((index, ArgumentType::Format(placeholder.format_trait))) {
+                // Duplicate (argument, format trait) combination,
+                // which we'll only put once in the args array.
+                use_format_options = true;
+            }
+        }
+    }
+
+    let format_options = use_format_options.then(|| {
+        // Generate:
+        //     &[format_spec_0, format_spec_1, format_spec_2]
+        ecx.expr_array_ref(
+            macsp,
+            fmt.template
+                .iter()
+                .filter_map(|piece| {
+                    let FormatArgsPiece::Placeholder(placeholder) = piece else { return None };
+                    Some(make_format_spec(ecx, macsp, placeholder, &mut argmap))
+                })
+                .collect(),
+        )
+    });
+
+    let arguments = fmt.arguments.into_vec();
+
+    // If the args array contains exactly all the original arguments once,
+    // in order, we can use a simple array instead of a `match` construction.
+    // However, if there's a yield point in any argument except the first one,
+    // we don't do this, because an ArgumentV1 cannot be kept across yield points.
+    let use_simple_array = argmap.len() == arguments.len()
+        && argmap.iter().enumerate().all(|(i, &(j, _))| i == j)
+        && arguments.iter().skip(1).all(|arg| !may_contain_yield_point(&arg.expr));
+
+    let args = if use_simple_array {
+        // Generate:
+        //     &[
+        //         ::core::fmt::ArgumentV1::new_display(&arg0),
+        //         ::core::fmt::ArgumentV1::new_lower_hex(&arg1),
+        //         ::core::fmt::ArgumentV1::new_debug(&arg2),
+        //     ]
+        ecx.expr_array_ref(
+            macsp,
+            arguments
+                .into_iter()
+                .zip(argmap)
+                .map(|(arg, (_, ty))| {
+                    let sp = arg.expr.span.with_ctxt(macsp.ctxt());
+                    make_argument(ecx, sp, ecx.expr_addr_of(sp, arg.expr), ty)
+                })
+                .collect(),
+        )
+    } else {
+        // Generate:
+        //     match (&arg0, &arg1, &arg2) {
+        //         args => &[
+        //             ::core::fmt::ArgumentV1::new_display(args.0),
+        //             ::core::fmt::ArgumentV1::new_lower_hex(args.1),
+        //             ::core::fmt::ArgumentV1::new_debug(args.0),
+        //         ]
+        //     }
+        let args_ident = Ident::new(sym::args, macsp);
+        let args = argmap
+            .iter()
+            .map(|&(arg_index, ty)| {
+                if let Some(arg) = arguments.get(arg_index) {
+                    let sp = arg.expr.span.with_ctxt(macsp.ctxt());
+                    make_argument(
+                        ecx,
+                        sp,
+                        ecx.expr_field(
+                            sp,
+                            ecx.expr_ident(macsp, args_ident),
+                            Ident::new(sym::integer(arg_index), macsp),
+                        ),
+                        ty,
+                    )
+                } else {
+                    DummyResult::raw_expr(macsp, true)
+                }
+            })
+            .collect();
+        ecx.expr_addr_of(
+            macsp,
+            ecx.expr_match(
+                macsp,
+                ecx.expr_tuple(
+                    macsp,
+                    arguments
+                        .into_iter()
+                        .map(|arg| {
+                            ecx.expr_addr_of(arg.expr.span.with_ctxt(macsp.ctxt()), arg.expr)
+                        })
+                        .collect(),
+                ),
+                vec![ecx.arm(macsp, ecx.pat_ident(macsp, args_ident), ecx.expr_array(macsp, args))],
+            ),
+        )
+    };
+
+    if let Some(format_options) = format_options {
+        // Generate:
+        //     ::core::fmt::Arguments::new_v1_formatted(
+        //         lit_pieces,
+        //         args,
+        //         format_options,
+        //         unsafe { ::core::fmt::UnsafeArg::new() }
+        //     )
+        ecx.expr_call_global(
+            macsp,
+            ecx.std_path(&[sym::fmt, sym::Arguments, sym::new_v1_formatted]),
+            vec![
+                lit_pieces,
+                args,
+                format_options,
+                ecx.expr_block(P(ast::Block {
+                    stmts: vec![ecx.stmt_expr(ecx.expr_call_global(
+                        macsp,
+                        ecx.std_path(&[sym::fmt, sym::UnsafeArg, sym::new]),
+                        Vec::new(),
+                    ))],
+                    id: ast::DUMMY_NODE_ID,
+                    rules: BlockCheckMode::Unsafe(UnsafeSource::CompilerGenerated),
+                    span: macsp,
+                    tokens: None,
+                    could_be_bare_literal: false,
+                })),
+            ],
+        )
+    } else {
+        // Generate:
+        //     ::core::fmt::Arguments::new_v1(
+        //         lit_pieces,
+        //         args,
+        //     )
+        ecx.expr_call_global(
+            macsp,
+            ecx.std_path(&[sym::fmt, sym::Arguments, sym::new_v1]),
+            vec![lit_pieces, args],
+        )
+    }
+}
+
+fn may_contain_yield_point(e: &ast::Expr) -> bool {
+    struct MayContainYieldPoint(bool);
+
+    impl Visitor<'_> for MayContainYieldPoint {
+        fn visit_expr(&mut self, e: &ast::Expr) {
+            if let ast::ExprKind::Await(_) | ast::ExprKind::Yield(_) = e.kind {
+                self.0 = true;
+            } else {
+                visit::walk_expr(self, e);
+            }
+        }
+
+        fn visit_mac_call(&mut self, _: &ast::MacCall) {
+            self.0 = true;
+        }
+
+        fn visit_attribute(&mut self, _: &ast::Attribute) {
+            // Conservatively assume this may be a proc macro attribute in
+            // expression position.
+            self.0 = true;
+        }
+
+        fn visit_item(&mut self, _: &ast::Item) {
+            // Do not recurse into nested items.
+        }
+    }
+
+    let mut visitor = MayContainYieldPoint(false);
+    visitor.visit_expr(e);
+    visitor.0
+}
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 8aeb3b82a9c..f058503064b 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -7,9 +7,9 @@
 #![feature(box_patterns)]
 #![feature(decl_macro)]
 #![feature(if_let_guard)]
+#![feature(is_some_with)]
 #![feature(is_sorted)]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(proc_macro_internals)]
 #![feature(proc_macro_quote)]
 #![recursion_limit = "256"]
diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs
index 0b5b6cd55d7..ad108c34992 100644
--- a/compiler/rustc_codegen_cranelift/example/std_example.rs
+++ b/compiler/rustc_codegen_cranelift/example/std_example.rs
@@ -1,4 +1,4 @@
-#![feature(core_intrinsics, generators, generator_trait, is_sorted, bench_black_box)]
+#![feature(core_intrinsics, generators, generator_trait, is_sorted)]
 
 #[cfg(target_arch = "x86_64")]
 use std::arch::x86_64::*;
diff --git a/compiler/rustc_codegen_gcc/tests/run/int.rs b/compiler/rustc_codegen_gcc/tests/run/int.rs
index 2b90e4ae8d8..75779622b54 100644
--- a/compiler/rustc_codegen_gcc/tests/run/int.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/int.rs
@@ -3,7 +3,7 @@
 // Run-time:
 //   status: 0
 
-#![feature(bench_black_box, const_black_box, core_intrinsics, start)]
+#![feature(const_black_box, core_intrinsics, start)]
 
 #![no_std]
 
diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml
index 74115353aaf..a068aa2ec62 100644
--- a/compiler/rustc_codegen_llvm/Cargo.toml
+++ b/compiler/rustc_codegen_llvm/Cargo.toml
@@ -11,7 +11,6 @@ doctest = false
 bitflags = "1.0"
 cstr = "0.2"
 libc = "0.2"
-libloading = "0.7.1"
 measureme = "10.0.0"
 object = { version = "0.29.0", default-features = false, features = ["std", "read_core", "archive", "coff", "elf", "macho", "pe"] }
 tracing = "0.1"
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index a89df00e248..2049422b79a 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -1,8 +1,6 @@
-use crate::back::write::{
-    self, save_temp_bitcode, to_llvm_opt_settings, with_llvm_pmb, DiagnosticHandlers,
-};
-use crate::llvm::{self, build_string, False, True};
-use crate::{llvm_util, LlvmCodegenBackend, ModuleLlvm};
+use crate::back::write::{self, save_temp_bitcode, DiagnosticHandlers};
+use crate::llvm::{self, build_string};
+use crate::{LlvmCodegenBackend, ModuleLlvm};
 use object::read::archive::ArchiveFile;
 use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared};
 use rustc_codegen_ssa::back::symbol_export;
@@ -597,61 +595,9 @@ pub(crate) fn run_pass_manager(
                 1,
             );
         }
-        if llvm_util::should_use_new_llvm_pass_manager(
-            &config.new_llvm_pass_manager,
-            &cgcx.target_arch,
-        ) {
-            let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO };
-            let opt_level = config.opt_level.unwrap_or(config::OptLevel::No);
-            write::optimize_with_new_llvm_pass_manager(
-                cgcx,
-                diag_handler,
-                module,
-                config,
-                opt_level,
-                opt_stage,
-            )?;
-            debug!("lto done");
-            return Ok(());
-        }
-
-        let pm = llvm::LLVMCreatePassManager();
-        llvm::LLVMAddAnalysisPasses(module.module_llvm.tm, pm);
-
-        if config.verify_llvm_ir {
-            let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr().cast());
-            llvm::LLVMRustAddPass(pm, pass.unwrap());
-        }
-
-        let opt_level = config
-            .opt_level
-            .map(|x| to_llvm_opt_settings(x).0)
-            .unwrap_or(llvm::CodeGenOptLevel::None);
-        with_llvm_pmb(module.module_llvm.llmod(), config, opt_level, false, &mut |b| {
-            if thin {
-                llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm);
-            } else {
-                llvm::LLVMRustPassManagerBuilderPopulateLTOPassManager(
-                    b, pm, /* Internalize = */ False, /* RunInliner = */ True,
-                );
-            }
-        });
-
-        // We always generate bitcode through ThinLTOBuffers,
-        // which do not support anonymous globals
-        if config.bitcode_needed() {
-            let pass = llvm::LLVMRustFindAndCreatePass("name-anon-globals\0".as_ptr().cast());
-            llvm::LLVMRustAddPass(pm, pass.unwrap());
-        }
-
-        if config.verify_llvm_ir {
-            let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr().cast());
-            llvm::LLVMRustAddPass(pm, pass.unwrap());
-        }
-
-        llvm::LLVMRunPassManager(pm, module.module_llvm.llmod());
-
-        llvm::LLVMDisposePassManager(pm);
+        let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO };
+        let opt_level = config.opt_level.unwrap_or(config::OptLevel::No);
+        write::llvm_optimize(cgcx, diag_handler, module, config, opt_level, opt_stage)?;
     }
     debug!("lto done");
     Ok(())
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index a695df8409b..db526746fa7 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -21,7 +21,6 @@ use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_errors::{FatalError, Handler, Level};
 use rustc_fs_util::{link_or_copy, path_to_c_string};
-use rustc_middle::bug;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{self, Lto, OutputType, Passes, SplitDwarfKind, SwitchWithOptPath};
 use rustc_session::Session;
@@ -417,7 +416,7 @@ fn get_instr_profile_output_path(config: &ModuleConfig) -> Option<CString> {
     }
 }
 
-pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
+pub(crate) unsafe fn llvm_optimize(
     cgcx: &CodegenContext<LlvmCodegenBackend>,
     diag_handler: &Handler,
     module: &ModuleCodegen<ModuleLlvm>,
@@ -465,7 +464,7 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
     // FIXME: NewPM doesn't provide a facility to pass custom InlineParams.
     // We would have to add upstream support for this first, before we can support
     // config.inline_threshold and our more aggressive default thresholds.
-    let result = llvm::LLVMRustOptimizeWithNewPassManager(
+    let result = llvm::LLVMRustOptimize(
         module.module_llvm.llmod(),
         &*module.module_llvm.tm,
         to_pass_builder_opt_level(opt_level),
@@ -509,18 +508,11 @@ pub(crate) unsafe fn optimize(
 
     let llmod = module.module_llvm.llmod();
     let llcx = &*module.module_llvm.llcx;
-    let tm = &*module.module_llvm.tm;
     let _handlers = DiagnosticHandlers::new(cgcx, diag_handler, llcx);
 
     let module_name = module.name.clone();
     let module_name = Some(&module_name[..]);
 
-    if let Some(false) = config.new_llvm_pass_manager && llvm_util::get_version() >= (15, 0, 0) {
-        diag_handler.warn(
-            "ignoring `-Z new-llvm-pass-manager=no`, which is no longer supported with LLVM 15",
-        );
-    }
-
     if config.emit_no_opt_bc {
         let out = cgcx.output_filenames.temp_path_ext("no-opt.bc", module_name);
         let out = path_to_c_string(&out);
@@ -528,184 +520,17 @@ pub(crate) unsafe fn optimize(
     }
 
     if let Some(opt_level) = config.opt_level {
-        if llvm_util::should_use_new_llvm_pass_manager(
-            &config.new_llvm_pass_manager,
-            &cgcx.target_arch,
-        ) {
-            let opt_stage = match cgcx.lto {
-                Lto::Fat => llvm::OptStage::PreLinkFatLTO,
-                Lto::Thin | Lto::ThinLocal => llvm::OptStage::PreLinkThinLTO,
-                _ if cgcx.opts.cg.linker_plugin_lto.enabled() => llvm::OptStage::PreLinkThinLTO,
-                _ => llvm::OptStage::PreLinkNoLTO,
-            };
-            return optimize_with_new_llvm_pass_manager(
-                cgcx,
-                diag_handler,
-                module,
-                config,
-                opt_level,
-                opt_stage,
-            );
-        }
-
-        if cgcx.prof.llvm_recording_enabled() {
-            diag_handler
-                .warn("`-Z self-profile-events = llvm` requires `-Z new-llvm-pass-manager`");
-        }
-
-        // Create the two optimizing pass managers. These mirror what clang
-        // does, and are by populated by LLVM's default PassManagerBuilder.
-        // Each manager has a different set of passes, but they also share
-        // some common passes.
-        let fpm = llvm::LLVMCreateFunctionPassManagerForModule(llmod);
-        let mpm = llvm::LLVMCreatePassManager();
-
-        {
-            let find_pass = |pass_name: &str| {
-                let pass_name = SmallCStr::new(pass_name);
-                llvm::LLVMRustFindAndCreatePass(pass_name.as_ptr())
-            };
-
-            if config.verify_llvm_ir {
-                // Verification should run as the very first pass.
-                llvm::LLVMRustAddPass(fpm, find_pass("verify").unwrap());
-            }
-
-            let mut extra_passes = Vec::new();
-            let mut have_name_anon_globals_pass = false;
-
-            for pass_name in &config.passes {
-                if pass_name == "lint" {
-                    // Linting should also be performed early, directly on the generated IR.
-                    llvm::LLVMRustAddPass(fpm, find_pass("lint").unwrap());
-                    continue;
-                }
-
-                if let Some(pass) = find_pass(pass_name) {
-                    extra_passes.push(pass);
-                } else {
-                    diag_handler.warn(&format!("unknown pass `{}`, ignoring", pass_name));
-                }
-
-                if pass_name == "name-anon-globals" {
-                    have_name_anon_globals_pass = true;
-                }
-            }
-
-            // Instrumentation must be inserted before optimization,
-            // otherwise LLVM may optimize some functions away which
-            // breaks llvm-cov.
-            //
-            // This mirrors what Clang does in lib/CodeGen/BackendUtil.cpp.
-            if config.instrument_gcov {
-                llvm::LLVMRustAddPass(mpm, find_pass("insert-gcov-profiling").unwrap());
-            }
-            if config.instrument_coverage {
-                llvm::LLVMRustAddPass(mpm, find_pass("instrprof").unwrap());
-            }
-            if config.debug_info_for_profiling {
-                llvm::LLVMRustAddPass(mpm, find_pass("add-discriminators").unwrap());
-            }
-
-            add_sanitizer_passes(config, &mut extra_passes);
-
-            // Some options cause LLVM bitcode to be emitted, which uses ThinLTOBuffers, so we need
-            // to make sure we run LLVM's NameAnonGlobals pass when emitting bitcode; otherwise
-            // we'll get errors in LLVM.
-            let using_thin_buffers = config.bitcode_needed();
-            if !config.no_prepopulate_passes {
-                llvm::LLVMAddAnalysisPasses(tm, fpm);
-                llvm::LLVMAddAnalysisPasses(tm, mpm);
-                let opt_level = to_llvm_opt_settings(opt_level).0;
-                let prepare_for_thin_lto = cgcx.lto == Lto::Thin
-                    || cgcx.lto == Lto::ThinLocal
-                    || (cgcx.lto != Lto::Fat && cgcx.opts.cg.linker_plugin_lto.enabled());
-                with_llvm_pmb(llmod, config, opt_level, prepare_for_thin_lto, &mut |b| {
-                    llvm::LLVMRustAddLastExtensionPasses(
-                        b,
-                        extra_passes.as_ptr(),
-                        extra_passes.len() as size_t,
-                    );
-                    llvm::LLVMRustPassManagerBuilderPopulateFunctionPassManager(b, fpm);
-                    llvm::LLVMRustPassManagerBuilderPopulateModulePassManager(b, mpm);
-                });
-
-                have_name_anon_globals_pass = have_name_anon_globals_pass || prepare_for_thin_lto;
-                if using_thin_buffers && !prepare_for_thin_lto {
-                    llvm::LLVMRustAddPass(mpm, find_pass("name-anon-globals").unwrap());
-                    have_name_anon_globals_pass = true;
-                }
-            } else {
-                // If we don't use the standard pipeline, directly populate the MPM
-                // with the extra passes.
-                for pass in extra_passes {
-                    llvm::LLVMRustAddPass(mpm, pass);
-                }
-            }
-
-            if using_thin_buffers && !have_name_anon_globals_pass {
-                // As described above, this will probably cause an error in LLVM
-                if config.no_prepopulate_passes {
-                    diag_handler.err(
-                        "The current compilation is going to use thin LTO buffers \
-                                      without running LLVM's NameAnonGlobals pass. \
-                                      This will likely cause errors in LLVM. Consider adding \
-                                      -C passes=name-anon-globals to the compiler command line.",
-                    );
-                } else {
-                    bug!(
-                        "We are using thin LTO buffers without running the NameAnonGlobals pass. \
-                          This will likely cause errors in LLVM and should never happen."
-                    );
-                }
-            }
-        }
-
-        diag_handler.abort_if_errors();
-
-        // Finally, run the actual optimization passes
-        {
-            let _timer = cgcx.prof.extra_verbose_generic_activity(
-                "LLVM_module_optimize_function_passes",
-                &*module.name,
-            );
-            llvm::LLVMRustRunFunctionPassManager(fpm, llmod);
-        }
-        {
-            let _timer = cgcx.prof.extra_verbose_generic_activity(
-                "LLVM_module_optimize_module_passes",
-                &*module.name,
-            );
-            llvm::LLVMRunPassManager(mpm, llmod);
-        }
-
-        // Deallocate managers that we're now done with
-        llvm::LLVMDisposePassManager(fpm);
-        llvm::LLVMDisposePassManager(mpm);
+        let opt_stage = match cgcx.lto {
+            Lto::Fat => llvm::OptStage::PreLinkFatLTO,
+            Lto::Thin | Lto::ThinLocal => llvm::OptStage::PreLinkThinLTO,
+            _ if cgcx.opts.cg.linker_plugin_lto.enabled() => llvm::OptStage::PreLinkThinLTO,
+            _ => llvm::OptStage::PreLinkNoLTO,
+        };
+        return llvm_optimize(cgcx, diag_handler, module, config, opt_level, opt_stage);
     }
     Ok(())
 }
 
-unsafe fn add_sanitizer_passes(config: &ModuleConfig, passes: &mut Vec<&'static mut llvm::Pass>) {
-    if config.sanitizer.contains(SanitizerSet::ADDRESS) {
-        let recover = config.sanitizer_recover.contains(SanitizerSet::ADDRESS);
-        passes.push(llvm::LLVMRustCreateAddressSanitizerFunctionPass(recover));
-        passes.push(llvm::LLVMRustCreateModuleAddressSanitizerPass(recover));
-    }
-    if config.sanitizer.contains(SanitizerSet::MEMORY) {
-        let track_origins = config.sanitizer_memory_track_origins as c_int;
-        let recover = config.sanitizer_recover.contains(SanitizerSet::MEMORY);
-        passes.push(llvm::LLVMRustCreateMemorySanitizerPass(track_origins, recover));
-    }
-    if config.sanitizer.contains(SanitizerSet::THREAD) {
-        passes.push(llvm::LLVMRustCreateThreadSanitizerPass());
-    }
-    if config.sanitizer.contains(SanitizerSet::HWADDRESS) {
-        let recover = config.sanitizer_recover.contains(SanitizerSet::HWADDRESS);
-        passes.push(llvm::LLVMRustCreateHWAddressSanitizerPass(recover));
-    }
-}
-
 pub(crate) fn link(
     cgcx: &CodegenContext<LlvmCodegenBackend>,
     diag_handler: &Handler,
@@ -1072,72 +897,6 @@ unsafe fn embed_bitcode(
     }
 }
 
-pub unsafe fn with_llvm_pmb(
-    llmod: &llvm::Module,
-    config: &ModuleConfig,
-    opt_level: llvm::CodeGenOptLevel,
-    prepare_for_thin_lto: bool,
-    f: &mut dyn FnMut(&llvm::PassManagerBuilder),
-) {
-    use std::ptr;
-
-    // Create the PassManagerBuilder for LLVM. We configure it with
-    // reasonable defaults and prepare it to actually populate the pass
-    // manager.
-    let builder = llvm::LLVMRustPassManagerBuilderCreate();
-    let opt_size = config.opt_size.map_or(llvm::CodeGenOptSizeNone, |x| to_llvm_opt_settings(x).1);
-    let inline_threshold = config.inline_threshold;
-    let pgo_gen_path = get_pgo_gen_path(config);
-    let pgo_use_path = get_pgo_use_path(config);
-    let pgo_sample_use_path = get_pgo_sample_use_path(config);
-
-    llvm::LLVMRustConfigurePassManagerBuilder(
-        builder,
-        opt_level,
-        config.merge_functions,
-        config.vectorize_slp,
-        config.vectorize_loop,
-        prepare_for_thin_lto,
-        pgo_gen_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
-        pgo_use_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
-        pgo_sample_use_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
-        opt_size as c_int,
-    );
-
-    llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, config.no_builtins);
-
-    // Here we match what clang does (kinda). For O0 we only inline
-    // always-inline functions (but don't add lifetime intrinsics), at O1 we
-    // inline with lifetime intrinsics, and O2+ we add an inliner with a
-    // thresholds copied from clang.
-    match (opt_level, opt_size, inline_threshold) {
-        (.., Some(t)) => {
-            llvm::LLVMRustPassManagerBuilderUseInlinerWithThreshold(builder, t);
-        }
-        (llvm::CodeGenOptLevel::Aggressive, ..) => {
-            llvm::LLVMRustPassManagerBuilderUseInlinerWithThreshold(builder, 275);
-        }
-        (_, llvm::CodeGenOptSizeDefault, _) => {
-            llvm::LLVMRustPassManagerBuilderUseInlinerWithThreshold(builder, 75);
-        }
-        (_, llvm::CodeGenOptSizeAggressive, _) => {
-            llvm::LLVMRustPassManagerBuilderUseInlinerWithThreshold(builder, 25);
-        }
-        (llvm::CodeGenOptLevel::None, ..) => {
-            llvm::LLVMRustAddAlwaysInlinePass(builder, config.emit_lifetime_markers);
-        }
-        (llvm::CodeGenOptLevel::Less, ..) => {
-            llvm::LLVMRustAddAlwaysInlinePass(builder, config.emit_lifetime_markers);
-        }
-        (llvm::CodeGenOptLevel::Default, ..) => {
-            llvm::LLVMRustPassManagerBuilderUseInlinerWithThreshold(builder, 225);
-        }
-    }
-
-    f(builder);
-    llvm::LLVMRustPassManagerBuilderDispose(builder);
-}
-
 // Create a `__imp_<symbol> = &symbol` global for every public static `symbol`.
 // This is required to satisfy `dllimport` references to static data in .rlibs
 // when using MSVC linker.  We do this only for data, as linker can fix up
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index a559f7f3d57..ee2fc65e37b 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -552,7 +552,7 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
                 // `#[used(compiler)]` is explicitly requested. This is to avoid similar breakage
                 // on other targets, in particular MachO targets have *their* static constructor
                 // lists broken if `llvm.compiler.used` is emitted rather than llvm.used. However,
-                // that check happens when assigning the `CodegenFnAttrFlags` in `rustc_typeck`,
+                // that check happens when assigning the `CodegenFnAttrFlags` in `rustc_hir_analysis`,
                 // so we don't need to take care of it here.
                 self.add_compiler_used_global(g);
             }
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 42c65e04e3b..15bfa843046 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -7,7 +7,6 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(hash_raw_entry)]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(extern_types)]
 #![feature(once_cell)]
 #![feature(iter_intersperse)]
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 09f2c356897..42cb694c0e7 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -1792,18 +1792,9 @@ extern "C" {
     /// Writes a module to the specified path. Returns 0 on success.
     pub fn LLVMWriteBitcodeToFile(M: &Module, Path: *const c_char) -> c_int;
 
-    /// Creates a pass manager.
+    /// Creates a legacy pass manager -- only used for final codegen.
     pub fn LLVMCreatePassManager<'a>() -> &'a mut PassManager<'a>;
 
-    /// Creates a function-by-function pass manager
-    pub fn LLVMCreateFunctionPassManagerForModule(M: &Module) -> &mut PassManager<'_>;
-
-    /// Disposes a pass manager.
-    pub fn LLVMDisposePassManager<'a>(PM: &'a mut PassManager<'a>);
-
-    /// Runs a pass manager on a module.
-    pub fn LLVMRunPassManager<'a>(PM: &PassManager<'a>, M: &'a Module) -> Bool;
-
     pub fn LLVMInitializePasses();
 
     pub fn LLVMTimeTraceProfilerInitialize();
@@ -1814,32 +1805,6 @@ extern "C" {
 
     pub fn LLVMAddAnalysisPasses<'a>(T: &'a TargetMachine, PM: &PassManager<'a>);
 
-    pub fn LLVMRustPassManagerBuilderCreate() -> &'static mut PassManagerBuilder;
-    pub fn LLVMRustPassManagerBuilderDispose(PMB: &'static mut PassManagerBuilder);
-    pub fn LLVMRustPassManagerBuilderUseInlinerWithThreshold(
-        PMB: &PassManagerBuilder,
-        threshold: c_uint,
-    );
-    pub fn LLVMRustPassManagerBuilderPopulateModulePassManager(
-        PMB: &PassManagerBuilder,
-        PM: &PassManager<'_>,
-    );
-
-    pub fn LLVMRustPassManagerBuilderPopulateFunctionPassManager(
-        PMB: &PassManagerBuilder,
-        PM: &PassManager<'_>,
-    );
-    pub fn LLVMRustPassManagerBuilderPopulateLTOPassManager(
-        PMB: &PassManagerBuilder,
-        PM: &PassManager<'_>,
-        Internalize: Bool,
-        RunInliner: Bool,
-    );
-    pub fn LLVMRustPassManagerBuilderPopulateThinLTOPassManager(
-        PMB: &PassManagerBuilder,
-        PM: &PassManager<'_>,
-    );
-
     pub fn LLVMGetHostCPUFeatures() -> *mut c_char;
 
     pub fn LLVMDisposeMessage(message: *mut c_char);
@@ -2244,22 +2209,6 @@ extern "C" {
 
     pub fn LLVMIsAConstantInt(value_ref: &Value) -> Option<&ConstantInt>;
 
-    pub fn LLVMRustFindAndCreatePass(Pass: *const c_char) -> Option<&'static mut Pass>;
-    pub fn LLVMRustCreateAddressSanitizerFunctionPass(Recover: bool) -> &'static mut Pass;
-    pub fn LLVMRustCreateModuleAddressSanitizerPass(Recover: bool) -> &'static mut Pass;
-    pub fn LLVMRustCreateMemorySanitizerPass(
-        TrackOrigins: c_int,
-        Recover: bool,
-    ) -> &'static mut Pass;
-    pub fn LLVMRustCreateThreadSanitizerPass() -> &'static mut Pass;
-    pub fn LLVMRustCreateHWAddressSanitizerPass(Recover: bool) -> &'static mut Pass;
-    pub fn LLVMRustAddPass(PM: &PassManager<'_>, Pass: &'static mut Pass);
-    pub fn LLVMRustAddLastExtensionPasses(
-        PMB: &PassManagerBuilder,
-        Passes: *const &'static mut Pass,
-        NumPasses: size_t,
-    );
-
     pub fn LLVMRustHasFeature(T: &TargetMachine, s: *const c_char) -> bool;
 
     pub fn LLVMRustPrintTargetCPUs(T: &TargetMachine);
@@ -2293,29 +2242,11 @@ extern "C" {
         SplitDwarfFile: *const c_char,
     ) -> Option<&'static mut TargetMachine>;
     pub fn LLVMRustDisposeTargetMachine(T: &'static mut TargetMachine);
-    pub fn LLVMRustAddBuilderLibraryInfo<'a>(
-        PMB: &'a PassManagerBuilder,
-        M: &'a Module,
-        DisableSimplifyLibCalls: bool,
-    );
-    pub fn LLVMRustConfigurePassManagerBuilder(
-        PMB: &PassManagerBuilder,
-        OptLevel: CodeGenOptLevel,
-        MergeFunctions: bool,
-        SLPVectorize: bool,
-        LoopVectorize: bool,
-        PrepareForThinLTO: bool,
-        PGOGenPath: *const c_char,
-        PGOUsePath: *const c_char,
-        PGOSampleUsePath: *const c_char,
-        SizeLevel: c_int,
-    );
     pub fn LLVMRustAddLibraryInfo<'a>(
         PM: &PassManager<'a>,
         M: &'a Module,
         DisableSimplifyLibCalls: bool,
     );
-    pub fn LLVMRustRunFunctionPassManager<'a>(PM: &PassManager<'a>, M: &'a Module);
     pub fn LLVMRustWriteOutputFile<'a>(
         T: &'a TargetMachine,
         PM: &PassManager<'a>,
@@ -2324,7 +2255,7 @@ extern "C" {
         DwoOutput: *const c_char,
         FileType: FileType,
     ) -> LLVMRustResult;
-    pub fn LLVMRustOptimizeWithNewPassManager<'a>(
+    pub fn LLVMRustOptimize<'a>(
         M: &'a Module,
         TM: &'a TargetMachine,
         OptLevel: PassBuilderOptLevel,
@@ -2362,7 +2293,6 @@ extern "C" {
     pub fn LLVMRustSetLLVMOptions(Argc: c_int, Argv: *const *const c_char);
     pub fn LLVMRustPrintPasses();
     pub fn LLVMRustSetNormalizedTarget(M: &Module, triple: *const c_char);
-    pub fn LLVMRustAddAlwaysInlinePass(P: &PassManagerBuilder, AddLifetimes: bool);
     pub fn LLVMRustRunRestrictionPass(M: &Module, syms: *const *const c_char, len: size_t);
 
     pub fn LLVMRustOpenArchive(path: *const c_char) -> Option<&'static mut Archive>;
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 60707a1c34e..2fd58567c48 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -1,7 +1,6 @@
 use crate::back::write::create_informational_target_machine;
-use crate::{llvm, llvm_util};
+use crate::llvm;
 use libc::c_int;
-use libloading::Library;
 use rustc_codegen_ssa::target_features::{
     supported_target_features, tied_target_features, RUSTC_SPECIFIC_FEATURES,
 };
@@ -16,7 +15,6 @@ use rustc_target::spec::{MergeFunctions, PanicStrategy};
 use smallvec::{smallvec, SmallVec};
 use std::ffi::{CStr, CString};
 
-use std::mem;
 use std::path::Path;
 use std::ptr;
 use std::slice;
@@ -120,22 +118,6 @@ unsafe fn configure_llvm(sess: &Session) {
 
     llvm::LLVMInitializePasses();
 
-    // Use the legacy plugin registration if we don't use the new pass manager
-    if !should_use_new_llvm_pass_manager(
-        &sess.opts.unstable_opts.new_llvm_pass_manager,
-        &sess.target.arch,
-    ) {
-        // Register LLVM plugins by loading them into the compiler process.
-        for plugin in &sess.opts.unstable_opts.llvm_plugins {
-            let lib = Library::new(plugin).unwrap_or_else(|e| bug!("couldn't load plugin: {}", e));
-            debug!("LLVM plugin loaded successfully {:?} ({})", lib, plugin);
-
-            // Intentionally leak the dynamic library. We can't ever unload it
-            // since the library can make things that will live arbitrarily long.
-            mem::forget(lib);
-        }
-    }
-
     rustc_llvm::initialize_available_targets();
 
     llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, llvm_args.as_ptr());
@@ -539,19 +521,3 @@ pub fn tune_cpu(sess: &Session) -> Option<&str> {
     let name = sess.opts.unstable_opts.tune_cpu.as_ref()?;
     Some(handle_native(name))
 }
-
-pub(crate) fn should_use_new_llvm_pass_manager(user_opt: &Option<bool>, target_arch: &str) -> bool {
-    // The new pass manager is enabled by default for LLVM >= 13.
-    // This matches Clang, which also enables it since Clang 13.
-
-    // Since LLVM 15, the legacy pass manager is no longer supported.
-    if llvm_util::get_version() >= (15, 0, 0) {
-        return true;
-    }
-
-    // There are some perf issues with the new pass manager when targeting
-    // s390x with LLVM 13, so enable the new pass manager only with LLVM 14.
-    // See https://github.com/rust-lang/rust/issues/89609.
-    let min_version = if target_arch == "s390x" { 14 } else { 13 };
-    user_opt.unwrap_or_else(|| llvm_util::get_version() >= (min_version, 0, 0))
-}
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index e0bd7a33f73..f59a753a5ce 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -1180,18 +1180,12 @@ impl<'a> WasmLd<'a> {
         //   sharing memory and instantiating the module multiple times. As a
         //   result if it were exported then we'd just have no sharing.
         //
-        // * `--export=__wasm_init_memory` - when using `--passive-segments` the
-        //   linker will synthesize this function, and so we need to make sure
-        //   that our usage of `--export` below won't accidentally cause this
-        //   function to get deleted.
-        //
         // * `--export=*tls*` - when `#[thread_local]` symbols are used these
         //   symbols are how the TLS segments are initialized and configured.
         if sess.target_features.contains(&sym::atomics) {
             cmd.arg("--shared-memory");
             cmd.arg("--max-memory=1073741824");
             cmd.arg("--import-memory");
-            cmd.arg("--export=__wasm_init_memory");
             cmd.arg("--export=__wasm_init_tls");
             cmd.arg("--export=__tls_size");
             cmd.arg("--export=__tls_align");
@@ -1320,10 +1314,12 @@ impl<'a> Linker for WasmLd<'a> {
 
         // LLD will hide these otherwise-internal symbols since it only exports
         // symbols explicitly passed via the `--export` flags above and hides all
-        // others. Various bits and pieces of tooling use this, so be sure these
-        // symbols make their way out of the linker as well.
-        self.cmd.arg("--export=__heap_base");
-        self.cmd.arg("--export=__data_end");
+        // others. Various bits and pieces of wasm32-unknown-unknown tooling use
+        // this, so be sure these symbols make their way out of the linker as well.
+        if self.sess.target.os == "unknown" {
+            self.cmd.arg("--export=__heap_base");
+            self.cmd.arg("--export=__data_end");
+        }
     }
 
     fn subsystem(&mut self, _subsystem: &str) {}
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 68f3b19b715..680b9b642d9 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -113,7 +113,6 @@ pub struct ModuleConfig {
     pub vectorize_slp: bool,
     pub merge_functions: bool,
     pub inline_threshold: Option<u32>,
-    pub new_llvm_pass_manager: Option<bool>,
     pub emit_lifetime_markers: bool,
     pub llvm_plugins: Vec<String>,
 }
@@ -265,7 +264,6 @@ impl ModuleConfig {
             },
 
             inline_threshold: sess.opts.cg.inline_threshold,
-            new_llvm_pass_manager: sess.opts.unstable_opts.new_llvm_pass_manager,
             emit_lifetime_markers: sess.emit_lifetime_markers(),
             llvm_plugins: if_regular!(sess.opts.unstable_opts.llvm_plugins.clone(), vec![]),
         }
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index e736b2aba9c..3ef9a634e18 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -1,7 +1,6 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(box_patterns)]
 #![feature(try_blocks)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(once_cell)]
 #![feature(associated_type_bounds)]
 #![feature(strict_provenance)]
diff --git a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs
index 7755e67938c..450672fb941 100644
--- a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs
@@ -5,7 +5,7 @@ use rustc_span::Span;
 use rustc_target::abi::call::FnAbi;
 
 pub trait IntrinsicCallMethods<'tcx>: BackendTypes {
-    /// Remember to add all intrinsics here, in `compiler/rustc_typeck/src/check/mod.rs`,
+    /// Remember to add all intrinsics here, in `compiler/rustc_hir_analysis/src/check/mod.rs`,
     /// and in `library/core/src/intrinsics.rs`; if you need access to any LLVM intrinsics,
     /// add them to `compiler/rustc_codegen_llvm/src/context.rs`.
     fn codegen_intrinsic_call(
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index dc5305aabcf..510adde6296 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -784,7 +784,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 }
 
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64", not(bootstrap)))]
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index bc1aa43b73a..7a01b85381a 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -890,8 +890,6 @@ mod size_asserts {
     static_assert_size!(MemPlaceMeta, 24);
     static_assert_size!(MemPlace, 40);
     static_assert_size!(MPlaceTy<'_>, 64);
-    #[cfg(not(bootstrap))]
     static_assert_size!(Place, 40);
-    #[cfg(not(bootstrap))]
     static_assert_size!(PlaceTy<'_>, 64);
 }
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index 9f47d302a0c..7c4c7db1035 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -10,7 +10,6 @@ Rust MIR: a lowered representation of Rust.
 #![feature(decl_macro)]
 #![feature(exact_size_is_empty)]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(map_try_insert)]
 #![feature(min_specialization)]
 #![feature(slice_ptr_get)]
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index fb35399fa3a..b0dcbf76b01 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -1009,7 +1009,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
 
                 if needs_non_const_drop {
                     self.check_op_spanned(
-                        ops::LiveDrop { dropped_at: Some(terminator.source_info.span) },
+                        ops::LiveDrop {
+                            dropped_at: Some(terminator.source_info.span),
+                            dropped_ty: ty_of_dropped_place,
+                        },
                         err_span,
                     );
                 }
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
index 5fb4bf638b3..b56b230201e 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -422,10 +422,11 @@ impl<'tcx> NonConstOp<'tcx> for InlineAsm {
 }
 
 #[derive(Debug)]
-pub struct LiveDrop {
+pub struct LiveDrop<'tcx> {
     pub dropped_at: Option<Span>,
+    pub dropped_ty: Ty<'tcx>,
 }
-impl<'tcx> NonConstOp<'tcx> for LiveDrop {
+impl<'tcx> NonConstOp<'tcx> for LiveDrop<'tcx> {
     fn build_error(
         &self,
         ccx: &ConstCx<'_, 'tcx>,
@@ -435,9 +436,13 @@ impl<'tcx> NonConstOp<'tcx> for LiveDrop {
             ccx.tcx.sess,
             span,
             E0493,
-            "destructors cannot be evaluated at compile-time"
+            "destructor of `{}` cannot be evaluated at compile-time",
+            self.dropped_ty,
+        );
+        err.span_label(
+            span,
+            format!("the destructor for this type cannot be evaluated in {}s", ccx.const_kind()),
         );
-        err.span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind()));
         if let Some(span) = self.dropped_at {
             err.span_label(span, "value is dropped here");
         }
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs
index 4e210f66353..d4570c59889 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs
@@ -1,6 +1,6 @@
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::{self, BasicBlock, Location};
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_span::{symbol::sym, Span};
 
 use super::check::Qualifs;
@@ -58,9 +58,9 @@ impl<'mir, 'tcx> std::ops::Deref for CheckLiveDrops<'mir, 'tcx> {
     }
 }
 
-impl CheckLiveDrops<'_, '_> {
-    fn check_live_drop(&self, span: Span) {
-        ops::LiveDrop { dropped_at: None }.build_error(self.ccx, span).emit();
+impl<'tcx> CheckLiveDrops<'_, 'tcx> {
+    fn check_live_drop(&self, span: Span, dropped_ty: Ty<'tcx>) {
+        ops::LiveDrop { dropped_at: None, dropped_ty }.build_error(self.ccx, span).emit();
     }
 }
 
@@ -90,7 +90,7 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
                 }
 
                 if dropped_place.is_indirect() {
-                    self.check_live_drop(terminator.source_info.span);
+                    self.check_live_drop(terminator.source_info.span, dropped_ty);
                     return;
                 }
 
@@ -101,7 +101,7 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
                 if self.qualifs.needs_non_const_drop(self.ccx, dropped_place.local, location) {
                     // Use the span where the dropped local was declared for the error.
                     let span = self.body.local_decls[dropped_place.local].source_info.span;
-                    self.check_live_drop(span);
+                    self.check_live_drop(span, dropped_ty);
                 }
             }
 
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 56f7823efe0..467ac401d08 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -13,7 +13,6 @@
 #![feature(cell_leak)]
 #![feature(control_flow_enum)]
 #![feature(extend_one)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(hash_raw_entry)]
 #![feature(hasher_prefixfree_extras)]
 #![feature(maybe_uninit_uninit_array)]
diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml
index d1d02ed73f9..59e93777748 100644
--- a/compiler/rustc_driver/Cargo.toml
+++ b/compiler/rustc_driver/Cargo.toml
@@ -30,7 +30,7 @@ rustc_error_codes = { path = "../rustc_error_codes" }
 rustc_interface = { path = "../rustc_interface" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_span = { path = "../rustc_span" }
-rustc_typeck = { path = "../rustc_typeck" }
+rustc_hir_analysis = { path = "../rustc_hir_analysis" }
 
 [target.'cfg(unix)'.dependencies]
 libc = "0.2"
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index c768935eb62..fcd49f5d015 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -5,7 +5,6 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(once_cell)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs
index 2874fa0caff..f9b1316d2eb 100644
--- a/compiler/rustc_driver/src/pretty.rs
+++ b/compiler/rustc_driver/src/pretty.rs
@@ -329,7 +329,7 @@ impl<'tcx> pprust_hir::PpAnn for TypedAnnotation<'tcx> {
             let typeck_results = self.maybe_typeck_results.get().or_else(|| {
                 self.tcx
                     .hir()
-                    .maybe_body_owned_by(expr.hir_id.owner)
+                    .maybe_body_owned_by(expr.hir_id.owner.def_id)
                     .map(|body_id| self.tcx.typeck_body(body_id))
             });
 
@@ -502,7 +502,7 @@ fn print_with_analysis(
 
         ThirTree => {
             let mut out = String::new();
-            abort_on_err(rustc_typeck::check_crate(tcx), tcx.sess);
+            abort_on_err(rustc_hir_analysis::check_crate(tcx), tcx.sess);
             debug!("pretty printing THIR tree");
             for did in tcx.hir().body_owners() {
                 let _ = writeln!(
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index 854625579ee..1e86d159668 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -159,6 +159,7 @@ E0307: include_str!("./error_codes/E0307.md"),
 E0308: include_str!("./error_codes/E0308.md"),
 E0309: include_str!("./error_codes/E0309.md"),
 E0310: include_str!("./error_codes/E0310.md"),
+E0311: include_str!("./error_codes/E0311.md"),
 E0312: include_str!("./error_codes/E0312.md"),
 E0316: include_str!("./error_codes/E0316.md"),
 E0317: include_str!("./error_codes/E0317.md"),
@@ -568,7 +569,6 @@ E0790: include_str!("./error_codes/E0790.md"),
 //  E0300, // unexpanded macro
 //  E0304, // expected signed integer constant
 //  E0305, // expected constant
-    E0311, // thing may not live long enough
     E0313, // lifetime of borrowed pointer outlives lifetime of captured
            // variable
 //  E0314, // closure outlives stack frame
diff --git a/compiler/rustc_error_codes/src/error_codes/E0094.md b/compiler/rustc_error_codes/src/error_codes/E0094.md
index ec86ec44ece..cc546bdbb3b 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0094.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0094.md
@@ -6,6 +6,7 @@ Erroneous code example:
 #![feature(intrinsics)]
 
 extern "rust-intrinsic" {
+    #[rustc_safe_intrinsic]
     fn size_of<T, U>() -> usize; // error: intrinsic has wrong number
                                  //        of type parameters
 }
@@ -19,6 +20,7 @@ Example:
 #![feature(intrinsics)]
 
 extern "rust-intrinsic" {
+    #[rustc_safe_intrinsic]
     fn size_of<T>() -> usize; // ok!
 }
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0211.md b/compiler/rustc_error_codes/src/error_codes/E0211.md
index 77289f01900..8c2462ebd9b 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0211.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0211.md
@@ -7,6 +7,7 @@ used. Erroneous code examples:
 #![feature(intrinsics)]
 
 extern "rust-intrinsic" {
+    #[rustc_safe_intrinsic]
     fn size_of<T>(); // error: intrinsic has wrong type
 }
 
@@ -42,6 +43,7 @@ For the first code example, please check the function definition. Example:
 #![feature(intrinsics)]
 
 extern "rust-intrinsic" {
+    #[rustc_safe_intrinsic]
     fn size_of<T>() -> usize; // ok!
 }
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0311.md b/compiler/rustc_error_codes/src/error_codes/E0311.md
new file mode 100644
index 00000000000..08159d3f469
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0311.md
@@ -0,0 +1,42 @@
+This error occurs when there is an unsatisfied outlives bound involving an
+elided region and a generic type parameter or associated type.
+
+Erroneous code example:
+
+```compile_fail,E0311
+fn no_restriction<T>(x: &()) -> &() {
+    with_restriction::<T>(x)
+}
+
+fn with_restriction<'a, T: 'a>(x: &'a ()) -> &'a () {
+    x
+}
+```
+
+Why doesn't this code compile? It helps to look at the lifetime bounds that are
+automatically added by the compiler. For more details see the documentation for
+[lifetime elision]( https://doc.rust-lang.org/reference/lifetime-elision.html).
+
+The compiler elides the lifetime of `x` and the return type to some arbitrary
+lifetime `'anon` in `no_restriction()`. The only information available to the
+compiler is that `'anon` is valid for the duration of the function. When
+calling `with_restriction()`, the compiler requires the completely unrelated
+type parameter `T` to outlive `'anon` because of the `T: 'a` bound in
+`with_restriction()`. This causes an error because `T` is not required to
+outlive `'anon` in `no_restriction()`.
+
+If `no_restriction()` were to use `&T` instead of `&()` as an argument, the
+compiler would have added an implied bound, causing this to compile.
+
+This error can be resolved by explicitly naming the elided lifetime for `x` and
+then explicily requiring that the generic parameter `T` outlives that lifetime:
+
+```
+fn no_restriction<'a, T: 'a>(x: &'a ()) -> &'a () {
+    with_restriction::<T>(x)
+}
+
+fn with_restriction<'a, T: 'a>(x: &'a ()) -> &'a () {
+    x
+}
+```
diff --git a/compiler/rustc_error_messages/locales/en-US/parser.ftl b/compiler/rustc_error_messages/locales/en-US/parser.ftl
index 9459cfebde9..13c368d1c58 100644
--- a/compiler/rustc_error_messages/locales/en-US/parser.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/parser.ftl
@@ -71,6 +71,8 @@ parser_field_expression_with_generic = field expressions cannot have generic arg
 parser_macro_invocation_with_qualified_path = macros cannot use qualified paths
 
 parser_unexpected_token_after_label = expected `while`, `for`, `loop` or `{"{"}` after a label
+    .suggestion_remove_label = consider removing the label
+    .suggestion_enclose_in_block = consider enclosing expression in a block
 
 parser_require_colon_after_labeled_expression = labeled expression must be followed by `:`
     .note = labels are used before loops and blocks, allowing e.g., `break 'label` to them
@@ -158,3 +160,212 @@ parser_remove_let = expected pattern, found `let`
 
 parser_use_eq_instead = unexpected `==`
     .suggestion = try using `=` instead
+
+parser_use_empty_block_not_semi = expected { "`{}`" }, found `;`
+    .suggestion = try using { "`{}`" } instead
+
+parser_comparison_interpreted_as_generic =
+    `<` is interpreted as a start of generic arguments for `{$type}`, not a comparison
+    .label_args = interpreted as generic arguments
+    .label_comparison = not interpreted as comparison
+    .suggestion = try comparing the cast value
+
+parser_shift_interpreted_as_generic =
+    `<<` is interpreted as a start of generic arguments for `{$type}`, not a shift
+    .label_args = interpreted as generic arguments
+    .label_comparison = not interpreted as shift
+    .suggestion = try shifting the cast value
+
+parser_found_expr_would_be_stmt = expected expression, found `{$token}`
+    .label = expected expression
+
+parser_leading_plus_not_supported = leading `+` is not supported
+    .label = unexpected `+`
+    .suggestion_remove_plus = try removing the `+`
+
+parser_parentheses_with_struct_fields = invalid `struct` delimiters or `fn` call arguments
+    .suggestion_braces_for_struct = if `{$type}` is a struct, use braces as delimiters
+    .suggestion_no_fields_for_fn = if `{$type}` is a function, use the arguments directly
+
+parser_labeled_loop_in_break = parentheses are required around this expression to avoid confusion with a labeled break expression
+
+parser_sugg_wrap_expression_in_parentheses = wrap the expression in parentheses
+
+parser_array_brackets_instead_of_braces = this is a block expression, not an array
+    .suggestion = to make an array, use square brackets instead of curly braces
+
+parser_match_arm_body_without_braces = `match` arm body without braces
+    .label_statements = {$num_statements ->
+            [one] this statement is not surrounded by a body
+           *[other] these statements are not surrounded by a body
+        }
+    .label_arrow = while parsing the `match` arm starting here
+    .suggestion_add_braces = surround the {$num_statements ->
+            [one] statement
+           *[other] statements
+        } with a body
+    .suggestion_use_comma_not_semicolon = use a comma to end a `match` arm expression
+
+parser_struct_literal_not_allowed_here = struct literals are not allowed here
+    .suggestion = surround the struct literal with parentheses
+
+parser_invalid_interpolated_expression = invalid interpolated expression
+
+parser_hexadecimal_float_literal_not_supported = hexadecimal float literal is not supported
+parser_octal_float_literal_not_supported = octal float literal is not supported
+parser_binary_float_literal_not_supported = binary float literal is not supported
+parser_not_supported = not supported
+
+parser_invalid_literal_suffix = suffixes on {$kind} literals are invalid
+    .label = invalid suffix `{$suffix}`
+
+parser_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are invalid
+    .label = invalid suffix `{$suffix}`
+    .tuple_exception_line_1 = `{$suffix}` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases
+    .tuple_exception_line_2 = on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access
+    .tuple_exception_line_3 = see issue #60210 <https://github.com/rust-lang/rust/issues/60210> for more information
+
+parser_non_string_abi_literal = non-string ABI literal
+    .suggestion = specify the ABI with a string literal
+
+parser_mismatched_closing_delimiter = mismatched closing delimiter: `{$delimiter}`
+    .label_unmatched = mismatched closing delimiter
+    .label_opening_candidate = closing delimiter possibly meant for this
+    .label_unclosed = unclosed delimiter
+
+parser_incorrect_visibility_restriction = incorrect visibility restriction
+    .help = some possible visibility restrictions are:
+            `pub(crate)`: visible only on the current crate
+            `pub(super)`: visible only in the current module's parent
+            `pub(in path::to::module)`: visible only on the specified path
+    .suggestion = make this visible only to module `{$inner_str}` with `in`
+
+parser_assignment_else_not_allowed = <assignment> ... else {"{"} ... {"}"} is not allowed
+
+parser_expected_statement_after_outer_attr = expected statement after outer attribute
+
+parser_doc_comment_does_not_document_anything = found a documentation comment that doesn't document anything
+    .help = doc comments must come before what they document, if a comment was intended use `//`
+    .suggestion = missing comma here
+
+parser_const_let_mutually_exclusive = `const` and `let` are mutually exclusive
+    .suggestion = remove `let`
+
+parser_invalid_expression_in_let_else = a `{$operator}` expression cannot be directly assigned in `let...else`
+parser_invalid_curly_in_let_else = right curly brace `{"}"}` before `else` in a `let...else` statement not allowed
+
+parser_compound_assignment_expression_in_let = can't reassign to an uninitialized variable
+    .suggestion = initialize the variable
+    .help = if you meant to overwrite, remove the `let` binding
+
+parser_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes
+    .help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
+
+parser_invalid_meta_item = expected unsuffixed literal or identifier, found `{$token}`
+
+parser_label_inner_attr_does_not_annotate_this = the inner attribute doesn't annotate this {$item}
+parser_sugg_change_inner_attr_to_outer = to annotate the {$item}, change the attribute from inner to outer style
+
+parser_inner_attr_not_permitted_after_outer_doc_comment = an inner attribute is not permitted following an outer doc comment
+    .label_attr = not permitted following an outer doc comment
+    .label_prev_doc_comment = previous doc comment
+    .label_does_not_annotate_this = {parser_label_inner_attr_does_not_annotate_this}
+    .sugg_change_inner_to_outer = {parser_sugg_change_inner_attr_to_outer}
+
+parser_inner_attr_not_permitted_after_outer_attr = an inner attribute is not permitted following an outer attribute
+    .label_attr = not permitted following an outer attribute
+    .label_prev_attr = previous outer attribute
+    .label_does_not_annotate_this = {parser_label_inner_attr_does_not_annotate_this}
+    .sugg_change_inner_to_outer = {parser_sugg_change_inner_attr_to_outer}
+
+parser_inner_attr_not_permitted = an inner attribute is not permitted in this context
+    .label_does_not_annotate_this = {parser_label_inner_attr_does_not_annotate_this}
+    .sugg_change_inner_to_outer = {parser_sugg_change_inner_attr_to_outer}
+
+parser_inner_attr_explanation = inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
+parser_outer_attr_explanation = outer attributes, like `#[test]`, annotate the item following them
+
+parser_inner_doc_comment_not_permitted = expected outer doc comment
+    .note = inner doc comments like this (starting with `//!` or `/*!`) can only appear before items
+    .suggestion = you might have meant to write a regular comment
+    .label_does_not_annotate_this = the inner doc comment doesn't annotate this {$item}
+    .sugg_change_inner_to_outer = to annotate the {$item}, change the doc comment from inner to outer style
+
+parser_expected_identifier_found_reserved_identifier_str = expected identifier, found reserved identifier `{$token}`
+parser_expected_identifier_found_keyword_str = expected identifier, found keyword `{$token}`
+parser_expected_identifier_found_reserved_keyword_str = expected identifier, found reserved keyword `{$token}`
+parser_expected_identifier_found_doc_comment_str = expected identifier, found doc comment `{$token}`
+parser_expected_identifier_found_str = expected identifier, found `{$token}`
+
+parser_expected_identifier_found_reserved_identifier = expected identifier, found reserved identifier
+parser_expected_identifier_found_keyword = expected identifier, found keyword
+parser_expected_identifier_found_reserved_keyword = expected identifier, found reserved keyword
+parser_expected_identifier_found_doc_comment = expected identifier, found doc comment
+parser_expected_identifier = expected identifier
+
+parser_sugg_escape_to_use_as_identifier = escape `{$ident_name}` to use it as an identifier
+
+parser_sugg_remove_comma = remove this comma
+
+parser_expected_semi_found_reserved_identifier_str = expected `;`, found reserved identifier `{$token}`
+parser_expected_semi_found_keyword_str = expected `;`, found keyword `{$token}`
+parser_expected_semi_found_reserved_keyword_str = expected `;`, found reserved keyword `{$token}`
+parser_expected_semi_found_doc_comment_str = expected `;`, found doc comment `{$token}`
+parser_expected_semi_found_str = expected `;`, found `{$token}`
+
+parser_sugg_change_this_to_semi = change this to `;`
+parser_sugg_add_semi = add `;` here
+parser_label_unexpected_token = unexpected token
+
+parser_unmatched_angle_brackets = {$num_extra_brackets ->
+        [one] unmatched angle bracket
+       *[other] unmatched angle brackets
+    }
+    .suggestion = {$num_extra_brackets ->
+            [one] remove extra angle bracket
+           *[other] remove extra angle brackets
+        }
+
+parser_generic_parameters_without_angle_brackets = generic parameters without surrounding angle brackets
+    .suggestion = surround the type parameters with angle brackets
+
+parser_comparison_operators_cannot_be_chained = comparison operators cannot be chained
+    .sugg_parentheses_for_function_args = or use `(...)` if you meant to specify fn arguments
+    .sugg_split_comparison = split the comparison into two
+    .sugg_parenthesize = parenthesize the comparison
+parser_sugg_turbofish_syntax = use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
+
+parser_question_mark_in_type = invalid `?` in type
+    .label = `?` is only allowed on expressions, not types
+    .suggestion = if you meant to express that the type might not contain a value, use the `Option` wrapper type
+
+parser_unexpected_parentheses_in_for_head = unexpected parentheses surrounding `for` loop head
+    .suggestion = remove parentheses in `for` loop
+
+parser_doc_comment_on_param_type = documentation comments cannot be applied to a function parameter's type
+    .label = doc comments are not allowed here
+
+parser_attribute_on_param_type = attributes cannot be applied to a function parameter's type
+    .label = attributes are not allowed here
+
+parser_pattern_method_param_without_body = patterns aren't allowed in methods without bodies
+    .suggestion = give this argument a name or use an underscore to ignore it
+
+parser_self_param_not_first = unexpected `self` parameter in function
+    .label = must be the first parameter of an associated function
+
+parser_const_generic_without_braces = expressions must be enclosed in braces to be used as const generic arguments
+    .suggestion = enclose the `const` expression in braces
+
+parser_unexpected_const_param_declaration = unexpected `const` parameter declaration
+    .label = expected a `const` expression, not a parameter declaration
+    .suggestion = `const` parameters must be declared for the `impl`
+
+parser_unexpected_const_in_generic_param = expected lifetime, type, or constant, found keyword `const`
+    .suggestion = the `const` keyword is only needed in the definition of the type
+
+parser_async_move_order_incorrect = the order of `move` and `async` is incorrect
+    .suggestion = try switching the order
+
+parser_double_colon_in_bound = expected `:` followed by trait or lifetime
+    .suggestion = use single colon
diff --git a/compiler/rustc_error_messages/locales/en-US/session.ftl b/compiler/rustc_error_messages/locales/en-US/session.ftl
index 76cae3c81e4..3ea9429a23a 100644
--- a/compiler/rustc_error_messages/locales/en-US/session.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/session.ftl
@@ -66,3 +66,5 @@ session_crate_name_invalid = crate names cannot start with a `-`, but `{$s}` has
 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
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml
index c36ca11fad6..1eb9dca2a2b 100644
--- a/compiler/rustc_errors/Cargo.toml
+++ b/compiler/rustc_errors/Cargo.toml
@@ -8,6 +8,8 @@ doctest = false
 
 [dependencies]
 tracing = "0.1"
+rustc_ast = { path = "../rustc_ast" }
+rustc_ast_pretty = { path = "../rustc_ast_pretty" }
 rustc_error_messages = { path = "../rustc_error_messages" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_span = { path = "../rustc_span" }
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 1c440a0a07e..5520e22e476 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -3,6 +3,8 @@ use crate::{
     CodeSuggestion, DiagnosticMessage, EmissionGuarantee, Level, LintDiagnosticBuilder, 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;
@@ -175,6 +177,24 @@ impl IntoDiagnosticArg for hir::ConstContext {
     }
 }
 
+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")]
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index b44cf352233..d3effb7c1c0 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -7,7 +7,6 @@
 #![feature(if_let_guard)]
 #![feature(adt_const_params)]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(never_type)]
 #![feature(result_option_inspect)]
 #![feature(rustc_attrs)]
@@ -63,13 +62,14 @@ pub mod translation;
 pub use diagnostic_builder::IntoDiagnostic;
 pub use snippet::Style;
 
-pub type PResult<'a, T> = Result<T, DiagnosticBuilder<'a, ErrorGuaranteed>>;
+pub type PErr<'a> = DiagnosticBuilder<'a, ErrorGuaranteed>;
+pub type PResult<'a, T> = Result<T, PErr<'a>>;
 
 // `PResult` is used a lot. Make sure it doesn't unintentionally get bigger.
 // (See also the comment on `DiagnosticBuilder`'s `diagnostic` field.)
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(PResult<'_, ()>, 16);
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64", not(bootstrap)))]
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(PResult<'_, bool>, 16);
 
 #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)]
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index 50d2be3cee5..0952e65cfee 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -252,6 +252,10 @@ impl<'a> ExtCtxt<'a> {
         self.expr_ident(span, Ident::with_dummy_span(kw::SelfLower))
     }
 
+    pub fn expr_field(&self, span: Span, expr: P<Expr>, field: Ident) -> P<ast::Expr> {
+        self.expr(span, ast::ExprKind::Field(expr, field))
+    }
+
     pub fn expr_binary(
         &self,
         sp: Span,
diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs
index ffc9abe64d2..b34de94fb7d 100644
--- a/compiler/rustc_expand/src/lib.rs
+++ b/compiler/rustc_expand/src/lib.rs
@@ -3,7 +3,6 @@
 #![feature(associated_type_defaults)]
 #![feature(if_let_guard)]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(macro_metavar_expr)]
 #![feature(proc_macro_diagnostic)]
 #![feature(proc_macro_internals)]
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 5f7de94e726..8efb7ccc1c7 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -162,7 +162,7 @@ declare_features! (
     /// Allows capturing variables in scope using format_args!
     (accepted, format_args_capture, "1.58.0", Some(67984), None),
     /// Allows associated types to be generic, e.g., `type Foo<T>;` (RFC 1598).
-    (accepted, generic_associated_types, "CURRENT_RUSTC_VERSION", Some(44265), None),
+    (accepted, generic_associated_types, "1.65.0", Some(44265), None),
     /// Allows attributes on lifetime/type formal parameters in generics (RFC 1327).
     (accepted, generic_param_attrs, "1.27.0", Some(48848), None),
     /// Allows the `#[global_allocator]` attribute.
@@ -189,9 +189,9 @@ declare_features! (
     /// especially around globs and shadowing (RFC 1560).
     (accepted, item_like_imports, "1.15.0", Some(35120), None),
     /// Allows `'a: { break 'a; }`.
-    (accepted, label_break_value, "CURRENT_RUSTC_VERSION", Some(48594), None),
+    (accepted, label_break_value, "1.65.0", Some(48594), None),
     /// Allows `let...else` statements.
-    (accepted, let_else, "CURRENT_RUSTC_VERSION", Some(87335), None),
+    (accepted, let_else, "1.65.0", Some(87335), None),
     /// Allows `break {expr}` with a value inside `loop`s.
     (accepted, loop_break_value, "1.19.0", Some(37339), None),
     /// Allows use of `?` as the Kleene "at most one" operator in macros.
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 4c891fbf16e..71ad54291b2 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -341,7 +341,7 @@ declare_features! (
     /// Allows to use the `#[cmse_nonsecure_entry]` attribute.
     (active, cmse_nonsecure_entry, "1.48.0", Some(75835), None),
     /// Allows use of the `#[collapse_debuginfo]` attribute.
-    (active, collapse_debuginfo, "CURRENT_RUSTC_VERSION", Some(100758), None),
+    (active, collapse_debuginfo, "1.65.0", Some(100758), None),
     /// Allows `async {}` expressions in const contexts.
     (active, const_async_blocks, "1.53.0", Some(85368), None),
     // Allows limiting the evaluation steps of const expressions
@@ -387,7 +387,7 @@ declare_features! (
     /// Allows `#[doc(masked)]`.
     (active, doc_masked, "1.21.0", Some(44027), None),
     /// Allows `dyn* Trait` objects.
-    (incomplete, dyn_star, "CURRENT_RUSTC_VERSION", Some(91611), None),
+    (incomplete, dyn_star, "1.65.0", Some(91611), None),
     /// Allows `X..Y` patterns.
     (active, exclusive_range_pattern, "1.11.0", Some(37854), None),
     /// Allows exhaustive pattern matching on types that contain uninhabited types.
@@ -403,7 +403,7 @@ declare_features! (
     /// Allows using `#[repr(align(...))]` on function items
     (active, fn_align, "1.53.0", Some(82232), None),
     /// Allows generators to be cloned.
-    (active, generator_clone, "CURRENT_RUSTC_VERSION", Some(95360), None),
+    (active, generator_clone, "1.65.0", Some(95360), None),
     /// Allows defining generators.
     (active, generators, "1.21.0", Some(43122), None),
     /// Infer generic args for both consts and types.
@@ -484,7 +484,7 @@ declare_features! (
     /// Allows macro attributes on expressions, statements and non-inline modules.
     (active, proc_macro_hygiene, "1.30.0", Some(54727), None),
     /// Allows the use of raw-dylibs (RFC 2627).
-    (active, raw_dylib, "CURRENT_RUSTC_VERSION", Some(58713), None),
+    (active, raw_dylib, "1.65.0", Some(58713), None),
     /// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions.
     (active, raw_ref_op, "1.41.0", Some(64490), None),
     /// Allows using the `#[register_tool]` attribute.
@@ -494,7 +494,7 @@ declare_features! (
     /// Allows `repr(simd)` and importing the various simd intrinsics.
     (active, repr_simd, "1.4.0", Some(27731), None),
     /// Allows return-position `impl Trait` in traits.
-    (incomplete, return_position_impl_trait_in_trait, "CURRENT_RUSTC_VERSION", Some(91611), None),
+    (incomplete, return_position_impl_trait_in_trait, "1.65.0", Some(91611), None),
     /// Allows `extern "rust-cold"`.
     (active, rust_cold_cc, "1.63.0", Some(97544), None),
     /// Allows the use of SIMD types in functions declared in `extern` blocks.
@@ -528,7 +528,7 @@ declare_features! (
     /// not changed from prior instances of the same struct (RFC #2528)
     (active, type_changing_struct_update, "1.58.0", Some(86555), None),
     /// Enables rustc to generate code that instructs libstd to NOT ignore SIGPIPE.
-    (active, unix_sigpipe, "CURRENT_RUSTC_VERSION", Some(97889), None),
+    (active, unix_sigpipe, "1.65.0", Some(97889), None),
     /// Allows unsized fn parameters.
     (active, unsized_fn_params, "1.49.0", Some(48055), None),
     /// Allows unsized rvalues at arguments and parameters.
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 700d9dab64b..5ee6c9f2387 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -499,6 +499,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
     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_default_body_unstable, Normal,
         template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index 13f275bb6a0..79a12801de2 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -164,7 +164,7 @@ declare_features! (
     (removed, quote, "1.33.0", Some(29601), None, None),
     (removed, reflect, "1.0.0", Some(27749), None, None),
     /// Allows using the `#[register_attr]` attribute.
-    (removed, register_attr, "CURRENT_RUSTC_VERSION", Some(66080), None,
+    (removed, register_attr, "1.65.0", Some(66080), None,
      Some("removed in favor of `#![register_tool]`")),
     /// Allows using the macros:
     /// + `__diagnostic_used`
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index e7c26bd726f..f1f0c224bbd 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -314,74 +314,75 @@ pub enum Res<Id = hir::HirId> {
     /// **Belongs to the type namespace.**
     PrimTy(hir::PrimTy),
 
-    /// The `Self` type, optionally with the [`DefId`] of the trait it belongs to and
-    /// optionally with the [`DefId`] of the item introducing the `Self` type alias.
+    /// The `Self` type, as used within a trait.
+    ///
+    /// **Belongs to the type namespace.**
+    ///
+    /// See the examples on [`Res::SelfTyAlias`] for details.
+    SelfTyParam {
+        /// The trait this `Self` is a generic parameter for.
+        trait_: DefId,
+    },
+
+    /// The `Self` type, as used somewhere other than within a trait.
     ///
     /// **Belongs to the type namespace.**
     ///
     /// Examples:
     /// ```
-    /// struct Bar(Box<Self>);
-    /// // `Res::SelfTy { trait_: None, alias_of: Some(Bar) }`
+    /// struct Bar(Box<Self>); // SelfTyAlias
     ///
     /// trait Foo {
-    ///     fn foo() -> Box<Self>;
-    ///     // `Res::SelfTy { trait_: Some(Foo), alias_of: None }`
+    ///     fn foo() -> Box<Self>; // SelfTyParam
     /// }
     ///
     /// impl Bar {
     ///     fn blah() {
-    ///         let _: Self;
-    ///         // `Res::SelfTy { trait_: None, alias_of: Some(::{impl#0}) }`
+    ///         let _: Self; // SelfTyAlias
     ///     }
     /// }
     ///
     /// impl Foo for Bar {
-    ///     fn foo() -> Box<Self> {
-    ///     // `Res::SelfTy { trait_: Some(Foo), alias_of: Some(::{impl#1}) }`
-    ///         let _: Self;
-    ///         // `Res::SelfTy { trait_: Some(Foo), alias_of: Some(::{impl#1}) }`
+    ///     fn foo() -> Box<Self> { // SelfTyAlias
+    ///         let _: Self;        // SelfTyAlias
     ///
     ///         todo!()
     ///     }
     /// }
     /// ```
-    ///
     /// *See also [`Res::SelfCtor`].*
     ///
-    /// -----
-    ///
-    /// HACK(min_const_generics): self types also have an optional requirement to **not** mention
-    /// any generic parameters to allow the following with `min_const_generics`:
-    /// ```
-    /// # struct Foo;
-    /// impl Foo { fn test() -> [u8; std::mem::size_of::<Self>()] { todo!() } }
-    ///
-    /// struct Bar([u8; baz::<Self>()]);
-    /// const fn baz<T>() -> usize { 10 }
-    /// ```
-    /// We do however allow `Self` in repeat expression even if it is generic to not break code
-    /// which already works on stable while causing the `const_evaluatable_unchecked` future compat
-    /// lint:
-    /// ```
-    /// fn foo<T>() {
-    ///     let _bar = [1_u8; std::mem::size_of::<*mut T>()];
-    /// }
-    /// ```
-    // FIXME(generic_const_exprs): Remove this bodge once that feature is stable.
-    SelfTy {
-        /// The trait this `Self` is a generic arg for.
-        trait_: Option<DefId>,
+    SelfTyAlias {
         /// The item introducing the `Self` type alias. Can be used in the `type_of` query
-        /// to get the underlying type. Additionally whether the `Self` type is disallowed
-        /// from mentioning generics (i.e. when used in an anonymous constant).
-        alias_to: Option<(DefId, bool)>,
-    },
+        /// to get the underlying type.
+        alias_to: DefId,
 
-    /// A tool attribute module; e.g., the `rustfmt` in `#[rustfmt::skip]`.
-    ///
-    /// **Belongs to the type namespace.**
-    ToolMod,
+        /// Whether the `Self` type is disallowed from mentioning generics (i.e. when used in an
+        /// anonymous constant).
+        ///
+        /// HACK(min_const_generics): self types also have an optional requirement to **not**
+        /// mention any generic parameters to allow the following with `min_const_generics`:
+        /// ```
+        /// # struct Foo;
+        /// impl Foo { fn test() -> [u8; std::mem::size_of::<Self>()] { todo!() } }
+        ///
+        /// struct Bar([u8; baz::<Self>()]);
+        /// const fn baz<T>() -> usize { 10 }
+        /// ```
+        /// We do however allow `Self` in repeat expression even if it is generic to not break code
+        /// which already works on stable while causing the `const_evaluatable_unchecked` future
+        /// compat lint:
+        /// ```
+        /// fn foo<T>() {
+        ///     let _bar = [1_u8; std::mem::size_of::<*mut T>()];
+        /// }
+        /// ```
+        // FIXME(generic_const_exprs): Remove this bodge once that feature is stable.
+        forbid_generic: bool,
+
+        /// Is this within an `impl Foo for bar`?
+        is_trait_impl: bool,
+    },
 
     // Value namespace
     /// The `Self` constructor, along with the [`DefId`]
@@ -389,7 +390,7 @@ pub enum Res<Id = hir::HirId> {
     ///
     /// **Belongs to the value namespace.**
     ///
-    /// *See also [`Res::SelfTy`].*
+    /// *See also [`Res::SelfTyParam`] and [`Res::SelfTyAlias`].*
     SelfCtor(DefId),
 
     /// A local variable or function parameter.
@@ -397,6 +398,11 @@ pub enum Res<Id = hir::HirId> {
     /// **Belongs to the value namespace.**
     Local(Id),
 
+    /// A tool attribute module; e.g., the `rustfmt` in `#[rustfmt::skip]`.
+    ///
+    /// **Belongs to the type namespace.**
+    ToolMod,
+
     // Macro namespace
     /// An attribute that is *not* implemented via macro.
     /// E.g., `#[inline]` and `#[rustfmt::skip]`, which are essentially directives,
@@ -606,7 +612,8 @@ impl<Id> Res<Id> {
 
             Res::Local(..)
             | Res::PrimTy(..)
-            | Res::SelfTy { .. }
+            | Res::SelfTyParam { .. }
+            | Res::SelfTyAlias { .. }
             | Res::SelfCtor(..)
             | Res::ToolMod
             | Res::NonMacroAttr(..)
@@ -629,7 +636,7 @@ impl<Id> Res<Id> {
             Res::SelfCtor(..) => "self constructor",
             Res::PrimTy(..) => "builtin type",
             Res::Local(..) => "local variable",
-            Res::SelfTy { .. } => "self type",
+            Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => "self type",
             Res::ToolMod => "tool module",
             Res::NonMacroAttr(attr_kind) => attr_kind.descr(),
             Res::Err => "unresolved item",
@@ -652,7 +659,10 @@ impl<Id> Res<Id> {
             Res::SelfCtor(id) => Res::SelfCtor(id),
             Res::PrimTy(id) => Res::PrimTy(id),
             Res::Local(id) => Res::Local(map(id)),
-            Res::SelfTy { trait_, alias_to } => Res::SelfTy { trait_, alias_to },
+            Res::SelfTyParam { trait_ } => Res::SelfTyParam { trait_ },
+            Res::SelfTyAlias { alias_to, forbid_generic, is_trait_impl } => {
+                Res::SelfTyAlias { alias_to, forbid_generic, is_trait_impl }
+            }
             Res::ToolMod => Res::ToolMod,
             Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind),
             Res::Err => Res::Err,
@@ -665,7 +675,10 @@ impl<Id> Res<Id> {
             Res::SelfCtor(id) => Res::SelfCtor(id),
             Res::PrimTy(id) => Res::PrimTy(id),
             Res::Local(id) => Res::Local(map(id)?),
-            Res::SelfTy { trait_, alias_to } => Res::SelfTy { trait_, alias_to },
+            Res::SelfTyParam { trait_ } => Res::SelfTyParam { trait_ },
+            Res::SelfTyAlias { alias_to, forbid_generic, is_trait_impl } => {
+                Res::SelfTyAlias { alias_to, forbid_generic, is_trait_impl }
+            }
             Res::ToolMod => Res::ToolMod,
             Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind),
             Res::Err => Res::Err,
@@ -692,7 +705,9 @@ impl<Id> Res<Id> {
     pub fn ns(&self) -> Option<Namespace> {
         match self {
             Res::Def(kind, ..) => kind.ns(),
-            Res::PrimTy(..) | Res::SelfTy { .. } | Res::ToolMod => Some(Namespace::TypeNS),
+            Res::PrimTy(..) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::ToolMod => {
+                Some(Namespace::TypeNS)
+            }
             Res::SelfCtor(..) | Res::Local(..) => Some(Namespace::ValueNS),
             Res::NonMacroAttr(..) => Some(Namespace::MacroNS),
             Res::Err => None,
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index a8436ea64f8..922ce738dbb 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1,6 +1,6 @@
 use crate::def::{CtorKind, DefKind, Res};
 use crate::def_id::DefId;
-pub(crate) use crate::hir_id::{HirId, ItemLocalId};
+pub(crate) use crate::hir_id::{HirId, ItemLocalId, OwnerId};
 use crate::intravisit::FnKind;
 use crate::LangItem;
 
@@ -731,6 +731,7 @@ pub enum PredicateOrigin {
 /// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`).
 #[derive(Debug, HashStable_Generic)]
 pub struct WhereBoundPredicate<'hir> {
+    pub hir_id: HirId,
     pub span: Span,
     /// Origin of the predicate.
     pub origin: PredicateOrigin,
@@ -2206,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: LocalDefId,
+    pub def_id: OwnerId,
 }
 
 impl TraitItemId {
     #[inline]
     pub fn hir_id(&self) -> HirId {
         // Items are always HIR owners.
-        HirId::make_owner(self.def_id)
+        HirId::make_owner(self.def_id.def_id)
     }
 }
 
@@ -2224,7 +2225,7 @@ impl TraitItemId {
 #[derive(Debug, HashStable_Generic)]
 pub struct TraitItem<'hir> {
     pub ident: Ident,
-    pub def_id: LocalDefId,
+    pub def_id: OwnerId,
     pub generics: &'hir Generics<'hir>,
     pub kind: TraitItemKind<'hir>,
     pub span: Span,
@@ -2235,7 +2236,7 @@ impl TraitItem<'_> {
     #[inline]
     pub fn hir_id(&self) -> HirId {
         // Items are always HIR owners.
-        HirId::make_owner(self.def_id)
+        HirId::make_owner(self.def_id.def_id)
     }
 
     pub fn trait_item_id(&self) -> TraitItemId {
@@ -2270,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: LocalDefId,
+    pub def_id: OwnerId,
 }
 
 impl ImplItemId {
     #[inline]
     pub fn hir_id(&self) -> HirId {
         // Items are always HIR owners.
-        HirId::make_owner(self.def_id)
+        HirId::make_owner(self.def_id.def_id)
     }
 }
 
@@ -2285,7 +2286,7 @@ impl ImplItemId {
 #[derive(Debug, HashStable_Generic)]
 pub struct ImplItem<'hir> {
     pub ident: Ident,
-    pub def_id: LocalDefId,
+    pub def_id: OwnerId,
     pub generics: &'hir Generics<'hir>,
     pub kind: ImplItemKind<'hir>,
     pub defaultness: Defaultness,
@@ -2297,7 +2298,7 @@ impl ImplItem<'_> {
     #[inline]
     pub fn hir_id(&self) -> HirId {
         // Items are always HIR owners.
-        HirId::make_owner(self.def_id)
+        HirId::make_owner(self.def_id.def_id)
     }
 
     pub fn impl_item_id(&self) -> ImplItemId {
@@ -2403,8 +2404,9 @@ impl<'hir> Ty<'hir> {
             return None;
         };
         match path.res {
-            Res::Def(DefKind::TyParam, def_id)
-            | Res::SelfTy { trait_: Some(def_id), alias_to: None } => Some((def_id, segment.ident)),
+            Res::Def(DefKind::TyParam, def_id) | Res::SelfTyParam { trait_: def_id } => {
+                Some((def_id, segment.ident))
+            }
             _ => None,
         }
     }
@@ -2888,14 +2890,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: LocalDefId,
+    pub def_id: OwnerId,
 }
 
 impl ItemId {
     #[inline]
     pub fn hir_id(&self) -> HirId {
         // Items are always HIR owners.
-        HirId::make_owner(self.def_id)
+        HirId::make_owner(self.def_id.def_id)
     }
 }
 
@@ -2905,7 +2907,7 @@ impl ItemId {
 #[derive(Debug, HashStable_Generic)]
 pub struct Item<'hir> {
     pub ident: Ident,
-    pub def_id: LocalDefId,
+    pub def_id: OwnerId,
     pub kind: ItemKind<'hir>,
     pub span: Span,
     pub vis_span: Span,
@@ -2915,7 +2917,7 @@ impl Item<'_> {
     #[inline]
     pub fn hir_id(&self) -> HirId {
         // Items are always HIR owners.
-        HirId::make_owner(self.def_id)
+        HirId::make_owner(self.def_id.def_id)
     }
 
     pub fn item_id(&self) -> ItemId {
@@ -3132,14 +3134,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: LocalDefId,
+    pub def_id: OwnerId,
 }
 
 impl ForeignItemId {
     #[inline]
     pub fn hir_id(&self) -> HirId {
         // Items are always HIR owners.
-        HirId::make_owner(self.def_id)
+        HirId::make_owner(self.def_id.def_id)
     }
 }
 
@@ -3160,7 +3162,7 @@ pub struct ForeignItemRef {
 pub struct ForeignItem<'hir> {
     pub ident: Ident,
     pub kind: ForeignItemKind<'hir>,
-    pub def_id: LocalDefId,
+    pub def_id: OwnerId,
     pub span: Span,
     pub vis_span: Span,
 }
@@ -3169,7 +3171,7 @@ impl ForeignItem<'_> {
     #[inline]
     pub fn hir_id(&self) -> HirId {
         // Items are always HIR owners.
-        HirId::make_owner(self.def_id)
+        HirId::make_owner(self.def_id.def_id)
     }
 
     pub fn foreign_item_id(&self) -> ForeignItemId {
@@ -3263,7 +3265,7 @@ impl<'hir> OwnerNode<'hir> {
         Node::generics(self.into())
     }
 
-    pub fn def_id(self) -> LocalDefId {
+    pub fn def_id(self) -> OwnerId {
         match self {
             OwnerNode::Item(Item { def_id, .. })
             | OwnerNode::TraitItem(TraitItem { def_id, .. })
@@ -3520,14 +3522,11 @@ mod size_asserts {
     static_assert_size!(FnDecl<'_>, 40);
     static_assert_size!(ForeignItem<'_>, 72);
     static_assert_size!(ForeignItemKind<'_>, 40);
-    #[cfg(not(bootstrap))]
     static_assert_size!(GenericArg<'_>, 24);
     static_assert_size!(GenericBound<'_>, 48);
     static_assert_size!(Generics<'_>, 56);
     static_assert_size!(Impl<'_>, 80);
-    #[cfg(not(bootstrap))]
     static_assert_size!(ImplItem<'_>, 80);
-    #[cfg(not(bootstrap))]
     static_assert_size!(ImplItemKind<'_>, 32);
     static_assert_size!(Item<'_>, 80);
     static_assert_size!(ItemKind<'_>, 48);
@@ -3535,14 +3534,13 @@ mod size_asserts {
     static_assert_size!(Param<'_>, 32);
     static_assert_size!(Pat<'_>, 72);
     static_assert_size!(PatKind<'_>, 48);
-    static_assert_size!(Path<'_>, 48);
-    static_assert_size!(PathSegment<'_>, 56);
+    static_assert_size!(Path<'_>, 40);
+    static_assert_size!(PathSegment<'_>, 48);
     static_assert_size!(QPath<'_>, 24);
+    static_assert_size!(Res, 12);
     static_assert_size!(Stmt<'_>, 32);
     static_assert_size!(StmtKind<'_>, 16);
-    #[cfg(not(bootstrap))]
     static_assert_size!(TraitItem<'_>, 88);
-    #[cfg(not(bootstrap))]
     static_assert_size!(TraitItemKind<'_>, 48);
     static_assert_size!(Ty<'_>, 48);
     static_assert_size!(TyKind<'_>, 32);
diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs
index 84b0740c7b3..752f760ea97 100644
--- a/compiler/rustc_hir/src/hir_id.rs
+++ b/compiler/rustc_hir/src/hir_id.rs
@@ -1,6 +1,43 @@
-use crate::def_id::{LocalDefId, CRATE_DEF_ID};
+use crate::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
+use rustc_span::{def_id::DefPathHash, HashStableContext};
 use std::fmt;
 
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Encodable, Decodable)]
+pub struct OwnerId {
+    pub def_id: LocalDefId,
+}
+
+impl From<OwnerId> for HirId {
+    fn from(owner: OwnerId) -> HirId {
+        HirId { owner, local_id: ItemLocalId::from_u32(0) }
+    }
+}
+
+impl OwnerId {
+    #[inline]
+    pub fn to_def_id(self) -> DefId {
+        self.def_id.to_def_id()
+    }
+}
+
+impl<CTX: HashStableContext> HashStable<CTX> for OwnerId {
+    #[inline]
+    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+        self.to_stable_hash_key(hcx).hash_stable(hcx, hasher);
+    }
+}
+
+impl<CTX: HashStableContext> ToStableHashKey<CTX> for OwnerId {
+    type KeyType = DefPathHash;
+
+    #[inline]
+    fn to_stable_hash_key(&self, hcx: &CTX) -> DefPathHash {
+        hcx.def_path_hash(self.to_def_id())
+    }
+}
+
 /// Uniquely identifies a node in the HIR of the current crate. It is
 /// composed of the `owner`, which is the `LocalDefId` of the directly enclosing
 /// `hir::Item`, `hir::TraitItem`, or `hir::ImplItem` (i.e., the closest "item-like"),
@@ -15,22 +52,23 @@ use std::fmt;
 #[derive(Encodable, Decodable, HashStable_Generic)]
 #[rustc_pass_by_value]
 pub struct HirId {
-    pub owner: LocalDefId,
+    pub owner: OwnerId,
     pub local_id: ItemLocalId,
 }
 
 impl HirId {
     /// Signal local id which should never be used.
-    pub const INVALID: HirId = HirId { owner: CRATE_DEF_ID, local_id: ItemLocalId::INVALID };
+    pub const INVALID: HirId =
+        HirId { owner: OwnerId { def_id: CRATE_DEF_ID }, local_id: ItemLocalId::INVALID };
 
     #[inline]
-    pub fn expect_owner(self) -> LocalDefId {
+    pub fn expect_owner(self) -> OwnerId {
         assert_eq!(self.local_id.index(), 0);
         self.owner
     }
 
     #[inline]
-    pub fn as_owner(self) -> Option<LocalDefId> {
+    pub fn as_owner(self) -> Option<OwnerId> {
         if self.local_id.index() == 0 { Some(self.owner) } else { None }
     }
 
@@ -41,11 +79,14 @@ impl HirId {
 
     #[inline]
     pub fn make_owner(owner: LocalDefId) -> Self {
-        Self { owner, local_id: ItemLocalId::from_u32(0) }
+        Self { owner: OwnerId { def_id: owner }, local_id: ItemLocalId::from_u32(0) }
     }
 
     pub fn index(self) -> (usize, usize) {
-        (rustc_index::vec::Idx::index(self.owner), rustc_index::vec::Idx::index(self.local_id))
+        (
+            rustc_index::vec::Idx::index(self.owner.def_id),
+            rustc_index::vec::Idx::index(self.local_id),
+        )
     }
 }
 
@@ -94,4 +135,7 @@ impl ItemLocalId {
 }
 
 /// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_ID`.
-pub const CRATE_HIR_ID: HirId = HirId { owner: CRATE_DEF_ID, local_id: ItemLocalId::from_u32(0) };
+pub const CRATE_HIR_ID: HirId =
+    HirId { owner: OwnerId { def_id: CRATE_DEF_ID }, local_id: ItemLocalId::from_u32(0) };
+
+pub const CRATE_OWNER_ID: OwnerId = OwnerId { def_id: CRATE_DEF_ID };
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 8f5f314ecae..8777a54ba09 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -847,20 +847,28 @@ pub fn walk_where_predicate<'v, V: Visitor<'v>>(
 ) {
     match *predicate {
         WherePredicate::BoundPredicate(WhereBoundPredicate {
+            hir_id,
             ref bounded_ty,
             bounds,
             bound_generic_params,
-            ..
+            origin: _,
+            span: _,
         }) => {
+            visitor.visit_id(hir_id);
             visitor.visit_ty(bounded_ty);
             walk_list!(visitor, visit_param_bound, bounds);
             walk_list!(visitor, visit_generic_param, bound_generic_params);
         }
-        WherePredicate::RegionPredicate(WhereRegionPredicate { ref lifetime, bounds, .. }) => {
+        WherePredicate::RegionPredicate(WhereRegionPredicate {
+            ref lifetime,
+            bounds,
+            span: _,
+            in_where_clause: _,
+        }) => {
             visitor.visit_lifetime(lifetime);
             walk_list!(visitor, visit_param_bound, bounds);
         }
-        WherePredicate::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty, .. }) => {
+        WherePredicate::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty, span: _ }) => {
             visitor.visit_ty(lhs_ty);
             visitor.visit_ty(rhs_ty);
         }
diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs
index 946da9265ba..1c4aa420c9b 100644
--- a/compiler/rustc_hir/src/lib.rs
+++ b/compiler/rustc_hir/src/lib.rs
@@ -4,8 +4,7 @@
 
 #![feature(associated_type_defaults)]
 #![feature(closure_track_caller)]
-#![feature(const_btree_new)]
-#![cfg_attr(bootstrap, feature(let_else))]
+#![feature(const_btree_len)]
 #![feature(once_cell)]
 #![feature(min_specialization)]
 #![feature(never_type)]
diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs
index 5b9c42686c3..06b7a65662e 100644
--- a/compiler/rustc_hir/src/stable_hash_impls.rs
+++ b/compiler/rustc_hir/src/stable_hash_impls.rs
@@ -20,7 +20,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for HirId {
 
     #[inline]
     fn to_stable_hash_key(&self, hcx: &HirCtx) -> (DefPathHash, ItemLocalId) {
-        let def_path_hash = self.owner.to_stable_hash_key(hcx);
+        let def_path_hash = self.owner.def_id.to_stable_hash_key(hcx);
         (def_path_hash, self.local_id)
     }
 }
@@ -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.to_stable_hash_key(hcx)
+        self.def_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.to_stable_hash_key(hcx)
+        self.def_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.to_stable_hash_key(hcx)
+        self.def_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.to_stable_hash_key(hcx)
+        self.def_id.def_id.to_stable_hash_key(hcx)
     }
 }
 
diff --git a/compiler/rustc_typeck/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml
index cae29c1d3c5..dd26b3da7bc 100644
--- a/compiler/rustc_typeck/Cargo.toml
+++ b/compiler/rustc_hir_analysis/Cargo.toml
@@ -1,5 +1,5 @@
 [package]
-name = "rustc_typeck"
+name = "rustc_hir_analysis"
 version = "0.0.0"
 edition = "2021"
 
diff --git a/compiler/rustc_typeck/README.md b/compiler/rustc_hir_analysis/README.md
index b61dbd8c964..b61dbd8c964 100644
--- a/compiler/rustc_typeck/README.md
+++ b/compiler/rustc_hir_analysis/README.md
diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs
index a9152bdc597..a9152bdc597 100644
--- a/compiler/rustc_typeck/src/astconv/errors.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs
diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs
index afac75de2d9..afac75de2d9 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 5432fdbb5e8..d7c9cff2294 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -365,7 +365,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         // here and so associated type bindings will be handled regardless of whether there are any
         // non-`Self` generic parameters.
         if generics.params.is_empty() {
-            return (tcx.intern_substs(&[]), arg_count);
+            return (tcx.intern_substs(parent_substs), arg_count);
         }
 
         struct SubstsForAstPathCtxt<'a, 'tcx> {
@@ -586,7 +586,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
     pub(crate) fn create_substs_for_associated_item(
         &self,
-        tcx: TyCtxt<'tcx>,
         span: Span,
         item_def_id: DefId,
         item_segment: &hir::PathSegment<'_>,
@@ -596,22 +595,22 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             "create_substs_for_associated_item(span: {:?}, item_def_id: {:?}, item_segment: {:?}",
             span, item_def_id, item_segment
         );
-        if tcx.generics_of(item_def_id).params.is_empty() {
-            self.prohibit_generics(slice::from_ref(item_segment).iter(), |_| {});
+        let (args, _) = self.create_substs_for_ast_path(
+            span,
+            item_def_id,
+            parent_substs,
+            item_segment,
+            item_segment.args(),
+            item_segment.infer_args,
+            None,
+        );
 
-            parent_substs
-        } else {
-            self.create_substs_for_ast_path(
-                span,
-                item_def_id,
-                parent_substs,
-                item_segment,
-                item_segment.args(),
-                item_segment.infer_args,
-                None,
-            )
-            .0
+        let assoc_bindings = self.create_assoc_bindings_for_generic_args(item_segment.args());
+        if let Some(b) = assoc_bindings.first() {
+            Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
         }
+
+        args
     }
 
     /// Instantiates the path for the given trait reference, assuming that it's
@@ -1121,7 +1120,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             };
 
             let substs_trait_ref_and_assoc_item = self.create_substs_for_associated_item(
-                tcx,
                 path_span,
                 assoc_item.def_id,
                 &item_segment,
@@ -1904,7 +1902,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         // Find the type of the associated item, and the trait where the associated
         // item is declared.
         let bound = match (&qself_ty.kind(), qself_res) {
-            (_, Res::SelfTy { trait_: Some(_), alias_to: Some((impl_def_id, _)) }) => {
+            (_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => {
                 // `Self` in an impl of a trait -- we have a concrete self type and a
                 // trait reference.
                 let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else {
@@ -1923,8 +1921,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             }
             (
                 &ty::Param(_),
-                Res::SelfTy { trait_: Some(param_did), alias_to: None }
-                | Res::Def(DefKind::TyParam, param_did),
+                Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did),
             ) => self.find_bound_for_assoc_item(param_did.expect_local(), assoc_ident, span)?,
             _ => {
                 let reported = if variant_resolution.is_some() {
@@ -2100,7 +2097,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             self.ast_path_to_mono_trait_ref(span, trait_def_id, self_ty, trait_segment, false);
 
         let item_substs = self.create_substs_for_associated_item(
-            tcx,
             span,
             item_def_id,
             item_segment,
@@ -2420,7 +2416,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 let index = generics.param_def_id_to_index[&def_id.to_def_id()];
                 tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id))
             }
-            Res::SelfTy { trait_: Some(_), alias_to: None } => {
+            Res::SelfTyParam { .. } => {
                 // `Self` in trait or type alias.
                 assert_eq!(opt_self_ty, None);
                 self.prohibit_generics(path.segments.iter(), |err| {
@@ -2435,7 +2431,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 });
                 tcx.types.self_param
             }
-            Res::SelfTy { trait_: _, alias_to: Some((def_id, forbid_generic)) } => {
+            Res::SelfTyAlias { alias_to: def_id, forbid_generic, .. } => {
                 // `Self` in impl (we know the concrete type).
                 assert_eq!(opt_self_ty, None);
                 // Try to evaluate any array length constants.
@@ -3003,7 +2999,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     /// Make sure that we are in the condition to suggest the blanket implementation.
     fn maybe_lint_blanket_trait_impl(&self, self_ty: &hir::Ty<'_>, diag: &mut Diagnostic) {
         let tcx = self.tcx();
-        let parent_id = tcx.hir().get_parent_item(self_ty.hir_id);
+        let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
         if let hir::Node::Item(hir::Item {
             kind:
                 hir::ItemKind::Impl(hir::Impl {
diff --git a/compiler/rustc_typeck/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs
index 6a28bb16a20..6a28bb16a20 100644
--- a/compiler/rustc_typeck/src/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/bounds.rs
diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_hir_analysis/src/check/_match.rs
index 27329f8eab4..201927091a6 100644
--- a/compiler/rustc_typeck/src/check/_match.rs
+++ b/compiler/rustc_hir_analysis/src/check/_match.rs
@@ -140,7 +140,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     let Some(ret) = self
                         .tcx
                         .hir()
-                        .find_by_def_id(self.body_id.owner)
+                        .find_by_def_id(self.body_id.owner.def_id)
                         .and_then(|owner| owner.fn_decl())
                         .map(|decl| decl.output.span())
                     else { return; };
@@ -495,7 +495,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     .typeck_results
                     .borrow()
                     .liberated_fn_sigs()
-                    .get(hir::HirId::make_owner(self.body_id.owner))?;
+                    .get(hir::HirId::make_owner(self.body_id.owner.def_id))?;
 
                 let substs = sig.output().walk().find_map(|arg| {
                     if let ty::GenericArgKind::Type(ty) = arg.unpack()
diff --git a/compiler/rustc_typeck/src/check/autoderef.rs b/compiler/rustc_hir_analysis/src/check/autoderef.rs
index 59c366ad7d7..59c366ad7d7 100644
--- a/compiler/rustc_typeck/src/check/autoderef.rs
+++ b/compiler/rustc_hir_analysis/src/check/autoderef.rs
diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_hir_analysis/src/check/callee.rs
index c82a31e65cf..080771844a4 100644
--- a/compiler/rustc_typeck/src/check/callee.rs
+++ b/compiler/rustc_hir_analysis/src/check/callee.rs
@@ -394,140 +394,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             ty::FnPtr(sig) => (sig, None),
             _ => {
-                let mut unit_variant = None;
-                if let hir::ExprKind::Path(qpath) = &callee_expr.kind
-                    && let Res::Def(def::DefKind::Ctor(kind, def::CtorKind::Const), _)
-                        = self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id)
-                    // Only suggest removing parens if there are no arguments
-                    && arg_exprs.is_empty()
-                {
-                    let descr = match kind {
-                        def::CtorOf::Struct => "struct",
-                        def::CtorOf::Variant => "enum variant",
-                    };
-                    let removal_span =
-                        callee_expr.span.shrink_to_hi().to(call_expr.span.shrink_to_hi());
-                    unit_variant =
-                        Some((removal_span, descr, rustc_hir_pretty::qpath_to_string(qpath)));
-                }
-
-                let callee_ty = self.resolve_vars_if_possible(callee_ty);
-                let mut err = type_error_struct!(
-                    self.tcx.sess,
-                    callee_expr.span,
-                    callee_ty,
-                    E0618,
-                    "expected function, found {}",
-                    match &unit_variant {
-                        Some((_, kind, path)) => format!("{kind} `{path}`"),
-                        None => format!("`{callee_ty}`"),
-                    }
-                );
-
-                self.identify_bad_closure_def_and_call(
-                    &mut err,
-                    call_expr.hir_id,
-                    &callee_expr.kind,
-                    callee_expr.span,
-                );
-
-                if let Some((removal_span, kind, path)) = &unit_variant {
-                    err.span_suggestion_verbose(
-                        *removal_span,
-                        &format!(
-                            "`{path}` is a unit {kind}, and does not take parentheses to be constructed",
-                        ),
-                        "",
-                        Applicability::MachineApplicable,
-                    );
-                }
-
-                let mut inner_callee_path = None;
-                let def = match callee_expr.kind {
-                    hir::ExprKind::Path(ref qpath) => {
-                        self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id)
-                    }
-                    hir::ExprKind::Call(ref inner_callee, _) => {
-                        // If the call spans more than one line and the callee kind is
-                        // itself another `ExprCall`, that's a clue that we might just be
-                        // missing a semicolon (Issue #51055)
-                        let call_is_multiline =
-                            self.tcx.sess.source_map().is_multiline(call_expr.span);
-                        if call_is_multiline {
-                            err.span_suggestion(
-                                callee_expr.span.shrink_to_hi(),
-                                "consider using a semicolon here",
-                                ";",
-                                Applicability::MaybeIncorrect,
-                            );
-                        }
-                        if let hir::ExprKind::Path(ref inner_qpath) = inner_callee.kind {
-                            inner_callee_path = Some(inner_qpath);
-                            self.typeck_results.borrow().qpath_res(inner_qpath, inner_callee.hir_id)
-                        } else {
-                            Res::Err
-                        }
-                    }
-                    _ => Res::Err,
-                };
-
-                if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) {
-                    if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_expr, callee_ty)
-                        && !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span)
-                    {
-                        let descr = match maybe_def {
-                            DefIdOrName::DefId(def_id) => self.tcx.def_kind(def_id).descr(def_id),
-                            DefIdOrName::Name(name) => name,
-                        };
-                        err.span_label(
-                            callee_expr.span,
-                            format!("this {descr} returns an unsized value `{output_ty}`, so it cannot be called")
-                        );
-                        if let DefIdOrName::DefId(def_id) = maybe_def
-                            && let Some(def_span) = self.tcx.hir().span_if_local(def_id)
-                        {
-                            err.span_label(def_span, "the callable type is defined here");
-                        }
-                    } else {
-                        err.span_label(call_expr.span, "call expression requires function");
-                    }
-                }
-
-                if let Some(span) = self.tcx.hir().res_span(def) {
-                    let callee_ty = callee_ty.to_string();
-                    let label = match (unit_variant, inner_callee_path) {
-                        (Some((_, kind, path)), _) => Some(format!("{kind} `{path}` defined here")),
-                        (_, Some(hir::QPath::Resolved(_, path))) => self
-                            .tcx
-                            .sess
-                            .source_map()
-                            .span_to_snippet(path.span)
-                            .ok()
-                            .map(|p| format!("`{p}` defined here returns `{callee_ty}`")),
-                        _ => {
-                            match def {
-                                // Emit a different diagnostic for local variables, as they are not
-                                // type definitions themselves, but rather variables *of* that type.
-                                Res::Local(hir_id) => Some(format!(
-                                    "`{}` has type `{}`",
-                                    self.tcx.hir().name(hir_id),
-                                    callee_ty
-                                )),
-                                Res::Def(kind, def_id) if kind.ns() == Some(Namespace::ValueNS) => {
-                                    Some(format!(
-                                        "`{}` defined here",
-                                        self.tcx.def_path_str(def_id),
-                                    ))
-                                }
-                                _ => Some(format!("`{callee_ty}` defined here")),
-                            }
-                        }
-                    };
-                    if let Some(label) = label {
-                        err.span_label(span, label);
-                    }
-                }
-                err.emit();
+                self.report_invalid_callee(call_expr, callee_expr, callee_ty, arg_exprs);
 
                 // This is the "default" function signature, used in case of error.
                 // In that case, we check each argument against "error" in order to
@@ -574,6 +441,145 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         fn_sig.output()
     }
 
+    fn report_invalid_callee(
+        &self,
+        call_expr: &'tcx hir::Expr<'tcx>,
+        callee_expr: &'tcx hir::Expr<'tcx>,
+        callee_ty: Ty<'tcx>,
+        arg_exprs: &'tcx [hir::Expr<'tcx>],
+    ) {
+        let mut unit_variant = None;
+        if let hir::ExprKind::Path(qpath) = &callee_expr.kind
+            && let Res::Def(def::DefKind::Ctor(kind, def::CtorKind::Const), _)
+                = self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id)
+            // Only suggest removing parens if there are no arguments
+            && arg_exprs.is_empty()
+        {
+            let descr = match kind {
+                def::CtorOf::Struct => "struct",
+                def::CtorOf::Variant => "enum variant",
+            };
+            let removal_span =
+                callee_expr.span.shrink_to_hi().to(call_expr.span.shrink_to_hi());
+            unit_variant =
+                Some((removal_span, descr, rustc_hir_pretty::qpath_to_string(qpath)));
+        }
+
+        let callee_ty = self.resolve_vars_if_possible(callee_ty);
+        let mut err = type_error_struct!(
+            self.tcx.sess,
+            callee_expr.span,
+            callee_ty,
+            E0618,
+            "expected function, found {}",
+            match &unit_variant {
+                Some((_, kind, path)) => format!("{kind} `{path}`"),
+                None => format!("`{callee_ty}`"),
+            }
+        );
+
+        self.identify_bad_closure_def_and_call(
+            &mut err,
+            call_expr.hir_id,
+            &callee_expr.kind,
+            callee_expr.span,
+        );
+
+        if let Some((removal_span, kind, path)) = &unit_variant {
+            err.span_suggestion_verbose(
+                *removal_span,
+                &format!(
+                    "`{path}` is a unit {kind}, and does not take parentheses to be constructed",
+                ),
+                "",
+                Applicability::MachineApplicable,
+            );
+        }
+
+        let mut inner_callee_path = None;
+        let def = match callee_expr.kind {
+            hir::ExprKind::Path(ref qpath) => {
+                self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id)
+            }
+            hir::ExprKind::Call(ref inner_callee, _) => {
+                // If the call spans more than one line and the callee kind is
+                // itself another `ExprCall`, that's a clue that we might just be
+                // missing a semicolon (Issue #51055)
+                let call_is_multiline = self.tcx.sess.source_map().is_multiline(call_expr.span);
+                if call_is_multiline {
+                    err.span_suggestion(
+                        callee_expr.span.shrink_to_hi(),
+                        "consider using a semicolon here",
+                        ";",
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+                if let hir::ExprKind::Path(ref inner_qpath) = inner_callee.kind {
+                    inner_callee_path = Some(inner_qpath);
+                    self.typeck_results.borrow().qpath_res(inner_qpath, inner_callee.hir_id)
+                } else {
+                    Res::Err
+                }
+            }
+            _ => Res::Err,
+        };
+
+        if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) {
+            if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_expr, callee_ty)
+                && !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span)
+            {
+                let descr = match maybe_def {
+                    DefIdOrName::DefId(def_id) => self.tcx.def_kind(def_id).descr(def_id),
+                    DefIdOrName::Name(name) => name,
+                };
+                err.span_label(
+                    callee_expr.span,
+                    format!("this {descr} returns an unsized value `{output_ty}`, so it cannot be called")
+                );
+                if let DefIdOrName::DefId(def_id) = maybe_def
+                    && let Some(def_span) = self.tcx.hir().span_if_local(def_id)
+                {
+                    err.span_label(def_span, "the callable type is defined here");
+                }
+            } else {
+                err.span_label(call_expr.span, "call expression requires function");
+            }
+        }
+
+        if let Some(span) = self.tcx.hir().res_span(def) {
+            let callee_ty = callee_ty.to_string();
+            let label = match (unit_variant, inner_callee_path) {
+                (Some((_, kind, path)), _) => Some(format!("{kind} `{path}` defined here")),
+                (_, Some(hir::QPath::Resolved(_, path))) => self
+                    .tcx
+                    .sess
+                    .source_map()
+                    .span_to_snippet(path.span)
+                    .ok()
+                    .map(|p| format!("`{p}` defined here returns `{callee_ty}`")),
+                _ => {
+                    match def {
+                        // Emit a different diagnostic for local variables, as they are not
+                        // type definitions themselves, but rather variables *of* that type.
+                        Res::Local(hir_id) => Some(format!(
+                            "`{}` has type `{}`",
+                            self.tcx.hir().name(hir_id),
+                            callee_ty
+                        )),
+                        Res::Def(kind, def_id) if kind.ns() == Some(Namespace::ValueNS) => {
+                            Some(format!("`{}` defined here", self.tcx.def_path_str(def_id),))
+                        }
+                        _ => Some(format!("`{callee_ty}` defined here")),
+                    }
+                }
+            };
+            if let Some(label) = label {
+                err.span_label(span, label);
+            }
+        }
+        err.emit();
+    }
+
     fn confirm_deferred_closure_call(
         &self,
         call_expr: &'tcx hir::Expr<'tcx>,
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_hir_analysis/src/check/cast.rs
index 81a979865ac..81a979865ac 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_hir_analysis/src/check/cast.rs
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index d6fa74c8730..4bbe9abaf98 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -609,9 +609,12 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
         fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
             match arg.kind {
                 hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
-                    [PathSegment { res: Res::SelfTy { trait_: _, alias_to: impl_ref }, .. }] => {
-                        let impl_ty_name =
-                            impl_ref.map(|(def_id, _)| self.tcx.def_path_str(def_id));
+                    [PathSegment { res: Res::SelfTyParam { .. }, .. }] => {
+                        let impl_ty_name = None;
+                        self.selftys.push((path.span, impl_ty_name));
+                    }
+                    [PathSegment { res: Res::SelfTyAlias { alias_to: def_id, .. }, .. }] => {
+                        let impl_ty_name = Some(self.tcx.def_path_str(*def_id));
                         self.selftys.push((path.span, impl_ty_name));
                     }
                     _ => {}
@@ -782,19 +785,19 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
     let _indenter = indenter();
     match tcx.def_kind(id.def_id) {
         DefKind::Static(..) => {
-            tcx.ensure().typeck(id.def_id);
-            maybe_check_static_with_link_section(tcx, id.def_id);
-            check_static_inhabited(tcx, id.def_id);
+            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);
         }
         DefKind::Const => {
-            tcx.ensure().typeck(id.def_id);
+            tcx.ensure().typeck(id.def_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);
+            check_enum(tcx, &enum_definition.variants, item.def_id.def_id);
         }
         DefKind::Fn => {} // entirely within check_item_body
         DefKind::Impl => {
@@ -807,7 +810,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
                 check_impl_items_against_trait(
                     tcx,
                     it.span,
-                    it.def_id,
+                    it.def_id.def_id,
                     impl_trait_ref,
                     &impl_.items,
                 );
@@ -845,10 +848,10 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
             }
         }
         DefKind::Struct => {
-            check_struct(tcx, id.def_id);
+            check_struct(tcx, id.def_id.def_id);
         }
         DefKind::Union => {
-            check_union(tcx, id.def_id);
+            check_union(tcx, id.def_id.def_id);
         }
         DefKind::OpaqueTy => {
             let item = tcx.hir().item(id);
@@ -861,7 +864,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
             // See https://github.com/rust-lang/rust/issues/75100
             if !tcx.sess.opts.actually_rustdoc {
                 let substs = InternalSubsts::identity_for_item(tcx, item.def_id.to_def_id());
-                check_opaque(tcx, item.def_id, substs, &origin);
+                check_opaque(tcx, item.def_id.def_id, substs, &origin);
             }
         }
         DefKind::TyAlias => {
@@ -888,7 +891,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
                 }
             } else {
                 for item in items {
-                    let def_id = item.id.def_id;
+                    let def_id = item.id.def_id.def_id;
                     let generics = tcx.generics_of(def_id);
                     let own_counts = generics.own_counts();
                     if generics.params.len() - own_counts.lifetimes != 0 {
diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_hir_analysis/src/check/closure.rs
index 84ea06a460b..84ea06a460b 100644
--- a/compiler/rustc_typeck/src/check/closure.rs
+++ b/compiler/rustc_hir_analysis/src/check/closure.rs
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_hir_analysis/src/check/coercion.rs
index def592c46c2..d738e563256 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_hir_analysis/src/check/coercion.rs
@@ -1683,7 +1683,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                     expected,
                     found,
                     can_suggest,
-                    fcx.tcx.hir().local_def_id_to_hir_id(fcx.tcx.hir().get_parent_item(id)),
+                    fcx.tcx.hir().get_parent_item(id).into(),
                 );
             }
             if !pointing_at_return_type {
@@ -1692,7 +1692,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
         }
 
         let parent_id = fcx.tcx.hir().get_parent_item(id);
-        let parent_item = fcx.tcx.hir().get_by_def_id(parent_id);
+        let parent_item = fcx.tcx.hir().get_by_def_id(parent_id.def_id);
 
         if let (Some(expr), Some(_), Some((fn_decl, _, _))) =
             (expression, blk_id, fcx.get_node_fn_decl(parent_item))
@@ -1704,7 +1704,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                 expected,
                 found,
                 id,
-                fcx.tcx.hir().local_def_id_to_hir_id(parent_id),
+                parent_id.into(),
             );
         }
 
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_method.rs
index 7c0b815e42a..ae98a8f6209 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_method.rs
@@ -140,6 +140,7 @@ pub(crate) fn compare_impl_method<'tcx>(
 ///
 /// Finally we register each of these predicates as an obligation and check that
 /// they hold.
+#[instrument(level = "debug", skip(tcx, impl_m_span, impl_trait_ref))]
 fn compare_predicate_entailment<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_m: &AssocItem,
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_hir_analysis/src/check/demand.rs
index 2c07c333a6f..264df8b914b 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_hir_analysis/src/check/demand.rs
@@ -375,7 +375,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                     let field_is_local = sole_field.did.is_local();
                     let field_is_accessible =
-                        sole_field.vis.is_accessible_from(expr.hir_id.owner, self.tcx)
+                        sole_field.vis.is_accessible_from(expr.hir_id.owner.def_id, self.tcx)
                         // Skip suggestions for unstable public fields (for example `Pin::pointer`)
                         && matches!(self.tcx.eval_stability(sole_field.did, None, expr.span, None), EvalResult::Allow | EvalResult::Unmarked);
 
diff --git a/compiler/rustc_typeck/src/check/diverges.rs b/compiler/rustc_hir_analysis/src/check/diverges.rs
index 963a93a95c2..963a93a95c2 100644
--- a/compiler/rustc_typeck/src/check/diverges.rs
+++ b/compiler/rustc_hir_analysis/src/check/diverges.rs
diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs
index ab143c05982..e5b212eb757 100644
--- a/compiler/rustc_typeck/src/check/dropck.rs
+++ b/compiler/rustc_hir_analysis/src/check/dropck.rs
@@ -1,4 +1,4 @@
-// FIXME(@lcnr): Move this module out of `rustc_typeck`.
+// FIXME(@lcnr): Move this module out of `rustc_hir_analysis`.
 //
 // We don't do any drop checking during hir typeck.
 use crate::hir::def_id::{DefId, LocalDefId};
diff --git a/compiler/rustc_typeck/src/check/expectation.rs b/compiler/rustc_hir_analysis/src/check/expectation.rs
index e9e81034477..e9e81034477 100644
--- a/compiler/rustc_typeck/src/check/expectation.rs
+++ b/compiler/rustc_hir_analysis/src/check/expectation.rs
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_hir_analysis/src/check/expr.rs
index 23fadff3248..48a4f40780b 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_hir_analysis/src/check/expr.rs
@@ -752,7 +752,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 kind: hir::ImplItemKind::Fn(..),
                 span: encl_fn_span,
                 ..
-            })) = self.tcx.hir().find_by_def_id(encl_item_id)
+            })) = self.tcx.hir().find_by_def_id(encl_item_id.def_id)
             {
                 // We are inside a function body, so reporting "return statement
                 // outside of function body" needs an explanation.
@@ -761,7 +761,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                 // If this didn't hold, we would not have to report an error in
                 // the first place.
-                assert_ne!(encl_item_id, encl_body_owner_id);
+                assert_ne!(encl_item_id.def_id, encl_body_owner_id);
 
                 let encl_body_id = self.tcx.hir().body_owned_by(encl_body_owner_id);
                 let encl_body = self.tcx.hir().body(encl_body_id);
@@ -2338,7 +2338,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if let ty::Adt(def, _) = output_ty.kind() && !def.is_enum() {
                 def.non_enum_variant().fields.iter().any(|field| {
                     field.ident(self.tcx) == ident
-                        && field.vis.is_accessible_from(expr.hir_id.owner, self.tcx)
+                        && field.vis.is_accessible_from(expr.hir_id.owner.def_id, self.tcx)
                 })
             } else if let ty::Tuple(tys) = output_ty.kind()
                 && let Ok(idx) = ident.as_str().parse::<usize>()
diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_hir_analysis/src/check/fallback.rs
index 4059b3403b1..4059b3403b1 100644
--- a/compiler/rustc_typeck/src/check/fallback.rs
+++ b/compiler/rustc_hir_analysis/src/check/fallback.rs
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs
index 4522678802b..4522678802b 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs b/compiler/rustc_hir_analysis/src/check/fn_ctxt/arg_matrix.rs
index fc83994caf5..fc83994caf5 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs
+++ b/compiler/rustc_hir_analysis/src/check/fn_ctxt/arg_matrix.rs
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_hir_analysis/src/check/fn_ctxt/checks.rs
index 311fcaadaa9..55902aafb35 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_analysis/src/check/fn_ctxt/checks.rs
@@ -1199,7 +1199,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 _ => bug!("unexpected type: {:?}", ty),
             },
             Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
-            | Res::SelfTy { .. } => match ty.kind() {
+            | Res::SelfTyParam { .. }
+            | Res::SelfTyAlias { .. } => match ty.kind() {
                 ty::Adt(adt, substs) if !adt.is_enum() => {
                     Some((adt.non_enum_variant(), adt.did(), substs))
                 }
@@ -1543,7 +1544,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     fn parent_item_span(&self, id: hir::HirId) -> Option<Span> {
-        let node = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(id));
+        let node = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(id).def_id);
         match node {
             Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })
             | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body_id), .. }) => {
@@ -1559,7 +1560,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     /// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise.
     fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> {
-        let parent = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(blk_id));
+        let parent = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(blk_id).def_id);
         self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident))
     }
 
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_hir_analysis/src/check/fn_ctxt/mod.rs
index 0e22971d3aa..d929a3e6548 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/fn_ctxt/mod.rs
@@ -276,7 +276,6 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
 
         let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item(
             self,
-            self.tcx,
             span,
             item_def_id,
             item_segment,
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs
index c32d1309031..c32d1309031 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs
diff --git a/compiler/rustc_typeck/src/check/gather_locals.rs b/compiler/rustc_hir_analysis/src/check/gather_locals.rs
index 8f34a970f6f..8f34a970f6f 100644
--- a/compiler/rustc_typeck/src/check/gather_locals.rs
+++ b/compiler/rustc_hir_analysis/src/check/gather_locals.rs
diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_hir_analysis/src/check/generator_interior.rs
index 254a19368bf..254a19368bf 100644
--- a/compiler/rustc_typeck/src/check/generator_interior.rs
+++ b/compiler/rustc_hir_analysis/src/check/generator_interior.rs
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs b/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges.rs
index 518cd734236..518cd734236 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs
+++ b/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges.rs
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_build.rs
index 016f4056bd9..016f4056bd9 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
+++ b/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_build.rs
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_propagate.rs b/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_propagate.rs
index 139d17d2e1c..139d17d2e1c 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_propagate.rs
+++ b/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_propagate.rs
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs b/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_visualize.rs
index c0a0bfe8e1c..c0a0bfe8e1c 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs
+++ b/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_visualize.rs
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs b/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
index e22675e9d5f..e22675e9d5f 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
+++ b/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_hir_analysis/src/check/inherited.rs
index 37c830d4e38..37c830d4e38 100644
--- a/compiler/rustc_typeck/src/check/inherited.rs
+++ b/compiler/rustc_hir_analysis/src/check/inherited.rs
diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index ae484b4feda..8be1cf04f8b 100644
--- a/compiler/rustc_typeck/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -7,7 +7,8 @@ use crate::errors::{
 };
 use crate::require_same_types;
 
-use rustc_errors::struct_span_err;
+use hir::def_id::DefId;
+use rustc_errors::{struct_span_err, DiagnosticMessage};
 use rustc_hir as hir;
 use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::{self, TyCtxt};
@@ -61,8 +62,12 @@ fn equate_intrinsic_type<'tcx>(
 }
 
 /// Returns the unsafety of the given intrinsic.
-pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety {
-    match intrinsic {
+pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: DefId) -> hir::Unsafety {
+    let has_safe_attr = match tcx.has_attr(intrinsic_id, sym::rustc_safe_intrinsic) {
+        true => hir::Unsafety::Normal,
+        false => hir::Unsafety::Unsafe,
+    };
+    let is_in_list = match tcx.item_name(intrinsic_id) {
         // When adding a new intrinsic to this list,
         // it's usually worth updating that intrinsic's documentation
         // to note that it's safe to call, since
@@ -106,14 +111,26 @@ pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety {
         | sym::variant_count
         | sym::ptr_mask => hir::Unsafety::Normal,
         _ => hir::Unsafety::Unsafe,
+    };
+
+    if has_safe_attr != is_in_list {
+        tcx.sess.struct_span_err(
+            tcx.def_span(intrinsic_id),
+            DiagnosticMessage::Str(format!(
+                    "intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `{}`",
+                    tcx.item_name(intrinsic_id)
+        ))).emit();
     }
+
+    is_in_list
 }
 
 /// Remember to add all intrinsics here, in `compiler/rustc_codegen_llvm/src/intrinsic.rs`,
 /// 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_name = tcx.item_name(it.def_id.to_def_id());
+    let intrinsic_id = it.def_id.to_def_id();
+    let intrinsic_name = tcx.item_name(intrinsic_id);
     let name_str = intrinsic_name.as_str();
 
     let bound_vars = tcx.mk_bound_variable_kinds(
@@ -160,7 +177,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
         };
         (n_tps, 0, inputs, output, hir::Unsafety::Unsafe)
     } else {
-        let unsafety = intrinsic_operation_unsafety(intrinsic_name);
+        let unsafety = intrinsic_operation_unsafety(tcx, intrinsic_id);
         let (n_tps, inputs, output) = match intrinsic_name {
             sym::abort => (0, Vec::new(), tcx.types.never),
             sym::unreachable => (0, Vec::new(), tcx.types.never),
diff --git a/compiler/rustc_typeck/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
index d8fe63dbf08..d8fe63dbf08 100644
--- a/compiler/rustc_typeck/src/check/intrinsicck.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_hir_analysis/src/check/method/confirm.rs
index 30731cbd03d..30731cbd03d 100644
--- a/compiler/rustc_typeck/src/check/method/confirm.rs
+++ b/compiler/rustc_hir_analysis/src/check/method/confirm.rs
diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_hir_analysis/src/check/method/mod.rs
index 3fe9bea2299..3fe9bea2299 100644
--- a/compiler/rustc_typeck/src/check/method/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/method/mod.rs
diff --git a/compiler/rustc_typeck/src/check/method/prelude2021.rs b/compiler/rustc_hir_analysis/src/check/method/prelude2021.rs
index 392695cca68..392695cca68 100644
--- a/compiler/rustc_typeck/src/check/method/prelude2021.rs
+++ b/compiler/rustc_hir_analysis/src/check/method/prelude2021.rs
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_hir_analysis/src/check/method/probe.rs
index 6cd7ced01a3..6cd7ced01a3 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_hir_analysis/src/check/method/probe.rs
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_hir_analysis/src/check/method/suggest.rs
index 2d459b2cc0e..0e82e4956c7 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_hir_analysis/src/check/method/suggest.rs
@@ -2,6 +2,7 @@
 //! found or is otherwise invalid.
 
 use crate::check::FnCtxt;
+use rustc_ast::ast::Mutability;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{
     pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
@@ -30,7 +31,7 @@ use rustc_trait_selection::traits::{
 use std::cmp::Ordering;
 use std::iter;
 
-use super::probe::{IsSuggestion, Mode, ProbeScope};
+use super::probe::{AutorefOrPtrAdjustment, IsSuggestion, Mode, ProbeScope};
 use super::{CandidateSource, MethodError, NoMatchData};
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -983,7 +984,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     self.check_for_field_method(&mut err, source, span, actual, item_name);
                 }
 
-                self.check_for_unwrap_self(&mut err, source, span, actual, item_name);
+                self.check_for_inner_self(&mut err, source, span, actual, item_name);
 
                 bound_spans.sort();
                 bound_spans.dedup();
@@ -1395,7 +1396,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    fn check_for_unwrap_self(
+    fn check_for_inner_self(
         &self,
         err: &mut Diagnostic,
         source: SelfSource<'tcx>,
@@ -1408,81 +1409,168 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let call_expr = tcx.hir().expect_expr(tcx.hir().get_parent_node(expr.hir_id));
 
         let ty::Adt(kind, substs) = actual.kind() else { return; };
-        if !kind.is_enum() {
-            return;
-        }
+        match kind.adt_kind() {
+            ty::AdtKind::Enum => {
+                let matching_variants: Vec<_> = kind
+                    .variants()
+                    .iter()
+                    .flat_map(|variant| {
+                        let [field] = &variant.fields[..] else { return None; };
+                        let field_ty = field.ty(tcx, substs);
+
+                        // Skip `_`, since that'll just lead to ambiguity.
+                        if self.resolve_vars_if_possible(field_ty).is_ty_var() {
+                            return None;
+                        }
 
-        let matching_variants: Vec<_> = kind
-            .variants()
-            .iter()
-            .flat_map(|variant| {
-                let [field] = &variant.fields[..] else { return None; };
-                let field_ty = field.ty(tcx, substs);
+                        self.lookup_probe(
+                            span,
+                            item_name,
+                            field_ty,
+                            call_expr,
+                            ProbeScope::TraitsInScope,
+                        )
+                        .ok()
+                        .map(|pick| (variant, field, pick))
+                    })
+                    .collect();
+
+                let ret_ty_matches = |diagnostic_item| {
+                    if let Some(ret_ty) = self
+                        .ret_coercion
+                        .as_ref()
+                        .map(|c| self.resolve_vars_if_possible(c.borrow().expected_ty()))
+                        && let ty::Adt(kind, _) = ret_ty.kind()
+                        && tcx.get_diagnostic_item(diagnostic_item) == Some(kind.did())
+                    {
+                        true
+                    } else {
+                        false
+                    }
+                };
 
-                // Skip `_`, since that'll just lead to ambiguity.
-                if self.resolve_vars_if_possible(field_ty).is_ty_var() {
-                    return None;
+                match &matching_variants[..] {
+                    [(_, field, pick)] => {
+                        let self_ty = field.ty(tcx, substs);
+                        err.span_note(
+                            tcx.def_span(pick.item.def_id),
+                            &format!("the method `{item_name}` exists on the type `{self_ty}`"),
+                        );
+                        let (article, kind, variant, question) =
+                            if tcx.is_diagnostic_item(sym::Result, kind.did()) {
+                                ("a", "Result", "Err", ret_ty_matches(sym::Result))
+                            } else if tcx.is_diagnostic_item(sym::Option, kind.did()) {
+                                ("an", "Option", "None", ret_ty_matches(sym::Option))
+                            } else {
+                                return;
+                            };
+                        if question {
+                            err.span_suggestion_verbose(
+                                expr.span.shrink_to_hi(),
+                                format!(
+                                    "use the `?` operator to extract the `{self_ty}` value, propagating \
+                                    {article} `{kind}::{variant}` value to the caller"
+                                ),
+                                "?",
+                                Applicability::MachineApplicable,
+                            );
+                        } else {
+                            err.span_suggestion_verbose(
+                                expr.span.shrink_to_hi(),
+                                format!(
+                                    "consider using `{kind}::expect` to unwrap the `{self_ty}` value, \
+                                    panicking if the value is {article} `{kind}::{variant}`"
+                                ),
+                                ".expect(\"REASON\")",
+                                Applicability::HasPlaceholders,
+                            );
+                        }
+                    }
+                    // FIXME(compiler-errors): Support suggestions for other matching enum variants
+                    _ => {}
                 }
-
-                self.lookup_probe(span, item_name, field_ty, call_expr, ProbeScope::AllTraits)
-                    .ok()
-                    .map(|pick| (variant, field, pick))
-            })
-            .collect();
-
-        let ret_ty_matches = |diagnostic_item| {
-            if let Some(ret_ty) = self
-                .ret_coercion
-                .as_ref()
-                .map(|c| self.resolve_vars_if_possible(c.borrow().expected_ty()))
-                && let ty::Adt(kind, _) = ret_ty.kind()
-                && tcx.get_diagnostic_item(diagnostic_item) == Some(kind.did())
-            {
-                true
-            } else {
-                false
             }
-        };
+            // Target wrapper types - types that wrap or pretend to wrap another type,
+            // perhaps this inner type is meant to be called?
+            ty::AdtKind::Struct | ty::AdtKind::Union => {
+                let [first] = ***substs else { return; };
+                let ty::GenericArgKind::Type(ty) = first.unpack() else { return; };
+                let Ok(pick) = self.lookup_probe(
+                            span,
+                            item_name,
+                            ty,
+                            call_expr,
+                            ProbeScope::TraitsInScope,
+                        )  else { return; };
 
-        match &matching_variants[..] {
-            [(_, field, pick)] => {
-                let self_ty = field.ty(tcx, substs);
-                err.span_note(
-                    tcx.def_span(pick.item.def_id),
-                    &format!("the method `{item_name}` exists on the type `{self_ty}`"),
-                );
-                let (article, kind, variant, question) =
-                    if Some(kind.did()) == tcx.get_diagnostic_item(sym::Result) {
-                        ("a", "Result", "Err", ret_ty_matches(sym::Result))
-                    } else if Some(kind.did()) == tcx.get_diagnostic_item(sym::Option) {
-                        ("an", "Option", "None", ret_ty_matches(sym::Option))
-                    } else {
-                        return;
+                let name = self.ty_to_value_string(actual);
+                let inner_id = kind.did();
+                let mutable = if let Some(AutorefOrPtrAdjustment::Autoref { mutbl, .. }) =
+                    pick.autoref_or_ptr_adjustment
+                {
+                    Some(mutbl)
+                } else {
+                    None
+                };
+
+                if tcx.is_diagnostic_item(sym::LocalKey, inner_id) {
+                    err.help("use `with` or `try_with` to access thread local storage");
+                } else if Some(kind.did()) == tcx.lang_items().maybe_uninit() {
+                    err.help(format!(
+                        "if this `{name}` has been initialized, \
+                        use one of the `assume_init` methods to access the inner value"
+                    ));
+                } else if tcx.is_diagnostic_item(sym::RefCell, inner_id) {
+                    let (suggestion, borrow_kind, panic_if) = match mutable {
+                        Some(Mutability::Not) => (".borrow()", "borrow", "a mutable borrow exists"),
+                        Some(Mutability::Mut) => {
+                            (".borrow_mut()", "mutably borrow", "any borrows exist")
+                        }
+                        None => return,
                     };
-                if question {
                     err.span_suggestion_verbose(
                         expr.span.shrink_to_hi(),
                         format!(
-                            "use the `?` operator to extract the `{self_ty}` value, propagating \
-                            {article} `{kind}::{variant}` value to the caller"
+                            "use `{suggestion}` to {borrow_kind} the `{ty}`, \
+                            panicking if {panic_if}"
                         ),
-                        "?",
-                        Applicability::MachineApplicable,
+                        suggestion,
+                        Applicability::MaybeIncorrect,
                     );
-                } else {
+                } else if tcx.is_diagnostic_item(sym::Mutex, inner_id) {
                     err.span_suggestion_verbose(
                         expr.span.shrink_to_hi(),
                         format!(
-                            "consider using `{kind}::expect` to unwrap the `{self_ty}` value, \
-                             panicking if the value is {article} `{kind}::{variant}`"
+                            "use `.lock().unwrap()` to borrow the `{ty}`, \
+                            blocking the current thread until it can be acquired"
                         ),
-                        ".expect(\"REASON\")",
-                        Applicability::HasPlaceholders,
+                        ".lock().unwrap()",
+                        Applicability::MaybeIncorrect,
                     );
-                }
+                } else if tcx.is_diagnostic_item(sym::RwLock, inner_id) {
+                    let (suggestion, borrow_kind) = match mutable {
+                        Some(Mutability::Not) => (".read().unwrap()", "borrow"),
+                        Some(Mutability::Mut) => (".write().unwrap()", "mutably borrow"),
+                        None => return,
+                    };
+                    err.span_suggestion_verbose(
+                        expr.span.shrink_to_hi(),
+                        format!(
+                            "use `{suggestion}` to {borrow_kind} the `{ty}`, \
+                            blocking the current thread until it can be acquired"
+                        ),
+                        suggestion,
+                        Applicability::MaybeIncorrect,
+                    );
+                } else {
+                    return;
+                };
+
+                err.span_note(
+                    tcx.def_span(pick.item.def_id),
+                    &format!("the method `{item_name}` exists on the type `{ty}`"),
+                );
             }
-            // FIXME(compiler-errors): Support suggestions for other matching enum variants
-            _ => {}
         }
     }
 
@@ -2077,7 +2165,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 Colon,
                                 Nothing,
                             }
-                            let ast_generics = hir.get_generics(id.owner).unwrap();
+                            let ast_generics = hir.get_generics(id.owner.def_id).unwrap();
                             let (sp, mut introducer) = if let Some(span) =
                                 ast_generics.bounds_span_for_suggestions(def_id)
                             {
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 1a4c888a5a4..593a9776bde 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -519,7 +519,7 @@ fn get_owner_return_paths<'tcx>(
     def_id: LocalDefId,
 ) -> Option<(LocalDefId, ReturnsVisitor<'tcx>)> {
     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-    let parent_id = tcx.hir().get_parent_item(hir_id);
+    let parent_id = tcx.hir().get_parent_item(hir_id).def_id;
     tcx.hir().find_by_def_id(parent_id).and_then(|node| node.body_id()).map(|body_id| {
         let body = tcx.hir().body(body_id);
         let mut visitor = ReturnsVisitor::default();
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_hir_analysis/src/check/op.rs
index 4754717c29a..4754717c29a 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_hir_analysis/src/check/op.rs
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_hir_analysis/src/check/pat.rs
index 8906b622b68..8906b622b68 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_hir_analysis/src/check/pat.rs
diff --git a/compiler/rustc_typeck/src/check/place_op.rs b/compiler/rustc_hir_analysis/src/check/place_op.rs
index 2e0f37eba23..2e0f37eba23 100644
--- a/compiler/rustc_typeck/src/check/place_op.rs
+++ b/compiler/rustc_hir_analysis/src/check/place_op.rs
diff --git a/compiler/rustc_typeck/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index b89db79bef8..b89db79bef8 100644
--- a/compiler/rustc_typeck/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
diff --git a/compiler/rustc_typeck/src/check/rvalue_scopes.rs b/compiler/rustc_hir_analysis/src/check/rvalue_scopes.rs
index 22c9e796107..22c9e796107 100644
--- a/compiler/rustc_typeck/src/check/rvalue_scopes.rs
+++ b/compiler/rustc_hir_analysis/src/check/rvalue_scopes.rs
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_hir_analysis/src/check/upvar.rs
index 0b207a6c0be..0b207a6c0be 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_hir_analysis/src/check/upvar.rs
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index e4124185d15..7965ec1b43f 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -116,7 +116,7 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
     })
 }
 
-fn check_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
+fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) {
     let node = tcx.hir().expect_owner(def_id);
     match node {
         hir::OwnerNode::Crate(_) => {}
@@ -148,7 +148,7 @@ fn check_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
 /// 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;
+    let def_id = item.def_id.def_id;
 
     debug!(
         ?item.def_id,
@@ -175,7 +175,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
         // for `T`
         hir::ItemKind::Impl(ref impl_) => {
             let is_auto = tcx
-                .impl_trait_ref(item.def_id)
+                .impl_trait_ref(def_id)
                 .map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.def_id));
             if let (hir::Defaultness::Default { .. }, true) = (impl_.defaultness, is_auto) {
                 let sp = impl_.of_trait.as_ref().map_or(item.span, |t| t.path.span);
@@ -211,13 +211,13 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
             }
         }
         hir::ItemKind::Fn(ref sig, ..) => {
-            check_item_fn(tcx, item.def_id, item.ident, item.span, sig.decl);
+            check_item_fn(tcx, def_id, item.ident, item.span, sig.decl);
         }
         hir::ItemKind::Static(ty, ..) => {
-            check_item_type(tcx, item.def_id, ty.span, false);
+            check_item_type(tcx, def_id, ty.span, false);
         }
         hir::ItemKind::Const(ty, ..) => {
-            check_item_type(tcx, item.def_id, ty.span, false);
+            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)]);
@@ -247,7 +247,7 @@ 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;
+    let def_id = item.def_id.def_id;
 
     debug!(
         ?item.def_id,
@@ -256,15 +256,15 @@ fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) {
 
     match item.kind {
         hir::ForeignItemKind::Fn(decl, ..) => {
-            check_item_fn(tcx, item.def_id, item.ident, item.span, decl)
+            check_item_fn(tcx, def_id, item.ident, item.span, decl)
         }
-        hir::ForeignItemKind::Static(ty, ..) => check_item_type(tcx, item.def_id, ty.span, true),
+        hir::ForeignItemKind::Static(ty, ..) => check_item_type(tcx, def_id, ty.span, true),
         hir::ForeignItemKind::Type => (),
     }
 }
 
 fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) {
-    let def_id = trait_item.def_id;
+    let def_id = trait_item.def_id.def_id;
 
     let (method_sig, span) = match trait_item.kind {
         hir::TraitItemKind::Fn(ref sig, _) => (Some(sig), trait_item.span),
@@ -272,7 +272,7 @@ fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) {
         _ => (None, trait_item.span),
     };
     check_object_unsafe_self_trait_by_name(tcx, trait_item);
-    check_associated_item(tcx, trait_item.def_id, span, method_sig);
+    check_associated_item(tcx, def_id, span, method_sig);
 
     let encl_trait_def_id = tcx.local_parent(def_id);
     let encl_trait = tcx.hir().expect_item(encl_trait_def_id);
@@ -393,7 +393,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
                             // We also assume that all of the function signature's parameter types
                             // are well formed.
                             &sig.inputs().iter().copied().collect(),
-                            gat_def_id,
+                            gat_def_id.def_id,
                             gat_generics,
                         )
                     }
@@ -416,7 +416,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
                                 .copied()
                                 .collect::<Vec<_>>(),
                             &FxHashSet::default(),
-                            gat_def_id,
+                            gat_def_id.def_id,
                             gat_generics,
                         )
                     }
@@ -456,7 +456,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
     }
 
     for (gat_def_id, required_bounds) in required_bounds_by_item {
-        let gat_item_hir = tcx.hir().expect_trait_item(gat_def_id);
+        let gat_item_hir = tcx.hir().expect_trait_item(gat_def_id.def_id);
         debug!(?required_bounds);
         let param_env = tcx.param_env(gat_def_id);
         let gat_hir = gat_item_hir.hir_id();
@@ -786,7 +786,7 @@ fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
 /// When this is done, suggest using `Self` instead.
 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())) {
+        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),
                 _ => return,
@@ -796,18 +796,18 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem
     let mut trait_should_be_self = vec![];
     match &item.kind {
         hir::TraitItemKind::Const(ty, _) | hir::TraitItemKind::Type(_, Some(ty))
-            if could_be_self(trait_def_id, ty) =>
+            if could_be_self(trait_def_id.def_id, ty) =>
         {
             trait_should_be_self.push(ty.span)
         }
         hir::TraitItemKind::Fn(sig, _) => {
             for ty in sig.decl.inputs {
-                if could_be_self(trait_def_id, ty) {
+                if could_be_self(trait_def_id.def_id, ty) {
                     trait_should_be_self.push(ty.span);
                 }
             }
             match sig.decl.output {
-                hir::FnRetTy::Return(ty) if could_be_self(trait_def_id, ty) => {
+                hir::FnRetTy::Return(ty) if could_be_self(trait_def_id.def_id, ty) => {
                     trait_should_be_self.push(ty.span);
                 }
                 _ => {}
@@ -836,8 +836,6 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem
 }
 
 fn check_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) {
-    let def_id = impl_item.def_id;
-
     let (method_sig, span) = match impl_item.kind {
         hir::ImplItemKind::Fn(ref sig, _) => (Some(sig), impl_item.span),
         // Constrain binding and overflow error spans to `<Ty>` in `type foo = <Ty>`.
@@ -845,7 +843,7 @@ fn check_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) {
         _ => (None, impl_item.span),
     };
 
-    check_associated_item(tcx, def_id, span, method_sig);
+    check_associated_item(tcx, impl_item.def_id.def_id, span, method_sig);
 }
 
 fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
@@ -1045,7 +1043,7 @@ fn check_type_defn<'tcx, F>(
 ) where
     F: FnMut(&WfCheckingCtxt<'_, 'tcx>) -> Vec<AdtVariant<'tcx>>,
 {
-    enter_wf_checking_ctxt(tcx, item.span, item.def_id, |wfcx| {
+    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();
 
@@ -1124,7 +1122,7 @@ fn check_type_defn<'tcx, F>(
             }
         }
 
-        check_where_clauses(wfcx, item.span, item.def_id);
+        check_where_clauses(wfcx, item.span, item.def_id.def_id);
     });
 }
 
@@ -1132,11 +1130,12 @@ fn check_type_defn<'tcx, F>(
 fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
     debug!(?item.def_id);
 
-    let trait_def = tcx.trait_def(item.def_id);
+    let def_id = item.def_id.def_id;
+    let trait_def = tcx.trait_def(def_id);
     if trait_def.is_marker
         || matches!(trait_def.specialization_kind, TraitSpecializationKind::Marker)
     {
-        for associated_def_id in &*tcx.associated_item_def_ids(item.def_id) {
+        for associated_def_id in &*tcx.associated_item_def_ids(def_id) {
             struct_span_err!(
                 tcx.sess,
                 tcx.def_span(*associated_def_id),
@@ -1147,8 +1146,8 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
         }
     }
 
-    enter_wf_checking_ctxt(tcx, item.span, item.def_id, |wfcx| {
-        check_where_clauses(wfcx, item.span, item.def_id)
+    enter_wf_checking_ctxt(tcx, item.span, def_id, |wfcx| {
+        check_where_clauses(wfcx, item.span, def_id)
     });
 
     // Only check traits, don't check trait aliases
@@ -1242,7 +1241,7 @@ fn check_impl<'tcx>(
     ast_trait_ref: &Option<hir::TraitRef<'_>>,
     constness: hir::Constness,
 ) {
-    enter_wf_checking_ctxt(tcx, item.span, item.def_id, |wfcx| {
+    enter_wf_checking_ctxt(tcx, item.span, item.def_id.def_id, |wfcx| {
         match *ast_trait_ref {
             Some(ref ast_trait_ref) => {
                 // `#[rustc_reservation_impl]` impls are not real impls and
@@ -1273,18 +1272,18 @@ fn check_impl<'tcx>(
                 let self_ty = tcx.type_of(item.def_id);
                 let self_ty = wfcx.normalize(
                     item.span,
-                    Some(WellFormedLoc::Ty(item.hir_id().expect_owner())),
+                    Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
                     self_ty,
                 );
                 wfcx.register_wf_obligation(
                     ast_self_ty.span,
-                    Some(WellFormedLoc::Ty(item.hir_id().expect_owner())),
+                    Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
                     self_ty.into(),
                 );
             }
         }
 
-        check_where_clauses(wfcx, item.span, item.def_id);
+        check_where_clauses(wfcx, item.span, item.def_id.def_id);
     });
 }
 
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_hir_analysis/src/check/writeback.rs
index 680dbf7037f..680dbf7037f 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_hir_analysis/src/check/writeback.rs
diff --git a/compiler/rustc_typeck/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs
index 1d23ed92921..1d23ed92921 100644
--- a/compiler/rustc_typeck/src/check_unused.rs
+++ b/compiler/rustc_hir_analysis/src/check_unused.rs
diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index d08c0d4dbb7..d4eb826f0b4 100644
--- a/compiler/rustc_typeck/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -70,23 +70,21 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
     let self_type = tcx.type_of(impl_did);
     debug!("visit_implementation_of_copy: self_type={:?} (bound)", self_type);
 
-    let span = tcx.hir().span(impl_hir_id);
     let param_env = tcx.param_env(impl_did);
     assert!(!self_type.has_escaping_bound_vars());
 
     debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type);
 
+    let span = match tcx.hir().expect_item(impl_did).kind {
+        ItemKind::Impl(hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. }) => return,
+        ItemKind::Impl(impl_) => impl_.self_ty.span,
+        _ => bug!("expected Copy impl item"),
+    };
+
     let cause = traits::ObligationCause::misc(span, impl_hir_id);
     match can_type_implement_copy(tcx, param_env, self_type, cause) {
         Ok(()) => {}
         Err(CopyImplementationError::InfrigingFields(fields)) => {
-            let item = tcx.hir().expect_item(impl_did);
-            let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(ref tr), .. }) = item.kind {
-                tr.path.span
-            } else {
-                span
-            };
-
             let mut err = struct_span_err!(
                 tcx.sess,
                 span,
@@ -166,10 +164,6 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
             err.emit();
         }
         Err(CopyImplementationError::NotAnAdt) => {
-            let item = tcx.hir().expect_item(impl_did);
-            let span =
-                if let ItemKind::Impl(ref impl_) = item.kind { impl_.self_ty.span } else { span };
-
             tcx.sess.emit_err(CopyImplOnNonAdt { span });
         }
         Err(CopyImplementationError::HasDestructor) => {
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index 52aad636fd8..308ad5d5fc2 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -105,7 +105,7 @@ impl<'tcx> InherentCollect<'tcx> {
             }
 
             if let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsInfer) {
-                self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
+                self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id.def_id);
             } else {
                 bug!("unexpected self type: {:?}", self_ty);
             }
@@ -220,7 +220,9 @@ impl<'tcx> InherentCollect<'tcx> {
             | ty::Ref(..)
             | ty::Never
             | ty::FnPtr(_)
-            | ty::Tuple(..) => self.check_primitive_impl(item.def_id, self_ty, items, ty.span),
+            | ty::Tuple(..) => {
+                self.check_primitive_impl(item.def_id.def_id, self_ty, items, ty.span)
+            }
             ty::Projection(..) | ty::Opaque(..) | ty::Param(_) => {
                 let mut err = struct_span_err!(
                     self.tcx.sess,
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
index 03e076bf5ec..03e076bf5ec 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
diff --git a/compiler/rustc_typeck/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs
index ae9ebe59091..ae9ebe59091 100644
--- a/compiler/rustc_typeck/src/coherence/mod.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs
diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 87961890f53..7d15e5a7f3c 100644
--- a/compiler/rustc_typeck/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -42,7 +42,7 @@ fn do_orphan_check_impl<'tcx>(
 ) -> Result<(), ErrorGuaranteed> {
     let trait_def_id = trait_ref.def_id;
 
-    let item = tcx.hir().item(hir::ItemId { def_id });
+    let item = tcx.hir().expect_item(def_id);
     let hir::ItemKind::Impl(ref impl_) = item.kind else {
         bug!("{:?} is not an impl: {:?}", def_id, item);
     };
diff --git a/compiler/rustc_typeck/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
index e45fb5fe41c..e45fb5fe41c 100644
--- a/compiler/rustc_typeck/src/coherence/unsafety.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 359a79e9979..8cd0a84274e 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -15,46 +15,40 @@
 //! crate as a kind of pass. This should eventually be factored away.
 
 use crate::astconv::AstConv;
-use crate::bounds::Bounds;
 use crate::check::intrinsic::intrinsic_operation_unsafety;
-use crate::constrained_generic_params as cgp;
 use crate::errors;
-use crate::middle::resolve_lifetime as rl;
 use rustc_ast as ast;
 use rustc_ast::{MetaItemKind, NestedMetaItem};
 use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
 use rustc_data_structures::captures::Captures;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey};
 use rustc_hir as hir;
-use rustc_hir::def::{CtorKind, DefKind};
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
+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, HirId, Node};
+use rustc_hir::{GenericParamKind, Node};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc_middle::mir::mono::Linkage;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::subst::InternalSubsts;
-use rustc_middle::ty::util::Discr;
-use rustc_middle::ty::util::IntTypeExt;
+use rustc_middle::ty::util::{Discr, IntTypeExt};
+use rustc_middle::ty::ReprOptions;
 use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, IsSuggestable, Ty, TyCtxt};
-use rustc_middle::ty::{ReprOptions, ToPredicate};
 use rustc_session::lint;
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::Span;
 use rustc_target::spec::{abi, SanitizerSet};
 use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
 use std::iter;
 
+mod generics_of;
 mod item_bounds;
+mod predicates_of;
 mod type_of;
 
-#[derive(Debug)]
-struct OnlySelfBounds(bool);
-
 ///////////////////////////////////////////////////////////////////////////
 // Main entry point
 
@@ -68,14 +62,15 @@ pub fn provide(providers: &mut Providers) {
         type_of: type_of::type_of,
         item_bounds: item_bounds::item_bounds,
         explicit_item_bounds: item_bounds::explicit_item_bounds,
-        generics_of,
-        predicates_of,
+        generics_of: generics_of::generics_of,
+        predicates_of: predicates_of::predicates_of,
         predicates_defined_on,
-        explicit_predicates_of,
-        super_predicates_of,
-        super_predicates_that_define_assoc_type,
-        trait_explicit_predicates_and_bounds,
-        type_param_predicates,
+        explicit_predicates_of: predicates_of::explicit_predicates_of,
+        super_predicates_of: predicates_of::super_predicates_of,
+        super_predicates_that_define_assoc_type:
+            predicates_of::super_predicates_that_define_assoc_type,
+        trait_explicit_predicates_and_bounds: predicates_of::trait_explicit_predicates_and_bounds,
+        type_param_predicates: predicates_of::type_param_predicates,
         trait_def,
         adt_def,
         fn_sig,
@@ -430,7 +425,6 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
         if let Some(trait_ref) = poly_trait_ref.no_bound_vars() {
             let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item(
                 self,
-                self.tcx,
                 span,
                 item_def_id,
                 item_segment,
@@ -449,8 +443,10 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
 
             match self.node() {
                 hir::Node::Field(_) | hir::Node::Ctor(_) | hir::Node::Variant(_) => {
-                    let item =
-                        self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(self.hir_id()));
+                    let item = self
+                        .tcx
+                        .hir()
+                        .expect_item(self.tcx.hir().get_parent_item(self.hir_id()).def_id);
                     match &item.kind {
                         hir::ItemKind::Enum(_, generics)
                         | hir::ItemKind::Struct(_, generics)
@@ -571,164 +567,10 @@ fn get_new_lifetime_name<'tcx>(
     (1..).flat_map(a_to_z_repeat_n).find(|lt| !existing_lifetimes.contains(lt.as_str())).unwrap()
 }
 
-/// Returns the predicates defined on `item_def_id` of the form
-/// `X: Foo` where `X` is the type parameter `def_id`.
-#[instrument(level = "trace", skip(tcx))]
-fn type_param_predicates(
-    tcx: TyCtxt<'_>,
-    (item_def_id, def_id, assoc_name): (DefId, LocalDefId, Ident),
-) -> ty::GenericPredicates<'_> {
-    use rustc_hir::*;
-
-    // In the AST, bounds can derive from two places. Either
-    // written inline like `<T: Foo>` or in a where-clause like
-    // `where T: Foo`.
-
-    let param_id = tcx.hir().local_def_id_to_hir_id(def_id);
-    let param_owner = tcx.hir().ty_param_owner(def_id);
-    let generics = tcx.generics_of(param_owner);
-    let index = generics.param_def_id_to_index[&def_id.to_def_id()];
-    let ty = tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id));
-
-    // Don't look for bounds where the type parameter isn't in scope.
-    let parent = if item_def_id == param_owner.to_def_id() {
-        None
-    } else {
-        tcx.generics_of(item_def_id).parent
-    };
-
-    let mut result = parent
-        .map(|parent| {
-            let icx = ItemCtxt::new(tcx, parent);
-            icx.get_type_parameter_bounds(DUMMY_SP, def_id.to_def_id(), assoc_name)
-        })
-        .unwrap_or_default();
-    let mut extend = None;
-
-    let item_hir_id = tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local());
-    let ast_generics = match tcx.hir().get(item_hir_id) {
-        Node::TraitItem(item) => &item.generics,
-
-        Node::ImplItem(item) => &item.generics,
-
-        Node::Item(item) => {
-            match item.kind {
-                ItemKind::Fn(.., ref generics, _)
-                | ItemKind::Impl(hir::Impl { ref generics, .. })
-                | ItemKind::TyAlias(_, ref generics)
-                | ItemKind::OpaqueTy(OpaqueTy {
-                    ref generics,
-                    origin: hir::OpaqueTyOrigin::TyAlias,
-                    ..
-                })
-                | ItemKind::Enum(_, ref generics)
-                | ItemKind::Struct(_, ref generics)
-                | ItemKind::Union(_, ref generics) => generics,
-                ItemKind::Trait(_, _, ref generics, ..) => {
-                    // Implied `Self: Trait` and supertrait bounds.
-                    if param_id == item_hir_id {
-                        let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id);
-                        extend =
-                            Some((identity_trait_ref.without_const().to_predicate(tcx), item.span));
-                    }
-                    generics
-                }
-                _ => return result,
-            }
-        }
-
-        Node::ForeignItem(item) => match item.kind {
-            ForeignItemKind::Fn(_, _, ref generics) => generics,
-            _ => return result,
-        },
-
-        _ => return result,
-    };
-
-    let icx = ItemCtxt::new(tcx, item_def_id);
-    let extra_predicates = extend.into_iter().chain(
-        icx.type_parameter_bounds_in_generics(
-            ast_generics,
-            param_id,
-            ty,
-            OnlySelfBounds(true),
-            Some(assoc_name),
-        )
-        .into_iter()
-        .filter(|(predicate, _)| match predicate.kind().skip_binder() {
-            ty::PredicateKind::Trait(data) => data.self_ty().is_param(index),
-            _ => false,
-        }),
-    );
-    result.predicates =
-        tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(extra_predicates));
-    result
-}
-
-impl<'tcx> ItemCtxt<'tcx> {
-    /// Finds bounds from `hir::Generics`. This requires scanning through the
-    /// AST. We do this to avoid having to convert *all* the bounds, which
-    /// would create artificial cycles. Instead, we can only convert the
-    /// bounds for a type parameter `X` if `X::Foo` is used.
-    #[instrument(level = "trace", skip(self, ast_generics))]
-    fn type_parameter_bounds_in_generics(
-        &self,
-        ast_generics: &'tcx hir::Generics<'tcx>,
-        param_id: hir::HirId,
-        ty: Ty<'tcx>,
-        only_self_bounds: OnlySelfBounds,
-        assoc_name: Option<Ident>,
-    ) -> Vec<(ty::Predicate<'tcx>, Span)> {
-        let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id();
-        trace!(?param_def_id);
-        ast_generics
-            .predicates
-            .iter()
-            .filter_map(|wp| match *wp {
-                hir::WherePredicate::BoundPredicate(ref bp) => Some(bp),
-                _ => None,
-            })
-            .flat_map(|bp| {
-                let bt = if bp.is_param_bound(param_def_id) {
-                    Some(ty)
-                } else if !only_self_bounds.0 {
-                    Some(self.to_ty(bp.bounded_ty))
-                } else {
-                    None
-                };
-                let bvars = self.tcx.late_bound_vars(bp.bounded_ty.hir_id);
-
-                bp.bounds.iter().filter_map(move |b| bt.map(|bt| (bt, b, bvars))).filter(
-                    |(_, b, _)| match assoc_name {
-                        Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
-                        None => true,
-                    },
-                )
-            })
-            .flat_map(|(bt, b, bvars)| predicates_from_bound(self, bt, b, bvars))
-            .collect()
-    }
-
-    #[instrument(level = "trace", skip(self))]
-    fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool {
-        match b {
-            hir::GenericBound::Trait(poly_trait_ref, _) => {
-                let trait_ref = &poly_trait_ref.trait_ref;
-                if let Some(trait_did) = trait_ref.trait_def_id() {
-                    self.tcx.trait_may_define_assoc_type(trait_did, assoc_name)
-                } else {
-                    false
-                }
-            }
-            _ => false,
-        }
-    }
-}
-
 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;
+    let def_id = item_id.def_id.def_id;
 
     match it.kind {
         // These don't define types.
@@ -840,20 +682,21 @@ 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);
-    tcx.ensure().generics_of(trait_item_id.def_id);
+    let def_id = trait_item_id.def_id;
+    tcx.ensure().generics_of(def_id);
 
     match trait_item.kind {
         hir::TraitItemKind::Fn(..) => {
-            tcx.ensure().type_of(trait_item_id.def_id);
-            tcx.ensure().fn_sig(trait_item_id.def_id);
+            tcx.ensure().type_of(def_id);
+            tcx.ensure().fn_sig(def_id);
         }
 
         hir::TraitItemKind::Const(.., Some(_)) => {
-            tcx.ensure().type_of(trait_item_id.def_id);
+            tcx.ensure().type_of(def_id);
         }
 
         hir::TraitItemKind::Const(hir_ty, _) => {
-            tcx.ensure().type_of(trait_item_id.def_id);
+            tcx.ensure().type_of(def_id);
             // Account for `const C: _;`.
             let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_trait_item(trait_item);
@@ -863,8 +706,8 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
         }
 
         hir::TraitItemKind::Type(_, Some(_)) => {
-            tcx.ensure().item_bounds(trait_item_id.def_id);
-            tcx.ensure().type_of(trait_item_id.def_id);
+            tcx.ensure().item_bounds(def_id);
+            tcx.ensure().type_of(def_id);
             // Account for `type T = _;`.
             let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_trait_item(trait_item);
@@ -872,7 +715,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
         }
 
         hir::TraitItemKind::Type(_, None) => {
-            tcx.ensure().item_bounds(trait_item_id.def_id);
+            tcx.ensure().item_bounds(def_id);
             // #74612: Visit and try to find bad placeholders
             // even if there is no concrete type.
             let mut visitor = HirPlaceholderCollector::default();
@@ -882,7 +725,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
         }
     };
 
-    tcx.ensure().predicates_of(trait_item_id.def_id);
+    tcx.ensure().predicates_of(def_id);
 }
 
 fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
@@ -1095,96 +938,6 @@ fn adt_def<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::AdtDef<'tcx> {
     tcx.alloc_adt_def(def_id.to_def_id(), kind, variants, repr)
 }
 
-/// Ensures that the super-predicates of the trait with a `DefId`
-/// of `trait_def_id` are converted and stored. This also ensures that
-/// the transitive super-predicates are converted.
-fn super_predicates_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> ty::GenericPredicates<'_> {
-    debug!("super_predicates(trait_def_id={:?})", trait_def_id);
-    tcx.super_predicates_that_define_assoc_type((trait_def_id, None))
-}
-
-/// Ensures that the super-predicates of the trait with a `DefId`
-/// of `trait_def_id` are converted and stored. This also ensures that
-/// the transitive super-predicates are converted.
-fn super_predicates_that_define_assoc_type(
-    tcx: TyCtxt<'_>,
-    (trait_def_id, assoc_name): (DefId, Option<Ident>),
-) -> ty::GenericPredicates<'_> {
-    debug!(
-        "super_predicates_that_define_assoc_type(trait_def_id={:?}, assoc_name={:?})",
-        trait_def_id, assoc_name
-    );
-    if trait_def_id.is_local() {
-        debug!("super_predicates_that_define_assoc_type: local trait_def_id={:?}", trait_def_id);
-        let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id.expect_local());
-
-        let Node::Item(item) = tcx.hir().get(trait_hir_id) else {
-            bug!("trait_node_id {} is not an item", trait_hir_id);
-        };
-
-        let (generics, bounds) = match item.kind {
-            hir::ItemKind::Trait(.., ref generics, ref supertraits, _) => (generics, supertraits),
-            hir::ItemKind::TraitAlias(ref generics, ref supertraits) => (generics, supertraits),
-            _ => span_bug!(item.span, "super_predicates invoked on non-trait"),
-        };
-
-        let icx = ItemCtxt::new(tcx, trait_def_id);
-
-        // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`.
-        let self_param_ty = tcx.types.self_param;
-        let superbounds1 = if let Some(assoc_name) = assoc_name {
-            <dyn AstConv<'_>>::compute_bounds_that_match_assoc_type(
-                &icx,
-                self_param_ty,
-                bounds,
-                assoc_name,
-            )
-        } else {
-            <dyn AstConv<'_>>::compute_bounds(&icx, self_param_ty, bounds)
-        };
-
-        let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
-
-        // Convert any explicit superbounds in the where-clause,
-        // e.g., `trait Foo where Self: Bar`.
-        // In the case of trait aliases, however, we include all bounds in the where-clause,
-        // so e.g., `trait Foo = where u32: PartialEq<Self>` would include `u32: PartialEq<Self>`
-        // as one of its "superpredicates".
-        let is_trait_alias = tcx.is_trait_alias(trait_def_id);
-        let superbounds2 = icx.type_parameter_bounds_in_generics(
-            generics,
-            item.hir_id(),
-            self_param_ty,
-            OnlySelfBounds(!is_trait_alias),
-            assoc_name,
-        );
-
-        // Combine the two lists to form the complete set of superbounds:
-        let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2));
-        debug!(?superbounds);
-
-        // Now require that immediate supertraits are converted,
-        // which will, in turn, reach indirect supertraits.
-        if assoc_name.is_none() {
-            // Now require that immediate supertraits are converted,
-            // which will, in turn, reach indirect supertraits.
-            for &(pred, span) in superbounds {
-                debug!("superbound: {:?}", pred);
-                if let ty::PredicateKind::Trait(bound) = pred.kind().skip_binder() {
-                    tcx.at(span).super_predicates_of(bound.def_id());
-                }
-            }
-        }
-
-        ty::GenericPredicates { parent: None, predicates: superbounds }
-    } else {
-        // if `assoc_name` is None, then the query should've been redirected to an
-        // external provider
-        assert!(assoc_name.is_some());
-        tcx.super_predicates_of(trait_def_id)
-    }
-}
-
 fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
     let item = tcx.hir().expect_item(def_id.expect_local());
 
@@ -1326,475 +1079,6 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
     )
 }
 
-fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<Span> {
-    struct LateBoundRegionsDetector<'tcx> {
-        tcx: TyCtxt<'tcx>,
-        outer_index: ty::DebruijnIndex,
-        has_late_bound_regions: Option<Span>,
-    }
-
-    impl<'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'tcx> {
-        fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
-            if self.has_late_bound_regions.is_some() {
-                return;
-            }
-            match ty.kind {
-                hir::TyKind::BareFn(..) => {
-                    self.outer_index.shift_in(1);
-                    intravisit::walk_ty(self, ty);
-                    self.outer_index.shift_out(1);
-                }
-                _ => intravisit::walk_ty(self, ty),
-            }
-        }
-
-        fn visit_poly_trait_ref(&mut self, tr: &'tcx hir::PolyTraitRef<'tcx>) {
-            if self.has_late_bound_regions.is_some() {
-                return;
-            }
-            self.outer_index.shift_in(1);
-            intravisit::walk_poly_trait_ref(self, tr);
-            self.outer_index.shift_out(1);
-        }
-
-        fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
-            if self.has_late_bound_regions.is_some() {
-                return;
-            }
-
-            match self.tcx.named_region(lt.hir_id) {
-                Some(rl::Region::Static | rl::Region::EarlyBound(..)) => {}
-                Some(rl::Region::LateBound(debruijn, _, _)) if debruijn < self.outer_index => {}
-                Some(rl::Region::LateBound(..) | rl::Region::Free(..)) | None => {
-                    self.has_late_bound_regions = Some(lt.span);
-                }
-            }
-        }
-    }
-
-    fn has_late_bound_regions<'tcx>(
-        tcx: TyCtxt<'tcx>,
-        generics: &'tcx hir::Generics<'tcx>,
-        decl: &'tcx hir::FnDecl<'tcx>,
-    ) -> Option<Span> {
-        let mut visitor = LateBoundRegionsDetector {
-            tcx,
-            outer_index: ty::INNERMOST,
-            has_late_bound_regions: None,
-        };
-        for param in generics.params {
-            if let GenericParamKind::Lifetime { .. } = param.kind {
-                if tcx.is_late_bound(param.hir_id) {
-                    return Some(param.span);
-                }
-            }
-        }
-        visitor.visit_fn_decl(decl);
-        visitor.has_late_bound_regions
-    }
-
-    match node {
-        Node::TraitItem(item) => match item.kind {
-            hir::TraitItemKind::Fn(ref sig, _) => {
-                has_late_bound_regions(tcx, &item.generics, sig.decl)
-            }
-            _ => None,
-        },
-        Node::ImplItem(item) => match item.kind {
-            hir::ImplItemKind::Fn(ref sig, _) => {
-                has_late_bound_regions(tcx, &item.generics, sig.decl)
-            }
-            _ => None,
-        },
-        Node::ForeignItem(item) => match item.kind {
-            hir::ForeignItemKind::Fn(fn_decl, _, ref generics) => {
-                has_late_bound_regions(tcx, generics, fn_decl)
-            }
-            _ => None,
-        },
-        Node::Item(item) => match item.kind {
-            hir::ItemKind::Fn(ref sig, .., ref generics, _) => {
-                has_late_bound_regions(tcx, generics, sig.decl)
-            }
-            _ => None,
-        },
-        _ => None,
-    }
-}
-
-struct AnonConstInParamTyDetector {
-    in_param_ty: bool,
-    found_anon_const_in_param_ty: bool,
-    ct: HirId,
-}
-
-impl<'v> Visitor<'v> for AnonConstInParamTyDetector {
-    fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) {
-        if let GenericParamKind::Const { ty, default: _ } = p.kind {
-            let prev = self.in_param_ty;
-            self.in_param_ty = true;
-            self.visit_ty(ty);
-            self.in_param_ty = prev;
-        }
-    }
-
-    fn visit_anon_const(&mut self, c: &'v hir::AnonConst) {
-        if self.in_param_ty && self.ct == c.hir_id {
-            self.found_anon_const_in_param_ty = true;
-        } else {
-            intravisit::walk_anon_const(self, c)
-        }
-    }
-}
-
-fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
-    use rustc_hir::*;
-
-    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-
-    let node = tcx.hir().get(hir_id);
-    let parent_def_id = match node {
-        Node::ImplItem(_)
-        | Node::TraitItem(_)
-        | Node::Variant(_)
-        | Node::Ctor(..)
-        | Node::Field(_) => {
-            let parent_id = tcx.hir().get_parent_item(hir_id);
-            Some(parent_id.to_def_id())
-        }
-        // FIXME(#43408) always enable this once `lazy_normalization` is
-        // stable enough and does not need a feature gate anymore.
-        Node::AnonConst(_) => {
-            let parent_def_id = tcx.hir().get_parent_item(hir_id);
-
-            let mut in_param_ty = false;
-            for (_parent, node) in tcx.hir().parent_iter(hir_id) {
-                if let Some(generics) = node.generics() {
-                    let mut visitor = AnonConstInParamTyDetector {
-                        in_param_ty: false,
-                        found_anon_const_in_param_ty: false,
-                        ct: hir_id,
-                    };
-
-                    visitor.visit_generics(generics);
-                    in_param_ty = visitor.found_anon_const_in_param_ty;
-                    break;
-                }
-            }
-
-            if in_param_ty {
-                // We do not allow generic parameters in anon consts if we are inside
-                // of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
-                None
-            } else if tcx.lazy_normalization() {
-                if let Some(param_id) = tcx.hir().opt_const_param_default_param_hir_id(hir_id) {
-                    // If the def_id we are calling generics_of on is an anon ct default i.e:
-                    //
-                    // struct Foo<const N: usize = { .. }>;
-                    //        ^^^       ^          ^^^^^^ def id of this anon const
-                    //        ^         ^ param_id
-                    //        ^ parent_def_id
-                    //
-                    // then we only want to return generics for params to the left of `N`. If we don't do that we
-                    // end up with that const looking like: `ty::ConstKind::Unevaluated(def_id, substs: [N#0])`.
-                    //
-                    // This causes ICEs (#86580) when building the substs for Foo in `fn foo() -> Foo { .. }` as
-                    // we substitute the defaults with the partially built substs when we build the substs. Subst'ing
-                    // the `N#0` on the unevaluated const indexes into the empty substs we're in the process of building.
-                    //
-                    // We fix this by having this function return the parent's generics ourselves and truncating the
-                    // generics to only include non-forward declared params (with the exception of the `Self` ty)
-                    //
-                    // For the above code example that means we want `substs: []`
-                    // For the following struct def we want `substs: [N#0]` when generics_of is called on
-                    // the def id of the `{ N + 1 }` anon const
-                    // struct Foo<const N: usize, const M: usize = { N + 1 }>;
-                    //
-                    // This has some implications for how we get the predicates available to the anon const
-                    // see `explicit_predicates_of` for more information on this
-                    let generics = tcx.generics_of(parent_def_id.to_def_id());
-                    let param_def = tcx.hir().local_def_id(param_id).to_def_id();
-                    let param_def_idx = generics.param_def_id_to_index[&param_def];
-                    // In the above example this would be .params[..N#0]
-                    let params = generics.params[..param_def_idx as usize].to_owned();
-                    let param_def_id_to_index =
-                        params.iter().map(|param| (param.def_id, param.index)).collect();
-
-                    return ty::Generics {
-                        // we set the parent of these generics to be our parent's parent so that we
-                        // dont end up with substs: [N, M, N] for the const default on a struct like this:
-                        // struct Foo<const N: usize, const M: usize = { ... }>;
-                        parent: generics.parent,
-                        parent_count: generics.parent_count,
-                        params,
-                        param_def_id_to_index,
-                        has_self: generics.has_self,
-                        has_late_bound_regions: generics.has_late_bound_regions,
-                    };
-                }
-
-                // HACK(eddyb) this provides the correct generics when
-                // `feature(generic_const_expressions)` is enabled, so that const expressions
-                // used with const generics, e.g. `Foo<{N+1}>`, can work at all.
-                //
-                // Note that we do not supply the parent generics when using
-                // `min_const_generics`.
-                Some(parent_def_id.to_def_id())
-            } else {
-                let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
-                match parent_node {
-                    // HACK(eddyb) this provides the correct generics for repeat
-                    // expressions' count (i.e. `N` in `[x; N]`), and explicit
-                    // `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`),
-                    // as they shouldn't be able to cause query cycle errors.
-                    Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
-                        if constant.hir_id() == hir_id =>
-                    {
-                        Some(parent_def_id.to_def_id())
-                    }
-                    Node::Variant(Variant { disr_expr: Some(ref constant), .. })
-                        if constant.hir_id == hir_id =>
-                    {
-                        Some(parent_def_id.to_def_id())
-                    }
-                    Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => {
-                        Some(tcx.typeck_root_def_id(def_id))
-                    }
-                    // Exclude `GlobalAsm` here which cannot have generics.
-                    Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
-                        if asm.operands.iter().any(|(op, _op_sp)| match op {
-                            hir::InlineAsmOperand::Const { anon_const }
-                            | hir::InlineAsmOperand::SymFn { anon_const } => {
-                                anon_const.hir_id == hir_id
-                            }
-                            _ => false,
-                        }) =>
-                    {
-                        Some(parent_def_id.to_def_id())
-                    }
-                    _ => None,
-                }
-            }
-        }
-        Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => {
-            Some(tcx.typeck_root_def_id(def_id))
-        }
-        Node::Item(item) => match item.kind {
-            ItemKind::OpaqueTy(hir::OpaqueTy {
-                origin:
-                    hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
-                in_trait,
-                ..
-            }) => {
-                if in_trait {
-                    assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn))
-                } else {
-                    assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn))
-                }
-                Some(fn_def_id.to_def_id())
-            }
-            ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
-                let parent_id = tcx.hir().get_parent_item(hir_id);
-                assert_ne!(parent_id, CRATE_DEF_ID);
-                debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent_id);
-                // Opaque types are always nested within another item, and
-                // inherit the generics of the item.
-                Some(parent_id.to_def_id())
-            }
-            _ => None,
-        },
-        _ => None,
-    };
-
-    enum Defaults {
-        Allowed,
-        // See #36887
-        FutureCompatDisallowed,
-        Deny,
-    }
-
-    let no_generics = hir::Generics::empty();
-    let ast_generics = node.generics().unwrap_or(&no_generics);
-    let (opt_self, allow_defaults) = match node {
-        Node::Item(item) => {
-            match item.kind {
-                ItemKind::Trait(..) | ItemKind::TraitAlias(..) => {
-                    // Add in the self type parameter.
-                    //
-                    // Something of a hack: use the node id for the trait, also as
-                    // the node id for the Self type parameter.
-                    let opt_self = Some(ty::GenericParamDef {
-                        index: 0,
-                        name: kw::SelfUpper,
-                        def_id,
-                        pure_wrt_drop: false,
-                        kind: ty::GenericParamDefKind::Type {
-                            has_default: false,
-                            synthetic: false,
-                        },
-                    });
-
-                    (opt_self, Defaults::Allowed)
-                }
-                ItemKind::TyAlias(..)
-                | ItemKind::Enum(..)
-                | ItemKind::Struct(..)
-                | ItemKind::OpaqueTy(..)
-                | ItemKind::Union(..) => (None, Defaults::Allowed),
-                _ => (None, Defaults::FutureCompatDisallowed),
-            }
-        }
-
-        // GATs
-        Node::TraitItem(item) if matches!(item.kind, TraitItemKind::Type(..)) => {
-            (None, Defaults::Deny)
-        }
-        Node::ImplItem(item) if matches!(item.kind, ImplItemKind::TyAlias(..)) => {
-            (None, Defaults::Deny)
-        }
-
-        _ => (None, Defaults::FutureCompatDisallowed),
-    };
-
-    let has_self = opt_self.is_some();
-    let mut parent_has_self = false;
-    let mut own_start = has_self as u32;
-    let parent_count = parent_def_id.map_or(0, |def_id| {
-        let generics = tcx.generics_of(def_id);
-        assert!(!has_self);
-        parent_has_self = generics.has_self;
-        own_start = generics.count() as u32;
-        generics.parent_count + generics.params.len()
-    });
-
-    let mut params: Vec<_> = Vec::with_capacity(ast_generics.params.len() + has_self as usize);
-
-    if let Some(opt_self) = opt_self {
-        params.push(opt_self);
-    }
-
-    let early_lifetimes = early_bound_lifetimes_from_generics(tcx, ast_generics);
-    params.extend(early_lifetimes.enumerate().map(|(i, param)| ty::GenericParamDef {
-        name: param.name.ident().name,
-        index: own_start + i as u32,
-        def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
-        pure_wrt_drop: param.pure_wrt_drop,
-        kind: ty::GenericParamDefKind::Lifetime,
-    }));
-
-    // 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;
-
-    const TYPE_DEFAULT_NOT_ALLOWED: &'static str = "defaults for type parameters are only allowed in \
-    `struct`, `enum`, `type`, or `trait` definitions";
-
-    params.extend(ast_generics.params.iter().filter_map(|param| match param.kind {
-        GenericParamKind::Lifetime { .. } => None,
-        GenericParamKind::Type { ref default, synthetic, .. } => {
-            if default.is_some() {
-                match allow_defaults {
-                    Defaults::Allowed => {}
-                    Defaults::FutureCompatDisallowed
-                        if tcx.features().default_type_parameter_fallback => {}
-                    Defaults::FutureCompatDisallowed => {
-                        tcx.struct_span_lint_hir(
-                            lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
-                            param.hir_id,
-                            param.span,
-                            |lint| {
-                                lint.build(TYPE_DEFAULT_NOT_ALLOWED).emit();
-                            },
-                        );
-                    }
-                    Defaults::Deny => {
-                        tcx.sess.span_err(param.span, TYPE_DEFAULT_NOT_ALLOWED);
-                    }
-                }
-            }
-
-            let kind = ty::GenericParamDefKind::Type { has_default: default.is_some(), synthetic };
-
-            let param_def = ty::GenericParamDef {
-                index: type_start + i as u32,
-                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() {
-                tcx.sess.span_err(
-                    param.span,
-                    "defaults for const parameters are only allowed in \
-                    `struct`, `enum`, `type`, or `trait` definitions",
-                );
-            }
-
-            let param_def = ty::GenericParamDef {
-                index: type_start + i as u32,
-                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)
-        }
-    }));
-
-    // provide junk type parameter defs - the only place that
-    // cares about anything but the length is instantiation,
-    // and we don't do that for closures.
-    if let Node::Expr(&hir::Expr {
-        kind: hir::ExprKind::Closure(hir::Closure { movability: gen, .. }),
-        ..
-    }) = node
-    {
-        let dummy_args = if gen.is_some() {
-            &["<resume_ty>", "<yield_ty>", "<return_ty>", "<witness>", "<upvars>"][..]
-        } else {
-            &["<closure_kind>", "<closure_signature>", "<upvars>"][..]
-        };
-
-        params.extend(dummy_args.iter().enumerate().map(|(i, &arg)| ty::GenericParamDef {
-            index: type_start + i as u32,
-            name: Symbol::intern(arg),
-            def_id,
-            pure_wrt_drop: false,
-            kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
-        }));
-    }
-
-    // provide junk type parameter defs for const blocks.
-    if let Node::AnonConst(_) = node {
-        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,
-                name: Symbol::intern("<const_ty>"),
-                def_id,
-                pure_wrt_drop: false,
-                kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
-            });
-        }
-    }
-
-    let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect();
-
-    ty::Generics {
-        parent: parent_def_id,
-        parent_count,
-        params,
-        param_def_id_to_index,
-        has_self: has_self || parent_has_self,
-        has_late_bound_regions: has_late_bound_regions(tcx, node),
-    }
-}
-
 fn are_suggestable_generic_args(generic_args: &[hir::GenericArg<'_>]) -> bool {
     generic_args.iter().any(|arg| match arg {
         hir::GenericArg::Type(ty) => is_suggestable_infer_ty(ty),
@@ -2091,450 +1375,6 @@ fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicate
     result
 }
 
-/// Returns a list of all type predicates (explicit and implicit) for the definition with
-/// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus
-/// `Self: Trait` predicates for traits.
-fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
-    let mut result = tcx.predicates_defined_on(def_id);
-
-    if tcx.is_trait(def_id) {
-        // For traits, add `Self: Trait` predicate. This is
-        // not part of the predicates that a user writes, but it
-        // is something that one must prove in order to invoke a
-        // method or project an associated type.
-        //
-        // In the chalk setup, this predicate is not part of the
-        // "predicates" for a trait item. But it is useful in
-        // rustc because if you directly (e.g.) invoke a trait
-        // method like `Trait::method(...)`, you must naturally
-        // prove that the trait applies to the types that were
-        // used, and adding the predicate into this list ensures
-        // that this is done.
-        //
-        // We use a DUMMY_SP here as a way to signal trait bounds that come
-        // from the trait itself that *shouldn't* be shown as the source of
-        // an obligation and instead be skipped. Otherwise we'd use
-        // `tcx.def_span(def_id);`
-
-        let constness = if tcx.has_attr(def_id, sym::const_trait) {
-            ty::BoundConstness::ConstIfConst
-        } else {
-            ty::BoundConstness::NotConst
-        };
-
-        let span = rustc_span::DUMMY_SP;
-        result.predicates =
-            tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once((
-                ty::TraitRef::identity(tcx, def_id).with_constness(constness).to_predicate(tcx),
-                span,
-            ))));
-    }
-    debug!("predicates_of(def_id={:?}) = {:?}", def_id, result);
-    result
-}
-
-/// Returns a list of user-specified type predicates for the definition with ID `def_id`.
-/// N.B., this does not include any implied/inferred constraints.
-#[instrument(level = "trace", skip(tcx), ret)]
-fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
-    use rustc_hir::*;
-
-    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-    let node = tcx.hir().get(hir_id);
-
-    let mut is_trait = None;
-    let mut is_default_impl_trait = None;
-
-    let icx = ItemCtxt::new(tcx, def_id);
-
-    const NO_GENERICS: &hir::Generics<'_> = hir::Generics::empty();
-
-    // We use an `IndexSet` to preserves order of insertion.
-    // Preserving the order of insertion is important here so as not to break UI tests.
-    let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default();
-
-    let ast_generics = match node {
-        Node::TraitItem(item) => item.generics,
-
-        Node::ImplItem(item) => item.generics,
-
-        Node::Item(item) => {
-            match item.kind {
-                ItemKind::Impl(ref impl_) => {
-                    if impl_.defaultness.is_default() {
-                        is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy);
-                    }
-                    &impl_.generics
-                }
-                ItemKind::Fn(.., ref generics, _)
-                | ItemKind::TyAlias(_, ref generics)
-                | ItemKind::Enum(_, ref generics)
-                | ItemKind::Struct(_, ref generics)
-                | ItemKind::Union(_, ref generics) => *generics,
-
-                ItemKind::Trait(_, _, ref generics, ..) => {
-                    is_trait = Some(ty::TraitRef::identity(tcx, def_id));
-                    *generics
-                }
-                ItemKind::TraitAlias(ref generics, _) => {
-                    is_trait = Some(ty::TraitRef::identity(tcx, def_id));
-                    *generics
-                }
-                ItemKind::OpaqueTy(OpaqueTy {
-                    origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
-                    ..
-                }) => {
-                    // return-position impl trait
-                    //
-                    // We don't inherit predicates from the parent here:
-                    // If we have, say `fn f<'a, T: 'a>() -> impl Sized {}`
-                    // then the return type is `f::<'static, T>::{{opaque}}`.
-                    //
-                    // If we inherited the predicates of `f` then we would
-                    // require that `T: 'static` to show that the return
-                    // type is well-formed.
-                    //
-                    // The only way to have something with this opaque type
-                    // is from the return type of the containing function,
-                    // which will ensure that the function's predicates
-                    // hold.
-                    return ty::GenericPredicates { parent: None, predicates: &[] };
-                }
-                ItemKind::OpaqueTy(OpaqueTy {
-                    ref generics,
-                    origin: hir::OpaqueTyOrigin::TyAlias,
-                    ..
-                }) => {
-                    // type-alias impl trait
-                    generics
-                }
-
-                _ => NO_GENERICS,
-            }
-        }
-
-        Node::ForeignItem(item) => match item.kind {
-            ForeignItemKind::Static(..) => NO_GENERICS,
-            ForeignItemKind::Fn(_, _, ref generics) => *generics,
-            ForeignItemKind::Type => NO_GENERICS,
-        },
-
-        _ => NO_GENERICS,
-    };
-
-    let generics = tcx.generics_of(def_id);
-    let parent_count = generics.parent_count as u32;
-    let has_own_self = generics.has_self && parent_count == 0;
-
-    // Below we'll consider the bounds on the type parameters (including `Self`)
-    // and the explicit where-clauses, but to get the full set of predicates
-    // on a trait we need to add in the supertrait bounds and bounds found on
-    // associated types.
-    if let Some(_trait_ref) = is_trait {
-        predicates.extend(tcx.super_predicates_of(def_id).predicates.iter().cloned());
-    }
-
-    // In default impls, we can assume that the self type implements
-    // the trait. So in:
-    //
-    //     default impl Foo for Bar { .. }
-    //
-    // we add a default where clause `Foo: Bar`. We do a similar thing for traits
-    // (see below). Recall that a default impl is not itself an impl, but rather a
-    // set of defaults that can be incorporated into another impl.
-    if let Some(trait_ref) = is_default_impl_trait {
-        predicates.insert((trait_ref.without_const().to_predicate(tcx), tcx.def_span(def_id)));
-    }
-
-    // Collect the region predicates that were declared inline as
-    // well. In the case of parameters declared on a fn or method, we
-    // have to be careful to only iterate over early-bound regions.
-    let mut index = parent_count
-        + has_own_self as u32
-        + early_bound_lifetimes_from_generics(tcx, ast_generics).count() as u32;
-
-    trace!(?predicates);
-    trace!(?ast_generics);
-
-    // Collect the predicates that were written inline by the user on each
-    // type parameter (e.g., `<T: Foo>`).
-    for param in ast_generics.params {
-        match param.kind {
-            // We already dealt with early bound lifetimes above.
-            GenericParamKind::Lifetime { .. } => (),
-            GenericParamKind::Type { .. } => {
-                let name = param.name.ident().name;
-                let param_ty = ty::ParamTy::new(index, name).to_ty(tcx);
-                index += 1;
-
-                let mut bounds = Bounds::default();
-                // Params are implicitly sized unless a `?Sized` bound is found
-                <dyn AstConv<'_>>::add_implicitly_sized(
-                    &icx,
-                    &mut bounds,
-                    &[],
-                    Some((param.hir_id, ast_generics.predicates)),
-                    param.span,
-                );
-                trace!(?bounds);
-                predicates.extend(bounds.predicates(tcx, param_ty));
-                trace!(?predicates);
-            }
-            GenericParamKind::Const { .. } => {
-                // Bounds on const parameters are currently not possible.
-                index += 1;
-            }
-        }
-    }
-
-    trace!(?predicates);
-    // Add in the bounds that appear in the where-clause.
-    for predicate in ast_generics.predicates {
-        match predicate {
-            hir::WherePredicate::BoundPredicate(bound_pred) => {
-                let ty = icx.to_ty(bound_pred.bounded_ty);
-                let bound_vars = icx.tcx.late_bound_vars(bound_pred.bounded_ty.hir_id);
-
-                // Keep the type around in a dummy predicate, in case of no bounds.
-                // That way, `where Ty:` is not a complete noop (see #53696) and `Ty`
-                // is still checked for WF.
-                if bound_pred.bounds.is_empty() {
-                    if let ty::Param(_) = ty.kind() {
-                        // This is a `where T:`, which can be in the HIR from the
-                        // transformation that moves `?Sized` to `T`'s declaration.
-                        // We can skip the predicate because type parameters are
-                        // trivially WF, but also we *should*, to avoid exposing
-                        // users who never wrote `where Type:,` themselves, to
-                        // compiler/tooling bugs from not handling WF predicates.
-                    } else {
-                        let span = bound_pred.bounded_ty.span;
-                        let predicate = ty::Binder::bind_with_vars(
-                            ty::PredicateKind::WellFormed(ty.into()),
-                            bound_vars,
-                        );
-                        predicates.insert((predicate.to_predicate(tcx), span));
-                    }
-                }
-
-                let mut bounds = Bounds::default();
-                <dyn AstConv<'_>>::add_bounds(
-                    &icx,
-                    ty,
-                    bound_pred.bounds.iter(),
-                    &mut bounds,
-                    bound_vars,
-                );
-                predicates.extend(bounds.predicates(tcx, ty));
-            }
-
-            hir::WherePredicate::RegionPredicate(region_pred) => {
-                let r1 = <dyn AstConv<'_>>::ast_region_to_region(&icx, &region_pred.lifetime, None);
-                predicates.extend(region_pred.bounds.iter().map(|bound| {
-                    let (r2, span) = match bound {
-                        hir::GenericBound::Outlives(lt) => {
-                            (<dyn AstConv<'_>>::ast_region_to_region(&icx, lt, None), lt.span)
-                        }
-                        _ => bug!(),
-                    };
-                    let pred = ty::Binder::dummy(ty::PredicateKind::RegionOutlives(
-                        ty::OutlivesPredicate(r1, r2),
-                    ))
-                    .to_predicate(icx.tcx);
-
-                    (pred, span)
-                }))
-            }
-
-            hir::WherePredicate::EqPredicate(..) => {
-                // FIXME(#20041)
-            }
-        }
-    }
-
-    if tcx.features().generic_const_exprs {
-        predicates.extend(const_evaluatable_predicates_of(tcx, def_id.expect_local()));
-    }
-
-    let mut predicates: Vec<_> = predicates.into_iter().collect();
-
-    // Subtle: before we store the predicates into the tcx, we
-    // sort them so that predicates like `T: Foo<Item=U>` come
-    // before uses of `U`.  This avoids false ambiguity errors
-    // in trait checking. See `setup_constraining_predicates`
-    // for details.
-    if let Node::Item(&Item { kind: ItemKind::Impl { .. }, .. }) = node {
-        let self_ty = tcx.type_of(def_id);
-        let trait_ref = tcx.impl_trait_ref(def_id);
-        cgp::setup_constraining_predicates(
-            tcx,
-            &mut predicates,
-            trait_ref,
-            &mut cgp::parameters_for_impl(self_ty, trait_ref),
-        );
-    }
-
-    ty::GenericPredicates {
-        parent: generics.parent,
-        predicates: tcx.arena.alloc_from_iter(predicates),
-    }
-}
-
-fn const_evaluatable_predicates_of<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    def_id: LocalDefId,
-) -> FxIndexSet<(ty::Predicate<'tcx>, Span)> {
-    struct ConstCollector<'tcx> {
-        tcx: TyCtxt<'tcx>,
-        preds: FxIndexSet<(ty::Predicate<'tcx>, Span)>,
-    }
-
-    impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'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() {
-                let span = self.tcx.hir().span(c.hir_id);
-                self.preds.insert((
-                    ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv))
-                        .to_predicate(self.tcx),
-                    span,
-                ));
-            }
-        }
-
-        fn visit_const_param_default(&mut self, _param: HirId, _ct: &'tcx hir::AnonConst) {
-            // Do not look into const param defaults,
-            // these get checked when they are actually instantiated.
-            //
-            // We do not want the following to error:
-            //
-            //     struct Foo<const N: usize, const M: usize = { N + 1 }>;
-            //     struct Bar<const N: usize>(Foo<N, 3>);
-        }
-    }
-
-    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-    let node = tcx.hir().get(hir_id);
-
-    let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() };
-    if let hir::Node::Item(item) = node && let hir::ItemKind::Impl(ref impl_) = item.kind {
-        if let Some(of_trait) = &impl_.of_trait {
-            debug!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id);
-            collector.visit_trait_ref(of_trait);
-        }
-
-        debug!("const_evaluatable_predicates_of({:?}): visit_self_ty", def_id);
-        collector.visit_ty(impl_.self_ty);
-    }
-
-    if let Some(generics) = node.generics() {
-        debug!("const_evaluatable_predicates_of({:?}): visit_generics", def_id);
-        collector.visit_generics(generics);
-    }
-
-    if let Some(fn_sig) = tcx.hir().fn_sig_by_hir_id(hir_id) {
-        debug!("const_evaluatable_predicates_of({:?}): visit_fn_decl", def_id);
-        collector.visit_fn_decl(fn_sig.decl);
-    }
-    debug!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.preds);
-
-    collector.preds
-}
-
-fn trait_explicit_predicates_and_bounds(
-    tcx: TyCtxt<'_>,
-    def_id: LocalDefId,
-) -> ty::GenericPredicates<'_> {
-    assert_eq!(tcx.def_kind(def_id), DefKind::Trait);
-    gather_explicit_predicates_of(tcx, def_id.to_def_id())
-}
-
-fn explicit_predicates_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::GenericPredicates<'tcx> {
-    let def_kind = tcx.def_kind(def_id);
-    if let DefKind::Trait = def_kind {
-        // Remove bounds on associated types from the predicates, they will be
-        // returned by `explicit_item_bounds`.
-        let predicates_and_bounds = tcx.trait_explicit_predicates_and_bounds(def_id.expect_local());
-        let trait_identity_substs = InternalSubsts::identity_for_item(tcx, def_id);
-
-        let is_assoc_item_ty = |ty: Ty<'tcx>| {
-            // For a predicate from a where clause to become a bound on an
-            // associated type:
-            // * It must use the identity substs of the item.
-            //     * Since any generic parameters on the item are not in scope,
-            //       this means that the item is not a GAT, and its identity
-            //       substs are the same as the trait's.
-            // * It must be an associated type for this trait (*not* a
-            //   supertrait).
-            if let ty::Projection(projection) = ty.kind() {
-                projection.substs == trait_identity_substs
-                    && tcx.associated_item(projection.item_def_id).container_id(tcx) == def_id
-            } else {
-                false
-            }
-        };
-
-        let predicates: Vec<_> = predicates_and_bounds
-            .predicates
-            .iter()
-            .copied()
-            .filter(|(pred, _)| match pred.kind().skip_binder() {
-                ty::PredicateKind::Trait(tr) => !is_assoc_item_ty(tr.self_ty()),
-                ty::PredicateKind::Projection(proj) => {
-                    !is_assoc_item_ty(proj.projection_ty.self_ty())
-                }
-                ty::PredicateKind::TypeOutlives(outlives) => !is_assoc_item_ty(outlives.0),
-                _ => true,
-            })
-            .collect();
-        if predicates.len() == predicates_and_bounds.predicates.len() {
-            predicates_and_bounds
-        } else {
-            ty::GenericPredicates {
-                parent: predicates_and_bounds.parent,
-                predicates: tcx.arena.alloc_slice(&predicates),
-            }
-        }
-    } 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());
-            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.
-                // (See comment in `generics_of` for more information on why the parent shenanigans is necessary)
-                //
-                // struct Foo<T, const N: usize = { <T as Trait>::ASSOC }>(T) where T: Trait;
-                //        ^^^                     ^^^^^^^^^^^^^^^^^^^^^^^ the def id we are calling
-                //        ^^^                                             explicit_predicates_of on
-                //        parent item we dont have set as the
-                //        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
-                return tcx.explicit_predicates_of(item_def_id);
-            }
-        }
-        gather_explicit_predicates_of(tcx, def_id)
-    }
-}
-
-/// Converts a specific `GenericBound` from the AST into a set of
-/// predicates that apply to the self type. A vector is returned
-/// because this can be anywhere from zero predicates (`T: ?Sized` adds no
-/// predicates) to one (`T: Foo`) to many (`T: Bar<X = i32>` adds `T: Bar`
-/// and `<T as Bar>::X == i32`).
-fn predicates_from_bound<'tcx>(
-    astconv: &dyn AstConv<'tcx>,
-    param_ty: Ty<'tcx>,
-    bound: &'tcx hir::GenericBound<'tcx>,
-    bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
-) -> Vec<(ty::Predicate<'tcx>, Span)> {
-    let mut bounds = Bounds::default();
-    astconv.add_bounds(param_ty, [bound].into_iter(), &mut bounds, bound_vars);
-    bounds.predicates(astconv.tcx(), param_ty).collect()
-}
-
 fn compute_sig_of_foreign_fn_decl<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: DefId,
@@ -2542,7 +1382,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
     abi: abi::Abi,
 ) -> ty::PolyFnSig<'tcx> {
     let unsafety = if abi == abi::Abi::RustIntrinsic {
-        intrinsic_operation_unsafety(tcx.item_name(def_id))
+        intrinsic_operation_unsafety(tcx, def_id)
     } else {
         hir::Unsafety::Unsafe
     };
@@ -3386,7 +2226,7 @@ fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span:
     let node = tcx.hir().get(hir_id);
     if let Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) = node {
         let parent_id = tcx.hir().get_parent_item(hir_id);
-        let parent_item = tcx.hir().expect_item(parent_id);
+        let parent_item = tcx.hir().expect_item(parent_id.def_id);
         if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = parent_item.kind {
             tcx.sess
                 .struct_span_err(
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
new file mode 100644
index 00000000000..1deff17e840
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -0,0 +1,481 @@
+use crate::middle::resolve_lifetime as rl;
+use hir::{
+    intravisit::{self, Visitor},
+    GenericParamKind, HirId, Node,
+};
+use rustc_hir as hir;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::DefId;
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_session::lint;
+use rustc_span::symbol::{kw, Symbol};
+use rustc_span::Span;
+
+pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
+    use rustc_hir::*;
+
+    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+
+    let node = tcx.hir().get(hir_id);
+    let parent_def_id = match node {
+        Node::ImplItem(_)
+        | Node::TraitItem(_)
+        | Node::Variant(_)
+        | Node::Ctor(..)
+        | Node::Field(_) => {
+            let parent_id = tcx.hir().get_parent_item(hir_id);
+            Some(parent_id.to_def_id())
+        }
+        // FIXME(#43408) always enable this once `lazy_normalization` is
+        // stable enough and does not need a feature gate anymore.
+        Node::AnonConst(_) => {
+            let parent_def_id = tcx.hir().get_parent_item(hir_id);
+
+            let mut in_param_ty = false;
+            for (_parent, node) in tcx.hir().parent_iter(hir_id) {
+                if let Some(generics) = node.generics() {
+                    let mut visitor = AnonConstInParamTyDetector {
+                        in_param_ty: false,
+                        found_anon_const_in_param_ty: false,
+                        ct: hir_id,
+                    };
+
+                    visitor.visit_generics(generics);
+                    in_param_ty = visitor.found_anon_const_in_param_ty;
+                    break;
+                }
+            }
+
+            if in_param_ty {
+                // We do not allow generic parameters in anon consts if we are inside
+                // of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
+                None
+            } else if tcx.lazy_normalization() {
+                if let Some(param_id) = tcx.hir().opt_const_param_default_param_hir_id(hir_id) {
+                    // If the def_id we are calling generics_of on is an anon ct default i.e:
+                    //
+                    // struct Foo<const N: usize = { .. }>;
+                    //        ^^^       ^          ^^^^^^ def id of this anon const
+                    //        ^         ^ param_id
+                    //        ^ parent_def_id
+                    //
+                    // then we only want to return generics for params to the left of `N`. If we don't do that we
+                    // end up with that const looking like: `ty::ConstKind::Unevaluated(def_id, substs: [N#0])`.
+                    //
+                    // This causes ICEs (#86580) when building the substs for Foo in `fn foo() -> Foo { .. }` as
+                    // we substitute the defaults with the partially built substs when we build the substs. Subst'ing
+                    // the `N#0` on the unevaluated const indexes into the empty substs we're in the process of building.
+                    //
+                    // We fix this by having this function return the parent's generics ourselves and truncating the
+                    // generics to only include non-forward declared params (with the exception of the `Self` ty)
+                    //
+                    // For the above code example that means we want `substs: []`
+                    // For the following struct def we want `substs: [N#0]` when generics_of is called on
+                    // the def id of the `{ N + 1 }` anon const
+                    // struct Foo<const N: usize, const M: usize = { N + 1 }>;
+                    //
+                    // This has some implications for how we get the predicates available to the anon const
+                    // see `explicit_predicates_of` for more information on this
+                    let generics = tcx.generics_of(parent_def_id.to_def_id());
+                    let param_def = tcx.hir().local_def_id(param_id).to_def_id();
+                    let param_def_idx = generics.param_def_id_to_index[&param_def];
+                    // In the above example this would be .params[..N#0]
+                    let params = generics.params[..param_def_idx as usize].to_owned();
+                    let param_def_id_to_index =
+                        params.iter().map(|param| (param.def_id, param.index)).collect();
+
+                    return ty::Generics {
+                        // we set the parent of these generics to be our parent's parent so that we
+                        // dont end up with substs: [N, M, N] for the const default on a struct like this:
+                        // struct Foo<const N: usize, const M: usize = { ... }>;
+                        parent: generics.parent,
+                        parent_count: generics.parent_count,
+                        params,
+                        param_def_id_to_index,
+                        has_self: generics.has_self,
+                        has_late_bound_regions: generics.has_late_bound_regions,
+                    };
+                }
+
+                // HACK(eddyb) this provides the correct generics when
+                // `feature(generic_const_expressions)` is enabled, so that const expressions
+                // used with const generics, e.g. `Foo<{N+1}>`, can work at all.
+                //
+                // Note that we do not supply the parent generics when using
+                // `min_const_generics`.
+                Some(parent_def_id.to_def_id())
+            } else {
+                let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
+                match parent_node {
+                    // HACK(eddyb) this provides the correct generics for repeat
+                    // expressions' count (i.e. `N` in `[x; N]`), and explicit
+                    // `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`),
+                    // as they shouldn't be able to cause query cycle errors.
+                    Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
+                        if constant.hir_id() == hir_id =>
+                    {
+                        Some(parent_def_id.to_def_id())
+                    }
+                    Node::Variant(Variant { disr_expr: Some(ref constant), .. })
+                        if constant.hir_id == hir_id =>
+                    {
+                        Some(parent_def_id.to_def_id())
+                    }
+                    Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => {
+                        Some(tcx.typeck_root_def_id(def_id))
+                    }
+                    // Exclude `GlobalAsm` here which cannot have generics.
+                    Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
+                        if asm.operands.iter().any(|(op, _op_sp)| match op {
+                            hir::InlineAsmOperand::Const { anon_const }
+                            | hir::InlineAsmOperand::SymFn { anon_const } => {
+                                anon_const.hir_id == hir_id
+                            }
+                            _ => false,
+                        }) =>
+                    {
+                        Some(parent_def_id.to_def_id())
+                    }
+                    _ => None,
+                }
+            }
+        }
+        Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => {
+            Some(tcx.typeck_root_def_id(def_id))
+        }
+        Node::Item(item) => match item.kind {
+            ItemKind::OpaqueTy(hir::OpaqueTy {
+                origin:
+                    hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
+                in_trait,
+                ..
+            }) => {
+                if in_trait {
+                    assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn))
+                } else {
+                    assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn))
+                }
+                Some(fn_def_id.to_def_id())
+            }
+            ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
+                let parent_id = tcx.hir().get_parent_item(hir_id);
+                assert_ne!(parent_id, hir::CRATE_OWNER_ID);
+                debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent_id);
+                // Opaque types are always nested within another item, and
+                // inherit the generics of the item.
+                Some(parent_id.to_def_id())
+            }
+            _ => None,
+        },
+        _ => None,
+    };
+
+    enum Defaults {
+        Allowed,
+        // See #36887
+        FutureCompatDisallowed,
+        Deny,
+    }
+
+    let no_generics = hir::Generics::empty();
+    let ast_generics = node.generics().unwrap_or(&no_generics);
+    let (opt_self, allow_defaults) = match node {
+        Node::Item(item) => {
+            match item.kind {
+                ItemKind::Trait(..) | ItemKind::TraitAlias(..) => {
+                    // Add in the self type parameter.
+                    //
+                    // Something of a hack: use the node id for the trait, also as
+                    // the node id for the Self type parameter.
+                    let opt_self = Some(ty::GenericParamDef {
+                        index: 0,
+                        name: kw::SelfUpper,
+                        def_id,
+                        pure_wrt_drop: false,
+                        kind: ty::GenericParamDefKind::Type {
+                            has_default: false,
+                            synthetic: false,
+                        },
+                    });
+
+                    (opt_self, Defaults::Allowed)
+                }
+                ItemKind::TyAlias(..)
+                | ItemKind::Enum(..)
+                | ItemKind::Struct(..)
+                | ItemKind::OpaqueTy(..)
+                | ItemKind::Union(..) => (None, Defaults::Allowed),
+                _ => (None, Defaults::FutureCompatDisallowed),
+            }
+        }
+
+        // GATs
+        Node::TraitItem(item) if matches!(item.kind, TraitItemKind::Type(..)) => {
+            (None, Defaults::Deny)
+        }
+        Node::ImplItem(item) if matches!(item.kind, ImplItemKind::TyAlias(..)) => {
+            (None, Defaults::Deny)
+        }
+
+        _ => (None, Defaults::FutureCompatDisallowed),
+    };
+
+    let has_self = opt_self.is_some();
+    let mut parent_has_self = false;
+    let mut own_start = has_self as u32;
+    let parent_count = parent_def_id.map_or(0, |def_id| {
+        let generics = tcx.generics_of(def_id);
+        assert!(!has_self);
+        parent_has_self = generics.has_self;
+        own_start = generics.count() as u32;
+        generics.parent_count + generics.params.len()
+    });
+
+    let mut params: Vec<_> = Vec::with_capacity(ast_generics.params.len() + has_self as usize);
+
+    if let Some(opt_self) = opt_self {
+        params.push(opt_self);
+    }
+
+    let early_lifetimes = super::early_bound_lifetimes_from_generics(tcx, ast_generics);
+    params.extend(early_lifetimes.enumerate().map(|(i, param)| ty::GenericParamDef {
+        name: param.name.ident().name,
+        index: own_start + i as u32,
+        def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
+        pure_wrt_drop: param.pure_wrt_drop,
+        kind: ty::GenericParamDefKind::Lifetime,
+    }));
+
+    // 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;
+
+    const TYPE_DEFAULT_NOT_ALLOWED: &'static str = "defaults for type parameters are only allowed in \
+    `struct`, `enum`, `type`, or `trait` definitions";
+
+    params.extend(ast_generics.params.iter().filter_map(|param| match param.kind {
+        GenericParamKind::Lifetime { .. } => None,
+        GenericParamKind::Type { ref default, synthetic, .. } => {
+            if default.is_some() {
+                match allow_defaults {
+                    Defaults::Allowed => {}
+                    Defaults::FutureCompatDisallowed
+                        if tcx.features().default_type_parameter_fallback => {}
+                    Defaults::FutureCompatDisallowed => {
+                        tcx.struct_span_lint_hir(
+                            lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
+                            param.hir_id,
+                            param.span,
+                            |lint| {
+                                lint.build(TYPE_DEFAULT_NOT_ALLOWED).emit();
+                            },
+                        );
+                    }
+                    Defaults::Deny => {
+                        tcx.sess.span_err(param.span, TYPE_DEFAULT_NOT_ALLOWED);
+                    }
+                }
+            }
+
+            let kind = ty::GenericParamDefKind::Type { has_default: default.is_some(), synthetic };
+
+            let param_def = ty::GenericParamDef {
+                index: type_start + i as u32,
+                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() {
+                tcx.sess.span_err(
+                    param.span,
+                    "defaults for const parameters are only allowed in \
+                    `struct`, `enum`, `type`, or `trait` definitions",
+                );
+            }
+
+            let param_def = ty::GenericParamDef {
+                index: type_start + i as u32,
+                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)
+        }
+    }));
+
+    // provide junk type parameter defs - the only place that
+    // cares about anything but the length is instantiation,
+    // and we don't do that for closures.
+    if let Node::Expr(&hir::Expr {
+        kind: hir::ExprKind::Closure(hir::Closure { movability: gen, .. }),
+        ..
+    }) = node
+    {
+        let dummy_args = if gen.is_some() {
+            &["<resume_ty>", "<yield_ty>", "<return_ty>", "<witness>", "<upvars>"][..]
+        } else {
+            &["<closure_kind>", "<closure_signature>", "<upvars>"][..]
+        };
+
+        params.extend(dummy_args.iter().enumerate().map(|(i, &arg)| ty::GenericParamDef {
+            index: type_start + i as u32,
+            name: Symbol::intern(arg),
+            def_id,
+            pure_wrt_drop: false,
+            kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
+        }));
+    }
+
+    // provide junk type parameter defs for const blocks.
+    if let Node::AnonConst(_) = node {
+        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,
+                name: Symbol::intern("<const_ty>"),
+                def_id,
+                pure_wrt_drop: false,
+                kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
+            });
+        }
+    }
+
+    let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect();
+
+    ty::Generics {
+        parent: parent_def_id,
+        parent_count,
+        params,
+        param_def_id_to_index,
+        has_self: has_self || parent_has_self,
+        has_late_bound_regions: has_late_bound_regions(tcx, node),
+    }
+}
+
+fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<Span> {
+    struct LateBoundRegionsDetector<'tcx> {
+        tcx: TyCtxt<'tcx>,
+        outer_index: ty::DebruijnIndex,
+        has_late_bound_regions: Option<Span>,
+    }
+
+    impl<'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'tcx> {
+        fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
+            if self.has_late_bound_regions.is_some() {
+                return;
+            }
+            match ty.kind {
+                hir::TyKind::BareFn(..) => {
+                    self.outer_index.shift_in(1);
+                    intravisit::walk_ty(self, ty);
+                    self.outer_index.shift_out(1);
+                }
+                _ => intravisit::walk_ty(self, ty),
+            }
+        }
+
+        fn visit_poly_trait_ref(&mut self, tr: &'tcx hir::PolyTraitRef<'tcx>) {
+            if self.has_late_bound_regions.is_some() {
+                return;
+            }
+            self.outer_index.shift_in(1);
+            intravisit::walk_poly_trait_ref(self, tr);
+            self.outer_index.shift_out(1);
+        }
+
+        fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
+            if self.has_late_bound_regions.is_some() {
+                return;
+            }
+
+            match self.tcx.named_region(lt.hir_id) {
+                Some(rl::Region::Static | rl::Region::EarlyBound(..)) => {}
+                Some(rl::Region::LateBound(debruijn, _, _)) if debruijn < self.outer_index => {}
+                Some(rl::Region::LateBound(..) | rl::Region::Free(..)) | None => {
+                    self.has_late_bound_regions = Some(lt.span);
+                }
+            }
+        }
+    }
+
+    fn has_late_bound_regions<'tcx>(
+        tcx: TyCtxt<'tcx>,
+        generics: &'tcx hir::Generics<'tcx>,
+        decl: &'tcx hir::FnDecl<'tcx>,
+    ) -> Option<Span> {
+        let mut visitor = LateBoundRegionsDetector {
+            tcx,
+            outer_index: ty::INNERMOST,
+            has_late_bound_regions: None,
+        };
+        for param in generics.params {
+            if let GenericParamKind::Lifetime { .. } = param.kind {
+                if tcx.is_late_bound(param.hir_id) {
+                    return Some(param.span);
+                }
+            }
+        }
+        visitor.visit_fn_decl(decl);
+        visitor.has_late_bound_regions
+    }
+
+    match node {
+        Node::TraitItem(item) => match item.kind {
+            hir::TraitItemKind::Fn(ref sig, _) => {
+                has_late_bound_regions(tcx, &item.generics, sig.decl)
+            }
+            _ => None,
+        },
+        Node::ImplItem(item) => match item.kind {
+            hir::ImplItemKind::Fn(ref sig, _) => {
+                has_late_bound_regions(tcx, &item.generics, sig.decl)
+            }
+            _ => None,
+        },
+        Node::ForeignItem(item) => match item.kind {
+            hir::ForeignItemKind::Fn(fn_decl, _, ref generics) => {
+                has_late_bound_regions(tcx, generics, fn_decl)
+            }
+            _ => None,
+        },
+        Node::Item(item) => match item.kind {
+            hir::ItemKind::Fn(ref sig, .., ref generics, _) => {
+                has_late_bound_regions(tcx, generics, sig.decl)
+            }
+            _ => None,
+        },
+        _ => None,
+    }
+}
+
+struct AnonConstInParamTyDetector {
+    in_param_ty: bool,
+    found_anon_const_in_param_ty: bool,
+    ct: HirId,
+}
+
+impl<'v> Visitor<'v> for AnonConstInParamTyDetector {
+    fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) {
+        if let GenericParamKind::Const { ty, default: _ } = p.kind {
+            let prev = self.in_param_ty;
+            self.in_param_ty = true;
+            self.visit_ty(ty);
+            self.in_param_ty = prev;
+        }
+    }
+
+    fn visit_anon_const(&mut self, c: &'v hir::AnonConst) {
+        if self.in_param_ty && self.ct == c.hir_id {
+            self.found_anon_const_in_param_ty = true;
+        } else {
+            intravisit::walk_anon_const(self, c)
+        }
+    }
+}
diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 0d34a8bfee3..0d34a8bfee3 100644
--- a/compiler/rustc_typeck/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
new file mode 100644
index 00000000000..db8f8de68f2
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -0,0 +1,707 @@
+use crate::astconv::AstConv;
+use crate::bounds::Bounds;
+use crate::collect::ItemCtxt;
+use crate::constrained_generic_params as cgp;
+use hir::{HirId, Node};
+use rustc_data_structures::fx::FxIndexSet;
+use rustc_hir as hir;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::intravisit::{self, Visitor};
+use rustc_middle::ty::subst::InternalSubsts;
+use rustc_middle::ty::ToPredicate;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::symbol::{sym, Ident};
+use rustc_span::{Span, DUMMY_SP};
+
+#[derive(Debug)]
+struct OnlySelfBounds(bool);
+
+/// Returns a list of all type predicates (explicit and implicit) for the definition with
+/// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus
+/// `Self: Trait` predicates for traits.
+pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
+    let mut result = tcx.predicates_defined_on(def_id);
+
+    if tcx.is_trait(def_id) {
+        // For traits, add `Self: Trait` predicate. This is
+        // not part of the predicates that a user writes, but it
+        // is something that one must prove in order to invoke a
+        // method or project an associated type.
+        //
+        // In the chalk setup, this predicate is not part of the
+        // "predicates" for a trait item. But it is useful in
+        // rustc because if you directly (e.g.) invoke a trait
+        // method like `Trait::method(...)`, you must naturally
+        // prove that the trait applies to the types that were
+        // used, and adding the predicate into this list ensures
+        // that this is done.
+        //
+        // We use a DUMMY_SP here as a way to signal trait bounds that come
+        // from the trait itself that *shouldn't* be shown as the source of
+        // an obligation and instead be skipped. Otherwise we'd use
+        // `tcx.def_span(def_id);`
+
+        let constness = if tcx.has_attr(def_id, sym::const_trait) {
+            ty::BoundConstness::ConstIfConst
+        } else {
+            ty::BoundConstness::NotConst
+        };
+
+        let span = rustc_span::DUMMY_SP;
+        result.predicates =
+            tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once((
+                ty::TraitRef::identity(tcx, def_id).with_constness(constness).to_predicate(tcx),
+                span,
+            ))));
+    }
+    debug!("predicates_of(def_id={:?}) = {:?}", def_id, result);
+    result
+}
+
+/// Returns a list of user-specified type predicates for the definition with ID `def_id`.
+/// N.B., this does not include any implied/inferred constraints.
+#[instrument(level = "trace", skip(tcx), ret)]
+fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
+    use rustc_hir::*;
+
+    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+    let node = tcx.hir().get(hir_id);
+
+    let mut is_trait = None;
+    let mut is_default_impl_trait = None;
+
+    let icx = ItemCtxt::new(tcx, def_id);
+
+    const NO_GENERICS: &hir::Generics<'_> = hir::Generics::empty();
+
+    // We use an `IndexSet` to preserves order of insertion.
+    // Preserving the order of insertion is important here so as not to break UI tests.
+    let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default();
+
+    let ast_generics = match node {
+        Node::TraitItem(item) => item.generics,
+
+        Node::ImplItem(item) => item.generics,
+
+        Node::Item(item) => {
+            match item.kind {
+                ItemKind::Impl(ref impl_) => {
+                    if impl_.defaultness.is_default() {
+                        is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy);
+                    }
+                    &impl_.generics
+                }
+                ItemKind::Fn(.., ref generics, _)
+                | ItemKind::TyAlias(_, ref generics)
+                | ItemKind::Enum(_, ref generics)
+                | ItemKind::Struct(_, ref generics)
+                | ItemKind::Union(_, ref generics) => *generics,
+
+                ItemKind::Trait(_, _, ref generics, ..) => {
+                    is_trait = Some(ty::TraitRef::identity(tcx, def_id));
+                    *generics
+                }
+                ItemKind::TraitAlias(ref generics, _) => {
+                    is_trait = Some(ty::TraitRef::identity(tcx, def_id));
+                    *generics
+                }
+                ItemKind::OpaqueTy(OpaqueTy {
+                    origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
+                    ..
+                }) => {
+                    // return-position impl trait
+                    //
+                    // We don't inherit predicates from the parent here:
+                    // If we have, say `fn f<'a, T: 'a>() -> impl Sized {}`
+                    // then the return type is `f::<'static, T>::{{opaque}}`.
+                    //
+                    // If we inherited the predicates of `f` then we would
+                    // require that `T: 'static` to show that the return
+                    // type is well-formed.
+                    //
+                    // The only way to have something with this opaque type
+                    // is from the return type of the containing function,
+                    // which will ensure that the function's predicates
+                    // hold.
+                    return ty::GenericPredicates { parent: None, predicates: &[] };
+                }
+                ItemKind::OpaqueTy(OpaqueTy {
+                    ref generics,
+                    origin: hir::OpaqueTyOrigin::TyAlias,
+                    ..
+                }) => {
+                    // type-alias impl trait
+                    generics
+                }
+
+                _ => NO_GENERICS,
+            }
+        }
+
+        Node::ForeignItem(item) => match item.kind {
+            ForeignItemKind::Static(..) => NO_GENERICS,
+            ForeignItemKind::Fn(_, _, ref generics) => *generics,
+            ForeignItemKind::Type => NO_GENERICS,
+        },
+
+        _ => NO_GENERICS,
+    };
+
+    let generics = tcx.generics_of(def_id);
+    let parent_count = generics.parent_count as u32;
+    let has_own_self = generics.has_self && parent_count == 0;
+
+    // Below we'll consider the bounds on the type parameters (including `Self`)
+    // and the explicit where-clauses, but to get the full set of predicates
+    // on a trait we need to add in the supertrait bounds and bounds found on
+    // associated types.
+    if let Some(_trait_ref) = is_trait {
+        predicates.extend(tcx.super_predicates_of(def_id).predicates.iter().cloned());
+    }
+
+    // In default impls, we can assume that the self type implements
+    // the trait. So in:
+    //
+    //     default impl Foo for Bar { .. }
+    //
+    // we add a default where clause `Foo: Bar`. We do a similar thing for traits
+    // (see below). Recall that a default impl is not itself an impl, but rather a
+    // set of defaults that can be incorporated into another impl.
+    if let Some(trait_ref) = is_default_impl_trait {
+        predicates.insert((trait_ref.without_const().to_predicate(tcx), tcx.def_span(def_id)));
+    }
+
+    // Collect the region predicates that were declared inline as
+    // well. In the case of parameters declared on a fn or method, we
+    // have to be careful to only iterate over early-bound regions.
+    let mut index = parent_count
+        + has_own_self as u32
+        + super::early_bound_lifetimes_from_generics(tcx, ast_generics).count() as u32;
+
+    trace!(?predicates);
+    trace!(?ast_generics);
+
+    // Collect the predicates that were written inline by the user on each
+    // type parameter (e.g., `<T: Foo>`).
+    for param in ast_generics.params {
+        match param.kind {
+            // We already dealt with early bound lifetimes above.
+            GenericParamKind::Lifetime { .. } => (),
+            GenericParamKind::Type { .. } => {
+                let name = param.name.ident().name;
+                let param_ty = ty::ParamTy::new(index, name).to_ty(tcx);
+                index += 1;
+
+                let mut bounds = Bounds::default();
+                // Params are implicitly sized unless a `?Sized` bound is found
+                <dyn AstConv<'_>>::add_implicitly_sized(
+                    &icx,
+                    &mut bounds,
+                    &[],
+                    Some((param.hir_id, ast_generics.predicates)),
+                    param.span,
+                );
+                trace!(?bounds);
+                predicates.extend(bounds.predicates(tcx, param_ty));
+                trace!(?predicates);
+            }
+            GenericParamKind::Const { .. } => {
+                // Bounds on const parameters are currently not possible.
+                index += 1;
+            }
+        }
+    }
+
+    trace!(?predicates);
+    // Add in the bounds that appear in the where-clause.
+    for predicate in ast_generics.predicates {
+        match predicate {
+            hir::WherePredicate::BoundPredicate(bound_pred) => {
+                let ty = icx.to_ty(bound_pred.bounded_ty);
+                let bound_vars = icx.tcx.late_bound_vars(bound_pred.hir_id);
+
+                // Keep the type around in a dummy predicate, in case of no bounds.
+                // That way, `where Ty:` is not a complete noop (see #53696) and `Ty`
+                // is still checked for WF.
+                if bound_pred.bounds.is_empty() {
+                    if let ty::Param(_) = ty.kind() {
+                        // This is a `where T:`, which can be in the HIR from the
+                        // transformation that moves `?Sized` to `T`'s declaration.
+                        // We can skip the predicate because type parameters are
+                        // trivially WF, but also we *should*, to avoid exposing
+                        // users who never wrote `where Type:,` themselves, to
+                        // compiler/tooling bugs from not handling WF predicates.
+                    } else {
+                        let span = bound_pred.bounded_ty.span;
+                        let predicate = ty::Binder::bind_with_vars(
+                            ty::PredicateKind::WellFormed(ty.into()),
+                            bound_vars,
+                        );
+                        predicates.insert((predicate.to_predicate(tcx), span));
+                    }
+                }
+
+                let mut bounds = Bounds::default();
+                <dyn AstConv<'_>>::add_bounds(
+                    &icx,
+                    ty,
+                    bound_pred.bounds.iter(),
+                    &mut bounds,
+                    bound_vars,
+                );
+                predicates.extend(bounds.predicates(tcx, ty));
+            }
+
+            hir::WherePredicate::RegionPredicate(region_pred) => {
+                let r1 = <dyn AstConv<'_>>::ast_region_to_region(&icx, &region_pred.lifetime, None);
+                predicates.extend(region_pred.bounds.iter().map(|bound| {
+                    let (r2, span) = match bound {
+                        hir::GenericBound::Outlives(lt) => {
+                            (<dyn AstConv<'_>>::ast_region_to_region(&icx, lt, None), lt.span)
+                        }
+                        _ => bug!(),
+                    };
+                    let pred = ty::Binder::dummy(ty::PredicateKind::RegionOutlives(
+                        ty::OutlivesPredicate(r1, r2),
+                    ))
+                    .to_predicate(icx.tcx);
+
+                    (pred, span)
+                }))
+            }
+
+            hir::WherePredicate::EqPredicate(..) => {
+                // FIXME(#20041)
+            }
+        }
+    }
+
+    if tcx.features().generic_const_exprs {
+        predicates.extend(const_evaluatable_predicates_of(tcx, def_id.expect_local()));
+    }
+
+    let mut predicates: Vec<_> = predicates.into_iter().collect();
+
+    // Subtle: before we store the predicates into the tcx, we
+    // sort them so that predicates like `T: Foo<Item=U>` come
+    // before uses of `U`.  This avoids false ambiguity errors
+    // in trait checking. See `setup_constraining_predicates`
+    // for details.
+    if let Node::Item(&Item { kind: ItemKind::Impl { .. }, .. }) = node {
+        let self_ty = tcx.type_of(def_id);
+        let trait_ref = tcx.impl_trait_ref(def_id);
+        cgp::setup_constraining_predicates(
+            tcx,
+            &mut predicates,
+            trait_ref,
+            &mut cgp::parameters_for_impl(self_ty, trait_ref),
+        );
+    }
+
+    ty::GenericPredicates {
+        parent: generics.parent,
+        predicates: tcx.arena.alloc_from_iter(predicates),
+    }
+}
+
+fn const_evaluatable_predicates_of<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+) -> FxIndexSet<(ty::Predicate<'tcx>, Span)> {
+    struct ConstCollector<'tcx> {
+        tcx: TyCtxt<'tcx>,
+        preds: FxIndexSet<(ty::Predicate<'tcx>, Span)>,
+    }
+
+    impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'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() {
+                let span = self.tcx.hir().span(c.hir_id);
+                self.preds.insert((
+                    ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv))
+                        .to_predicate(self.tcx),
+                    span,
+                ));
+            }
+        }
+
+        fn visit_const_param_default(&mut self, _param: HirId, _ct: &'tcx hir::AnonConst) {
+            // Do not look into const param defaults,
+            // these get checked when they are actually instantiated.
+            //
+            // We do not want the following to error:
+            //
+            //     struct Foo<const N: usize, const M: usize = { N + 1 }>;
+            //     struct Bar<const N: usize>(Foo<N, 3>);
+        }
+    }
+
+    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+    let node = tcx.hir().get(hir_id);
+
+    let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() };
+    if let hir::Node::Item(item) = node && let hir::ItemKind::Impl(ref impl_) = item.kind {
+        if let Some(of_trait) = &impl_.of_trait {
+            debug!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id);
+            collector.visit_trait_ref(of_trait);
+        }
+
+        debug!("const_evaluatable_predicates_of({:?}): visit_self_ty", def_id);
+        collector.visit_ty(impl_.self_ty);
+    }
+
+    if let Some(generics) = node.generics() {
+        debug!("const_evaluatable_predicates_of({:?}): visit_generics", def_id);
+        collector.visit_generics(generics);
+    }
+
+    if let Some(fn_sig) = tcx.hir().fn_sig_by_hir_id(hir_id) {
+        debug!("const_evaluatable_predicates_of({:?}): visit_fn_decl", def_id);
+        collector.visit_fn_decl(fn_sig.decl);
+    }
+    debug!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.preds);
+
+    collector.preds
+}
+
+pub(super) fn trait_explicit_predicates_and_bounds(
+    tcx: TyCtxt<'_>,
+    def_id: LocalDefId,
+) -> ty::GenericPredicates<'_> {
+    assert_eq!(tcx.def_kind(def_id), DefKind::Trait);
+    gather_explicit_predicates_of(tcx, def_id.to_def_id())
+}
+
+pub(super) fn explicit_predicates_of<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: DefId,
+) -> ty::GenericPredicates<'tcx> {
+    let def_kind = tcx.def_kind(def_id);
+    if let DefKind::Trait = def_kind {
+        // Remove bounds on associated types from the predicates, they will be
+        // returned by `explicit_item_bounds`.
+        let predicates_and_bounds = tcx.trait_explicit_predicates_and_bounds(def_id.expect_local());
+        let trait_identity_substs = InternalSubsts::identity_for_item(tcx, def_id);
+
+        let is_assoc_item_ty = |ty: Ty<'tcx>| {
+            // For a predicate from a where clause to become a bound on an
+            // associated type:
+            // * It must use the identity substs of the item.
+            //     * Since any generic parameters on the item are not in scope,
+            //       this means that the item is not a GAT, and its identity
+            //       substs are the same as the trait's.
+            // * It must be an associated type for this trait (*not* a
+            //   supertrait).
+            if let ty::Projection(projection) = ty.kind() {
+                projection.substs == trait_identity_substs
+                    && tcx.associated_item(projection.item_def_id).container_id(tcx) == def_id
+            } else {
+                false
+            }
+        };
+
+        let predicates: Vec<_> = predicates_and_bounds
+            .predicates
+            .iter()
+            .copied()
+            .filter(|(pred, _)| match pred.kind().skip_binder() {
+                ty::PredicateKind::Trait(tr) => !is_assoc_item_ty(tr.self_ty()),
+                ty::PredicateKind::Projection(proj) => {
+                    !is_assoc_item_ty(proj.projection_ty.self_ty())
+                }
+                ty::PredicateKind::TypeOutlives(outlives) => !is_assoc_item_ty(outlives.0),
+                _ => true,
+            })
+            .collect();
+        if predicates.len() == predicates_and_bounds.predicates.len() {
+            predicates_and_bounds
+        } else {
+            ty::GenericPredicates {
+                parent: predicates_and_bounds.parent,
+                predicates: tcx.arena.alloc_slice(&predicates),
+            }
+        }
+    } 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());
+            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.
+                // (See comment in `generics_of` for more information on why the parent shenanigans is necessary)
+                //
+                // struct Foo<T, const N: usize = { <T as Trait>::ASSOC }>(T) where T: Trait;
+                //        ^^^                     ^^^^^^^^^^^^^^^^^^^^^^^ the def id we are calling
+                //        ^^^                                             explicit_predicates_of on
+                //        parent item we dont have set as the
+                //        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
+                return tcx.explicit_predicates_of(item_def_id);
+            }
+        }
+        gather_explicit_predicates_of(tcx, def_id)
+    }
+}
+
+/// Ensures that the super-predicates of the trait with a `DefId`
+/// of `trait_def_id` are converted and stored. This also ensures that
+/// the transitive super-predicates are converted.
+pub(super) fn super_predicates_of(
+    tcx: TyCtxt<'_>,
+    trait_def_id: DefId,
+) -> ty::GenericPredicates<'_> {
+    tcx.super_predicates_that_define_assoc_type((trait_def_id, None))
+}
+
+/// Ensures that the super-predicates of the trait with a `DefId`
+/// of `trait_def_id` are converted and stored. This also ensures that
+/// the transitive super-predicates are converted.
+pub(super) fn super_predicates_that_define_assoc_type(
+    tcx: TyCtxt<'_>,
+    (trait_def_id, assoc_name): (DefId, Option<Ident>),
+) -> ty::GenericPredicates<'_> {
+    if trait_def_id.is_local() {
+        debug!("local trait");
+        let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id.expect_local());
+
+        let Node::Item(item) = tcx.hir().get(trait_hir_id) else {
+            bug!("trait_node_id {} is not an item", trait_hir_id);
+        };
+
+        let (generics, bounds) = match item.kind {
+            hir::ItemKind::Trait(.., ref generics, ref supertraits, _) => (generics, supertraits),
+            hir::ItemKind::TraitAlias(ref generics, ref supertraits) => (generics, supertraits),
+            _ => span_bug!(item.span, "super_predicates invoked on non-trait"),
+        };
+
+        let icx = ItemCtxt::new(tcx, trait_def_id);
+
+        // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`.
+        let self_param_ty = tcx.types.self_param;
+        let superbounds1 = if let Some(assoc_name) = assoc_name {
+            <dyn AstConv<'_>>::compute_bounds_that_match_assoc_type(
+                &icx,
+                self_param_ty,
+                bounds,
+                assoc_name,
+            )
+        } else {
+            <dyn AstConv<'_>>::compute_bounds(&icx, self_param_ty, bounds)
+        };
+
+        let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
+
+        // Convert any explicit superbounds in the where-clause,
+        // e.g., `trait Foo where Self: Bar`.
+        // In the case of trait aliases, however, we include all bounds in the where-clause,
+        // so e.g., `trait Foo = where u32: PartialEq<Self>` would include `u32: PartialEq<Self>`
+        // as one of its "superpredicates".
+        let is_trait_alias = tcx.is_trait_alias(trait_def_id);
+        let superbounds2 = icx.type_parameter_bounds_in_generics(
+            generics,
+            item.hir_id(),
+            self_param_ty,
+            OnlySelfBounds(!is_trait_alias),
+            assoc_name,
+        );
+
+        // Combine the two lists to form the complete set of superbounds:
+        let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2));
+        debug!(?superbounds);
+
+        // Now require that immediate supertraits are converted,
+        // which will, in turn, reach indirect supertraits.
+        if assoc_name.is_none() {
+            // Now require that immediate supertraits are converted,
+            // which will, in turn, reach indirect supertraits.
+            for &(pred, span) in superbounds {
+                debug!("superbound: {:?}", pred);
+                if let ty::PredicateKind::Trait(bound) = pred.kind().skip_binder() {
+                    tcx.at(span).super_predicates_of(bound.def_id());
+                }
+            }
+        }
+
+        ty::GenericPredicates { parent: None, predicates: superbounds }
+    } else {
+        // if `assoc_name` is None, then the query should've been redirected to an
+        // external provider
+        assert!(assoc_name.is_some());
+        tcx.super_predicates_of(trait_def_id)
+    }
+}
+
+/// Returns the predicates defined on `item_def_id` of the form
+/// `X: Foo` where `X` is the type parameter `def_id`.
+#[instrument(level = "trace", skip(tcx))]
+pub(super) fn type_param_predicates(
+    tcx: TyCtxt<'_>,
+    (item_def_id, def_id, assoc_name): (DefId, LocalDefId, Ident),
+) -> ty::GenericPredicates<'_> {
+    use rustc_hir::*;
+
+    // In the AST, bounds can derive from two places. Either
+    // written inline like `<T: Foo>` or in a where-clause like
+    // `where T: Foo`.
+
+    let param_id = tcx.hir().local_def_id_to_hir_id(def_id);
+    let param_owner = tcx.hir().ty_param_owner(def_id);
+    let generics = tcx.generics_of(param_owner);
+    let index = generics.param_def_id_to_index[&def_id.to_def_id()];
+    let ty = tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id));
+
+    // Don't look for bounds where the type parameter isn't in scope.
+    let parent = if item_def_id == param_owner.to_def_id() {
+        None
+    } else {
+        tcx.generics_of(item_def_id).parent
+    };
+
+    let mut result = parent
+        .map(|parent| {
+            let icx = ItemCtxt::new(tcx, parent);
+            icx.get_type_parameter_bounds(DUMMY_SP, def_id.to_def_id(), assoc_name)
+        })
+        .unwrap_or_default();
+    let mut extend = None;
+
+    let item_hir_id = tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local());
+    let ast_generics = match tcx.hir().get(item_hir_id) {
+        Node::TraitItem(item) => &item.generics,
+
+        Node::ImplItem(item) => &item.generics,
+
+        Node::Item(item) => {
+            match item.kind {
+                ItemKind::Fn(.., ref generics, _)
+                | ItemKind::Impl(hir::Impl { ref generics, .. })
+                | ItemKind::TyAlias(_, ref generics)
+                | ItemKind::OpaqueTy(OpaqueTy {
+                    ref generics,
+                    origin: hir::OpaqueTyOrigin::TyAlias,
+                    ..
+                })
+                | ItemKind::Enum(_, ref generics)
+                | ItemKind::Struct(_, ref generics)
+                | ItemKind::Union(_, ref generics) => generics,
+                ItemKind::Trait(_, _, ref generics, ..) => {
+                    // Implied `Self: Trait` and supertrait bounds.
+                    if param_id == item_hir_id {
+                        let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id);
+                        extend =
+                            Some((identity_trait_ref.without_const().to_predicate(tcx), item.span));
+                    }
+                    generics
+                }
+                _ => return result,
+            }
+        }
+
+        Node::ForeignItem(item) => match item.kind {
+            ForeignItemKind::Fn(_, _, ref generics) => generics,
+            _ => return result,
+        },
+
+        _ => return result,
+    };
+
+    let icx = ItemCtxt::new(tcx, item_def_id);
+    let extra_predicates = extend.into_iter().chain(
+        icx.type_parameter_bounds_in_generics(
+            ast_generics,
+            param_id,
+            ty,
+            OnlySelfBounds(true),
+            Some(assoc_name),
+        )
+        .into_iter()
+        .filter(|(predicate, _)| match predicate.kind().skip_binder() {
+            ty::PredicateKind::Trait(data) => data.self_ty().is_param(index),
+            _ => false,
+        }),
+    );
+    result.predicates =
+        tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(extra_predicates));
+    result
+}
+
+impl<'tcx> ItemCtxt<'tcx> {
+    /// Finds bounds from `hir::Generics`. This requires scanning through the
+    /// AST. We do this to avoid having to convert *all* the bounds, which
+    /// would create artificial cycles. Instead, we can only convert the
+    /// bounds for a type parameter `X` if `X::Foo` is used.
+    #[instrument(level = "trace", skip(self, ast_generics))]
+    fn type_parameter_bounds_in_generics(
+        &self,
+        ast_generics: &'tcx hir::Generics<'tcx>,
+        param_id: hir::HirId,
+        ty: Ty<'tcx>,
+        only_self_bounds: OnlySelfBounds,
+        assoc_name: Option<Ident>,
+    ) -> Vec<(ty::Predicate<'tcx>, Span)> {
+        let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id();
+        trace!(?param_def_id);
+        ast_generics
+            .predicates
+            .iter()
+            .filter_map(|wp| match *wp {
+                hir::WherePredicate::BoundPredicate(ref bp) => Some(bp),
+                _ => None,
+            })
+            .flat_map(|bp| {
+                let bt = if bp.is_param_bound(param_def_id) {
+                    Some(ty)
+                } else if !only_self_bounds.0 {
+                    Some(self.to_ty(bp.bounded_ty))
+                } else {
+                    None
+                };
+                let bvars = self.tcx.late_bound_vars(bp.hir_id);
+
+                bp.bounds.iter().filter_map(move |b| bt.map(|bt| (bt, b, bvars))).filter(
+                    |(_, b, _)| match assoc_name {
+                        Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
+                        None => true,
+                    },
+                )
+            })
+            .flat_map(|(bt, b, bvars)| predicates_from_bound(self, bt, b, bvars))
+            .collect()
+    }
+
+    #[instrument(level = "trace", skip(self))]
+    fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool {
+        match b {
+            hir::GenericBound::Trait(poly_trait_ref, _) => {
+                let trait_ref = &poly_trait_ref.trait_ref;
+                if let Some(trait_did) = trait_ref.trait_def_id() {
+                    self.tcx.trait_may_define_assoc_type(trait_did, assoc_name)
+                } else {
+                    false
+                }
+            }
+            _ => false,
+        }
+    }
+}
+
+/// Converts a specific `GenericBound` from the AST into a set of
+/// predicates that apply to the self type. A vector is returned
+/// because this can be anywhere from zero predicates (`T: ?Sized` adds no
+/// predicates) to one (`T: Foo`) to many (`T: Bar<X = i32>` adds `T: Bar`
+/// and `<T as Bar>::X == i32`).
+fn predicates_from_bound<'tcx>(
+    astconv: &dyn AstConv<'tcx>,
+    param_ty: Ty<'tcx>,
+    bound: &'tcx hir::GenericBound<'tcx>,
+    bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
+) -> Vec<(ty::Predicate<'tcx>, Span)> {
+    let mut bounds = Bounds::default();
+    astconv.add_bounds(param_ty, [bound].into_iter(), &mut bounds, bound_vars);
+    bounds.predicates(astconv.tcx(), param_ty).collect()
+}
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 70e259b46bf..f8a62c84910 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -333,7 +333,12 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                     find_opaque_ty_constraints_for_tait(tcx, def_id)
                 }
                 // Opaque types desugared from `impl Trait`.
-                ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner), in_trait, .. }) => {
+                ItemKind::OpaqueTy(OpaqueTy {
+                    origin:
+                        hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner),
+                    in_trait,
+                    ..
+                }) => {
                     if in_trait {
                         span_bug!(item.span, "impl-trait in trait has no default")
                     } else {
@@ -378,7 +383,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
 
         Node::Field(field) => icx.to_ty(field.ty),
 
-        Node::Expr(&Expr { kind: ExprKind::Closure{..}, .. }) => tcx.typeck(def_id).node_type(hir_id),
+        Node::Expr(&Expr { kind: ExprKind::Closure { .. }, .. }) => {
+            tcx.typeck(def_id).node_type(hir_id)
+        }
 
         Node::AnonConst(_) if let Some(param) = tcx.opt_const_param_of(def_id) => {
             // We defer to `type_of` of the corresponding parameter
@@ -410,40 +417,91 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                 | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
                     if asm.operands.iter().any(|(op, _op_sp)| match op {
                         hir::InlineAsmOperand::Const { anon_const }
-                        | hir::InlineAsmOperand::SymFn { anon_const } => anon_const.hir_id == hir_id,
+                        | hir::InlineAsmOperand::SymFn { anon_const } => {
+                            anon_const.hir_id == hir_id
+                        }
                         _ => false,
                     }) =>
                 {
                     tcx.typeck(def_id).node_type(hir_id)
                 }
 
-                Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => tcx
-                    .adt_def(tcx.hir().get_parent_item(hir_id))
-                    .repr()
-                    .discr_type()
-                    .to_ty(tcx),
+                Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => {
+                    tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx)
+                }
 
-                Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, ..  })
-                    if let Node::TraitRef(trait_ref) = tcx.hir().get(
-                        tcx.hir().get_parent_node(binding_id)
-                    ) =>
+                Node::TypeBinding(
+                    binding @ &TypeBinding {
+                        hir_id: binding_id,
+                        kind: TypeBindingKind::Equality { term: Term::Const(ref e) },
+                        ..
+                    },
+                ) if let Node::TraitRef(trait_ref) =
+                    tcx.hir().get(tcx.hir().get_parent_node(binding_id))
+                    && e.hir_id == hir_id =>
                 {
-                  let Some(trait_def_id) = trait_ref.trait_def_id() else {
-                    return tcx.ty_error_with_message(DUMMY_SP, "Could not find trait");
-                  };
-                  let assoc_items = tcx.associated_items(trait_def_id);
-                  let assoc_item = assoc_items.find_by_name_and_kind(
-                    tcx, binding.ident, ty::AssocKind::Const, def_id.to_def_id(),
-                  );
-                  if let Some(assoc_item) = assoc_item {
-                    tcx.type_of(assoc_item.def_id)
-                  } else {
-                      // FIXME(associated_const_equality): add a useful error message here.
-                      tcx.ty_error_with_message(
-                        DUMMY_SP,
-                        "Could not find associated const on trait",
-                    )
-                  }
+                    let Some(trait_def_id) = trait_ref.trait_def_id() else {
+                        return tcx.ty_error_with_message(DUMMY_SP, "Could not find trait");
+                    };
+                    let assoc_items = tcx.associated_items(trait_def_id);
+                    let assoc_item = assoc_items.find_by_name_and_kind(
+                        tcx,
+                        binding.ident,
+                        ty::AssocKind::Const,
+                        def_id.to_def_id(),
+                    );
+                    if let Some(assoc_item) = assoc_item {
+                        tcx.type_of(assoc_item.def_id)
+                    } else {
+                        // FIXME(associated_const_equality): add a useful error message here.
+                        tcx.ty_error_with_message(
+                            DUMMY_SP,
+                            "Could not find associated const on trait",
+                        )
+                    }
+                }
+
+                Node::TypeBinding(
+                    binding @ &TypeBinding { hir_id: binding_id, gen_args, ref kind, .. },
+                ) if let Node::TraitRef(trait_ref) =
+                    tcx.hir().get(tcx.hir().get_parent_node(binding_id))
+                    && let Some((idx, _)) =
+                        gen_args.args.iter().enumerate().find(|(_, arg)| {
+                            if let GenericArg::Const(ct) = arg {
+                                ct.value.hir_id == hir_id
+                            } else {
+                                false
+                            }
+                        }) =>
+                {
+                    let Some(trait_def_id) = trait_ref.trait_def_id() else {
+                        return tcx.ty_error_with_message(DUMMY_SP, "Could not find trait");
+                    };
+                    let assoc_items = tcx.associated_items(trait_def_id);
+                    let assoc_item = assoc_items.find_by_name_and_kind(
+                        tcx,
+                        binding.ident,
+                        match kind {
+                            // I think `<A: T>` type bindings requires that `A` is a type
+                            TypeBindingKind::Constraint { .. }
+                            | TypeBindingKind::Equality { term: Term::Ty(..) } => {
+                                ty::AssocKind::Type
+                            }
+                            TypeBindingKind::Equality { term: Term::Const(..) } => {
+                                ty::AssocKind::Const
+                            }
+                        },
+                        def_id.to_def_id(),
+                    );
+                    if let Some(assoc_item) = assoc_item {
+                        tcx.type_of(tcx.generics_of(assoc_item.def_id).params[idx].def_id)
+                    } else {
+                        // FIXME(associated_const_equality): add a useful error message here.
+                        tcx.ty_error_with_message(
+                            DUMMY_SP,
+                            "Could not find associated const on trait",
+                        )
+                    }
                 }
 
                 Node::GenericParam(&GenericParam {
@@ -452,8 +510,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                     ..
                 }) if ct.hir_id == hir_id => tcx.type_of(tcx.hir().local_def_id(param_hir_id)),
 
-                x =>
-                  tcx.ty_error_with_message(
+                x => tcx.ty_error_with_message(
                     DUMMY_SP,
                     &format!("unexpected const parent in type_of(): {x:?}"),
                 ),
@@ -569,22 +626,22 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
         fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
             trace!(?it.def_id);
             // The opaque type itself or its children are not within its reveal scope.
-            if it.def_id != self.def_id {
-                self.check(it.def_id);
+            if it.def_id.def_id != self.def_id {
+                self.check(it.def_id.def_id);
                 intravisit::walk_item(self, it);
             }
         }
         fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
             trace!(?it.def_id);
             // The opaque type itself or its children are not within its reveal scope.
-            if it.def_id != self.def_id {
-                self.check(it.def_id);
+            if it.def_id.def_id != self.def_id {
+                self.check(it.def_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);
+            self.check(it.def_id.def_id);
             intravisit::walk_trait_item(self, it);
         }
     }
@@ -688,22 +745,22 @@ fn find_opaque_ty_constraints_for_rpit(
         fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
             trace!(?it.def_id);
             // The opaque type itself or its children are not within its reveal scope.
-            if it.def_id != self.def_id {
-                self.check(it.def_id);
+            if it.def_id.def_id != self.def_id {
+                self.check(it.def_id.def_id);
                 intravisit::walk_item(self, it);
             }
         }
         fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
             trace!(?it.def_id);
             // The opaque type itself or its children are not within its reveal scope.
-            if it.def_id != self.def_id {
-                self.check(it.def_id);
+            if it.def_id.def_id != self.def_id {
+                self.check(it.def_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);
+            self.check(it.def_id.def_id);
             intravisit::walk_trait_item(self, it);
         }
     }
diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
index 8428e466406..8428e466406 100644
--- a/compiler/rustc_typeck/src/constrained_generic_params.rs
+++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 44df47e2fa0..44df47e2fa0 100644
--- a/compiler/rustc_typeck/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_analysis/src/expr_use_visitor.rs
index f483342b445..f483342b445 100644
--- a/compiler/rustc_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_analysis/src/expr_use_visitor.rs
diff --git a/compiler/rustc_typeck/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
index 7b080dc2942..7b080dc2942 100644
--- a/compiler/rustc_typeck/src/hir_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
diff --git a/compiler/rustc_typeck/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
index 9fee1eaaec9..c499364056f 100644
--- a/compiler/rustc_typeck/src/impl_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
@@ -58,10 +58,10 @@ fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     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);
-            enforce_impl_items_are_distinct(tcx, id.def_id);
+            enforce_impl_params_are_constrained(tcx, id.def_id.def_id);
+            enforce_impl_items_are_distinct(tcx, id.def_id.def_id);
             if min_specialization {
-                check_min_specialization(tcx, id.def_id);
+                check_min_specialization(tcx, id.def_id.def_id);
             }
         }
     }
diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index 2741d9f776c..5bebd7dee09 100644
--- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -423,13 +423,10 @@ fn trait_predicate_kind<'tcx>(
     predicate: ty::Predicate<'tcx>,
 ) -> Option<TraitSpecializationKind> {
     match predicate.kind().skip_binder() {
-        ty::PredicateKind::Trait(ty::TraitPredicate {
-            trait_ref,
-            constness: ty::BoundConstness::NotConst,
-            polarity: _,
-        }) => Some(tcx.trait_def(trait_ref.def_id).specialization_kind),
-        ty::PredicateKind::Trait(_)
-        | ty::PredicateKind::RegionOutlives(_)
+        ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref, constness: _, polarity: _ }) => {
+            Some(tcx.trait_def(trait_ref.def_id).specialization_kind)
+        }
+        ty::PredicateKind::RegionOutlives(_)
         | ty::PredicateKind::TypeOutlives(_)
         | ty::PredicateKind::Projection(_)
         | ty::PredicateKind::WellFormed(_)
diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index b1ce972e1d6..1859473166a 100644
--- a/compiler/rustc_typeck/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -64,9 +64,7 @@ This API is completely unstable and subject to change.
 #![feature(if_let_guard)]
 #![feature(is_sorted)]
 #![feature(iter_intersperse)]
-#![cfg_attr(bootstrap, feature(label_break_value))]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(min_specialization)]
 #![feature(never_type)]
 #![feature(once_cell)]
diff --git a/compiler/rustc_typeck/src/mem_categorization.rs b/compiler/rustc_hir_analysis/src/mem_categorization.rs
index ced919f66db..46b49647836 100644
--- a/compiler/rustc_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_hir_analysis/src/mem_categorization.rs
@@ -265,6 +265,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment)
     }
 
+    #[instrument(level = "debug", skip(self, previous))]
     fn cat_expr_adjusted_with<F>(
         &self,
         expr: &hir::Expr<'_>,
@@ -274,7 +275,6 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
     where
         F: FnOnce() -> McResult<PlaceWithHirId<'tcx>>,
     {
-        debug!("cat_expr_adjusted_with({:?}): {:?}", adjustment, expr);
         let target = self.resolve_vars_if_possible(adjustment.target);
         match adjustment.kind {
             adjustment::Adjust::Deref(overloaded) => {
@@ -299,6 +299,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         }
     }
 
+    #[instrument(level = "debug", skip(self))]
     pub(crate) fn cat_expr_unadjusted(
         &self,
         expr: &hir::Expr<'_>,
@@ -387,6 +388,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         }
     }
 
+    #[instrument(level = "debug", skip(self, span))]
     pub(crate) fn cat_res(
         &self,
         hir_id: hir::HirId,
@@ -394,8 +396,6 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         expr_ty: Ty<'tcx>,
         res: Res,
     ) -> McResult<PlaceWithHirId<'tcx>> {
-        debug!("cat_res: id={:?} expr={:?} def={:?}", hir_id, expr_ty, res);
-
         match res {
             Res::Def(
                 DefKind::Ctor(..)
@@ -475,13 +475,12 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         ret
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn cat_overloaded_place(
         &self,
         expr: &hir::Expr<'_>,
         base: &hir::Expr<'_>,
     ) -> McResult<PlaceWithHirId<'tcx>> {
-        debug!("cat_overloaded_place(expr={:?}, base={:?})", expr, base);
-
         // Reconstruct the output assuming it's a reference with the
         // same region and mutability as the receiver. This holds for
         // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
@@ -497,13 +496,12 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         self.cat_deref(expr, base)
     }
 
+    #[instrument(level = "debug", skip(self, node))]
     fn cat_deref(
         &self,
         node: &impl HirNode,
         base_place: PlaceWithHirId<'tcx>,
     ) -> McResult<PlaceWithHirId<'tcx>> {
-        debug!("cat_deref: base_place={:?}", base_place);
-
         let base_curr_ty = base_place.place.ty();
         let deref_ty = match base_curr_ty.builtin_deref(true) {
             Some(mt) => mt.ty,
@@ -562,7 +560,8 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
             Res::Def(DefKind::Ctor(CtorOf::Struct, ..), _)
             | Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
             | Res::SelfCtor(..)
-            | Res::SelfTy { .. } => {
+            | Res::SelfTyParam { .. }
+            | Res::SelfTyAlias { .. } => {
                 // Structs and Unions have only have one variant.
                 Ok(VariantIdx::new(0))
             }
diff --git a/compiler/rustc_typeck/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
index 7534482cce9..7534482cce9 100644
--- a/compiler/rustc_typeck/src/outlives/explicit.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
diff --git a/compiler/rustc_typeck/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
index 064a70107fe..064a70107fe 100644
--- a/compiler/rustc_typeck/src/outlives/implicit_infer.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
diff --git a/compiler/rustc_typeck/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs
index e50c267659e..e50c267659e 100644
--- a/compiler/rustc_typeck/src/outlives/mod.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs
diff --git a/compiler/rustc_typeck/src/outlives/test.rs b/compiler/rustc_hir_analysis/src/outlives/test.rs
index eb0e1203405..eb0e1203405 100644
--- a/compiler/rustc_typeck/src/outlives/test.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/test.rs
diff --git a/compiler/rustc_typeck/src/outlives/utils.rs b/compiler/rustc_hir_analysis/src/outlives/utils.rs
index 3e8d023fb55..0409c7081dc 100644
--- a/compiler/rustc_typeck/src/outlives/utils.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/utils.rs
@@ -96,6 +96,23 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
                             .or_insert(span);
                     }
 
+                    Component::Opaque(def_id, substs) => {
+                        // This would arise from something like:
+                        //
+                        // ```rust
+                        // type Opaque<T> = impl Sized;
+                        // fn defining<T>() -> Opaque<T> {}
+                        // struct Ss<'a, T>(&'a Opaque<T>);
+                        // ```
+                        //
+                        // Here we want to have an implied bound `Opaque<T>: 'a`
+
+                        let ty = tcx.mk_opaque(def_id, substs);
+                        required_predicates
+                            .entry(ty::OutlivesPredicate(ty.into(), outlived_region))
+                            .or_insert(span);
+                    }
+
                     Component::EscapingProjection(_) => {
                         // As above, but the projection involves
                         // late-bound regions.  Therefore, the WF
diff --git a/compiler/rustc_typeck/src/structured_errors.rs b/compiler/rustc_hir_analysis/src/structured_errors.rs
index 0b46fce1735..0b46fce1735 100644
--- a/compiler/rustc_typeck/src/structured_errors.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors.rs
diff --git a/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs b/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs
index 324df313ef1..324df313ef1 100644
--- a/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs
diff --git a/compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs b/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs
index bb608805488..bb608805488 100644
--- a/compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs
diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
index 4359124646d..4359124646d 100644
--- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
diff --git a/compiler/rustc_typeck/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs
index eaf0310d57a..eaf0310d57a 100644
--- a/compiler/rustc_typeck/src/variance/constraints.rs
+++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs
diff --git a/compiler/rustc_typeck/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs
index 82103c5a03b..82103c5a03b 100644
--- a/compiler/rustc_typeck/src/variance/mod.rs
+++ b/compiler/rustc_hir_analysis/src/variance/mod.rs
diff --git a/compiler/rustc_typeck/src/variance/solve.rs b/compiler/rustc_hir_analysis/src/variance/solve.rs
index 97aca621aa2..97aca621aa2 100644
--- a/compiler/rustc_typeck/src/variance/solve.rs
+++ b/compiler/rustc_hir_analysis/src/variance/solve.rs
diff --git a/compiler/rustc_typeck/src/variance/terms.rs b/compiler/rustc_hir_analysis/src/variance/terms.rs
index 1f763011e06..1f763011e06 100644
--- a/compiler/rustc_typeck/src/variance/terms.rs
+++ b/compiler/rustc_hir_analysis/src/variance/terms.rs
diff --git a/compiler/rustc_typeck/src/variance/test.rs b/compiler/rustc_hir_analysis/src/variance/test.rs
index 2ba87db880b..2ba87db880b 100644
--- a/compiler/rustc_typeck/src/variance/test.rs
+++ b/compiler/rustc_hir_analysis/src/variance/test.rs
diff --git a/compiler/rustc_typeck/src/variance/xform.rs b/compiler/rustc_hir_analysis/src/variance/xform.rs
index 027f0859fcd..027f0859fcd 100644
--- a/compiler/rustc_typeck/src/variance/xform.rs
+++ b/compiler/rustc_hir_analysis/src/variance/xform.rs
diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs
index 2c9e21f769f..83dd9a67e61 100644
--- a/compiler/rustc_incremental/src/lib.rs
+++ b/compiler/rustc_incremental/src/lib.rs
@@ -2,7 +2,6 @@
 
 #![deny(missing_docs)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
 
diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs
index 710c4a01b24..09163e4f25f 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);
+            dirty_clean_visitor.check_item(id.def_id.def_id);
         }
 
         for id in crate_items.trait_items() {
-            dirty_clean_visitor.check_item(id.def_id);
+            dirty_clean_visitor.check_item(id.def_id.def_id);
         }
 
         for id in crate_items.impl_items() {
-            dirty_clean_visitor.check_item(id.def_id);
+            dirty_clean_visitor.check_item(id.def_id.def_id);
         }
 
         for id in crate_items.foreign_items() {
-            dirty_clean_visitor.check_item(id.def_id);
+            dirty_clean_visitor.check_item(id.def_id.def_id);
         }
 
         let mut all_attrs = FindAllAttrs { tcx, found_attrs: vec![] };
diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs
index a00d7bd6801..23a4c1f0696 100644
--- a/compiler/rustc_index/src/lib.rs
+++ b/compiler/rustc_index/src/lib.rs
@@ -1,9 +1,7 @@
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
 #![feature(allow_internal_unstable)]
-#![feature(bench_black_box)]
 #![feature(extend_one)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(min_specialization)]
 #![feature(new_uninit)]
 #![feature(step_trait)]
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 82099d9e3f3..99de5b65981 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -1862,7 +1862,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
         // In some (most?) cases cause.body_id points to actual body, but in some cases
         // it's an actual definition. According to the comments (e.g. in
-        // librustc_typeck/check/compare_method.rs:compare_predicate_entailment) the latter
+        // rustc_hir_analysis/check/compare_method.rs:compare_predicate_entailment) the latter
         // is relied upon by some other code. This might (or might not) need cleanup.
         let body_owner_def_id =
             self.tcx.hir().opt_local_def_id(cause.body_id).unwrap_or_else(|| {
@@ -2440,7 +2440,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                         // We do this to avoid suggesting code that ends up as `T: 'a'b`,
                         // instead we suggest `T: 'a + 'b` in that case.
                         let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
-                        let ast_generics = self.tcx.hir().get_generics(hir_id.owner);
+                        let ast_generics = self.tcx.hir().get_generics(hir_id.owner.def_id);
                         let bounds =
                             ast_generics.and_then(|g| g.bounds_span_for_suggestions(def_id));
                         // `sp` only covers `T`, change it so that it covers
@@ -2481,6 +2481,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         let labeled_user_string = match bound_kind {
             GenericKind::Param(ref p) => format!("the parameter type `{}`", p),
             GenericKind::Projection(ref p) => format!("the associated type `{}`", p),
+            GenericKind::Opaque(def_id, substs) => {
+                format!("the opaque type `{}`", self.tcx.def_path_str_with_substs(def_id, substs))
+            }
         };
 
         if let Some(SubregionOrigin::CompareImplItemObligation {
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 baa97d72a4b..03116d59bf4 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
@@ -1021,7 +1021,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
                                     }
                                     // There cannot be inference variables in the self type,
                                     // so there's nothing for us to do here.
-                                    Res::SelfTy { .. } => {}
+                                    Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => {}
                                     _ => warn!(
                                         "unexpected path: def={:?} substs={:?} path={:?}",
                                         def, substs, path,
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 ae56bea6f86..2ccfcd51b11 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
@@ -185,8 +185,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             | ObligationCauseCode::BlockTailExpression(hir_id) = cause.code()
             {
                 let parent_id = tcx.hir().get_parent_item(*hir_id);
-                let parent_id = tcx.hir().local_def_id_to_hir_id(parent_id);
-                if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id) {
+                if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id.into()) {
                     let mut span: MultiSpan = fn_decl.output.span().into();
                     let mut add_label = true;
                     if let hir::FnRetTy::Return(ty) = fn_decl.output {
@@ -415,7 +414,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         let tcx = self.tcx();
         match tcx.hir().get_if_local(def_id) {
             Some(Node::ImplItem(impl_item)) => {
-                match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id())) {
+                match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id()).def_id)
+                {
                     Some(Node::Item(Item {
                         kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
                         ..
@@ -425,7 +425,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             }
             Some(Node::TraitItem(trait_item)) => {
                 let trait_did = tcx.hir().get_parent_item(trait_item.hir_id());
-                match tcx.hir().find_by_def_id(trait_did) {
+                match tcx.hir().find_by_def_id(trait_did.def_id) {
                     Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {
                         // The method being called is defined in the `trait`, but the `'static`
                         // obligation comes from the `impl`. Find that `impl` so that we can point
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
index a6a39d062d5..778c4fc01c8 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
@@ -156,7 +156,8 @@ impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
                 [segment]
                     if matches!(
                         segment.res,
-                        Res::SelfTy { trait_: _, alias_to: _ }
+                        Res::SelfTyParam { .. }
+                            | Res::SelfTyAlias { .. }
                             | Res::Def(hir::def::DefKind::TyParam, _)
                     ) =>
                 {
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 55cf9b7a2ea..b9fd79e0d2f 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -16,6 +16,7 @@ use rustc_data_structures::undo_log::Rollback;
 use rustc_data_structures::unify as ut;
 use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::hir_id::OwnerId;
 use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
 use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
@@ -580,12 +581,12 @@ impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
 }
 
 impl<'tcx> InferCtxtBuilder<'tcx> {
-    /// Used only by `rustc_typeck` during body type-checking/inference,
+    /// Used only by `rustc_hir_analysis` during body type-checking/inference,
     /// will initialize `in_progress_typeck_results` with fresh `TypeckResults`.
     /// Will also change the scope for opaque type defining use checks to the given owner.
-    pub fn with_fresh_in_progress_typeck_results(mut self, table_owner: LocalDefId) -> Self {
+    pub fn with_fresh_in_progress_typeck_results(mut self, table_owner: OwnerId) -> Self {
         self.fresh_typeck_results = Some(RefCell::new(ty::TypeckResults::new(table_owner)));
-        self.with_opaque_type_inference(DefiningAnchor::Bind(table_owner))
+        self.with_opaque_type_inference(DefiningAnchor::Bind(table_owner.def_id))
     }
 
     /// Whenever the `InferCtxt` should be able to handle defining uses of opaque types,
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index 76c340a5efa..9bf92f08aa5 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -616,7 +616,7 @@ fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hi
     let scope = tcx.hir().get_defining_scope(opaque_hir_id);
     // We walk up the node tree until we hit the root or the scope of the opaque type.
     while hir_id != scope && hir_id != hir::CRATE_HIR_ID {
-        hir_id = tcx.hir().local_def_id_to_hir_id(tcx.hir().get_parent_item(hir_id));
+        hir_id = tcx.hir().get_parent_item(hir_id).into();
     }
     // Syntactically, we are allowed to define the concrete type if:
     let res = hir_id == scope;
diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs
index b2d7f4a663a..14ee9f05190 100644
--- a/compiler/rustc_infer/src/infer/outlives/components.rs
+++ b/compiler/rustc_infer/src/infer/outlives/components.rs
@@ -3,8 +3,9 @@
 // RFC for reference.
 
 use rustc_data_structures::sso::SsoHashSet;
+use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::{self, SubstsRef, Ty, TyCtxt, TypeVisitable};
 use smallvec::{smallvec, SmallVec};
 
 #[derive(Debug)]
@@ -45,6 +46,8 @@ pub enum Component<'tcx> {
     // them. This gives us room to improve the regionck reasoning in
     // the future without breaking backwards compat.
     EscapingProjection(Vec<Component<'tcx>>),
+
+    Opaque(DefId, SubstsRef<'tcx>),
 }
 
 /// Push onto `out` all the things that must outlive `'a` for the condition
@@ -120,6 +123,17 @@ fn compute_components<'tcx>(
                 out.push(Component::Param(p));
             }
 
+            // Ignore lifetimes found in opaque types. Opaque types can
+            // have lifetimes in their substs which their hidden type doesn't
+            // actually use. If we inferred that an opaque type is outlived by
+            // its parameter lifetimes, then we could prove that any lifetime
+            // outlives any other lifetime, which is unsound.
+            // See https://github.com/rust-lang/rust/issues/84305 for
+            // more details.
+            ty::Opaque(def_id, substs) => {
+                out.push(Component::Opaque(def_id, substs));
+            },
+
             // For projections, we prefer to generate an obligation like
             // `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the
             // regionck more ways to prove that it holds. However,
@@ -168,7 +182,6 @@ fn compute_components<'tcx>(
             ty::Float(..) |       // OutlivesScalar
             ty::Never |           // ...
             ty::Adt(..) |         // OutlivesNominalType
-            ty::Opaque(..) |      // OutlivesNominalType (ish)
             ty::Foreign(..) |     // OutlivesNominalType
             ty::Str |             // OutlivesScalar (ish)
             ty::Slice(..) |       // ...
diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs
index 872886da362..113d4f09066 100644
--- a/compiler/rustc_infer/src/infer/outlives/env.rs
+++ b/compiler/rustc_infer/src/infer/outlives/env.rs
@@ -53,6 +53,7 @@ pub struct OutlivesEnvironment<'tcx> {
 }
 
 /// Builder of OutlivesEnvironment.
+#[derive(Debug)]
 struct OutlivesEnvironmentBuilder<'tcx> {
     param_env: ty::ParamEnv<'tcx>,
     region_relation: TransitiveRelationBuilder<Region<'tcx>>,
@@ -109,6 +110,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
 
 impl<'a, 'tcx> OutlivesEnvironmentBuilder<'tcx> {
     #[inline]
+    #[instrument(level = "debug")]
     fn build(self) -> OutlivesEnvironment<'tcx> {
         OutlivesEnvironment {
             param_env: self.param_env,
@@ -140,6 +142,10 @@ impl<'a, 'tcx> OutlivesEnvironmentBuilder<'tcx> {
                     self.region_bound_pairs
                         .insert(ty::OutlivesPredicate(GenericKind::Projection(projection_b), r_a));
                 }
+                OutlivesBound::RegionSubOpaque(r_a, def_id, substs) => {
+                    self.region_bound_pairs
+                        .insert(ty::OutlivesPredicate(GenericKind::Opaque(def_id, substs), r_a));
+                }
                 OutlivesBound::RegionSubRegion(r_a, r_b) => {
                     if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) {
                         infcx
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index 5bd1774f6b1..229b69b92e6 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -68,10 +68,11 @@ use crate::infer::{
 };
 use crate::traits::{ObligationCause, ObligationCauseCode};
 use rustc_data_structures::undo_log::UndoLogs;
+use rustc_hir::def_id::DefId;
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::{self, Region, SubstsRef, Ty, TyCtxt, TypeVisitable};
 use smallvec::smallvec;
 
 impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
@@ -283,6 +284,9 @@ where
                 Component::Param(param_ty) => {
                     self.param_ty_must_outlive(origin, region, *param_ty);
                 }
+                Component::Opaque(def_id, substs) => {
+                    self.opaque_must_outlive(*def_id, substs, origin, region)
+                }
                 Component::Projection(projection_ty) => {
                     self.projection_must_outlive(origin, region, *projection_ty);
                 }
@@ -314,17 +318,69 @@ where
         );
 
         let generic = GenericKind::Param(param_ty);
-        let verify_bound = self.verify_bound.generic_bound(generic);
+        let verify_bound = self.verify_bound.param_bound(param_ty);
         self.delegate.push_verify(origin, generic, region, verify_bound);
     }
 
     #[instrument(level = "debug", skip(self))]
+    fn opaque_must_outlive(
+        &mut self,
+        def_id: DefId,
+        substs: SubstsRef<'tcx>,
+        origin: infer::SubregionOrigin<'tcx>,
+        region: ty::Region<'tcx>,
+    ) {
+        self.generic_must_outlive(
+            origin,
+            region,
+            GenericKind::Opaque(def_id, substs),
+            def_id,
+            substs,
+            true,
+            |ty| match *ty.kind() {
+                ty::Opaque(def_id, substs) => (def_id, substs),
+                _ => bug!("expected only projection types from env, not {:?}", ty),
+            },
+        );
+    }
+
+    #[instrument(level = "debug", skip(self))]
     fn projection_must_outlive(
         &mut self,
         origin: infer::SubregionOrigin<'tcx>,
         region: ty::Region<'tcx>,
         projection_ty: ty::ProjectionTy<'tcx>,
     ) {
+        self.generic_must_outlive(
+            origin,
+            region,
+            GenericKind::Projection(projection_ty),
+            projection_ty.item_def_id,
+            projection_ty.substs,
+            false,
+            |ty| match ty.kind() {
+                ty::Projection(projection_ty) => (projection_ty.item_def_id, projection_ty.substs),
+                _ => bug!("expected only projection types from env, not {:?}", ty),
+            },
+        );
+    }
+
+    #[instrument(level = "debug", skip(self, filter))]
+    fn generic_must_outlive(
+        &mut self,
+        origin: infer::SubregionOrigin<'tcx>,
+        region: ty::Region<'tcx>,
+        generic: GenericKind<'tcx>,
+        def_id: DefId,
+        substs: SubstsRef<'tcx>,
+        is_opaque: bool,
+        filter: impl Fn(Ty<'tcx>) -> (DefId, SubstsRef<'tcx>),
+    ) {
+        // An optimization for a common case with opaque types.
+        if substs.is_empty() {
+            return;
+        }
+
         // This case is thorny for inference. The fundamental problem is
         // that there are many cases where we have choice, and inference
         // doesn't like choice (the current region inference in
@@ -343,16 +399,15 @@ where
         // These are guaranteed to apply, no matter the inference
         // results.
         let trait_bounds: Vec<_> =
-            self.verify_bound.projection_declared_bounds_from_trait(projection_ty).collect();
+            self.verify_bound.declared_region_bounds(def_id, substs).collect();
 
         debug!(?trait_bounds);
 
         // Compute the bounds we can derive from the environment. This
         // is an "approximate" match -- in some cases, these bounds
         // may not apply.
-        let mut approx_env_bounds =
-            self.verify_bound.projection_approx_declared_bounds_from_env(projection_ty);
-        debug!("projection_must_outlive: approx_env_bounds={:?}", approx_env_bounds);
+        let mut approx_env_bounds = self.verify_bound.approx_declared_bounds_from_env(generic);
+        debug!(?approx_env_bounds);
 
         // Remove outlives bounds that we get from the environment but
         // which are also deducible from the trait. This arises (cc
@@ -366,14 +421,8 @@ where
             // If the declaration is `trait Trait<'b> { type Item: 'b; }`, then `projection_declared_bounds_from_trait`
             // will be invoked with `['b => ^1]` and so we will get `^1` returned.
             let bound = bound_outlives.skip_binder();
-            match *bound.0.kind() {
-                ty::Projection(projection_ty) => self
-                    .verify_bound
-                    .projection_declared_bounds_from_trait(projection_ty)
-                    .all(|r| r != bound.1),
-
-                _ => panic!("expected only projection types from env, not {:?}", bound.0),
-            }
+            let (def_id, substs) = filter(bound.0);
+            self.verify_bound.declared_region_bounds(def_id, substs).all(|r| r != bound.1)
         });
 
         // If declared bounds list is empty, the only applicable rule is
@@ -390,29 +439,11 @@ where
         // the problem is to add `T: 'r`, which isn't true. So, if there are no
         // inference variables, we use a verify constraint instead of adding
         // edges, which winds up enforcing the same condition.
-        let needs_infer = projection_ty.needs_infer();
-        if approx_env_bounds.is_empty() && trait_bounds.is_empty() && needs_infer {
-            debug!("projection_must_outlive: no declared bounds");
-
-            let constraint = origin.to_constraint_category();
-            for k in projection_ty.substs {
-                match k.unpack() {
-                    GenericArgKind::Lifetime(lt) => {
-                        self.delegate.push_sub_region_constraint(
-                            origin.clone(),
-                            region,
-                            lt,
-                            constraint,
-                        );
-                    }
-                    GenericArgKind::Type(ty) => {
-                        self.type_must_outlive(origin.clone(), ty, region, constraint);
-                    }
-                    GenericArgKind::Const(_) => {
-                        // Const parameters don't impose constraints.
-                    }
-                }
-            }
+        let needs_infer = substs.needs_infer();
+        if approx_env_bounds.is_empty() && trait_bounds.is_empty() && (needs_infer || is_opaque) {
+            debug!("no declared bounds");
+
+            self.substs_must_outlive(substs, origin, region);
 
             return;
         }
@@ -442,8 +473,8 @@ where
                 .all(|b| b == Some(trait_bounds[0]))
         {
             let unique_bound = trait_bounds[0];
-            debug!("projection_must_outlive: unique trait bound = {:?}", unique_bound);
-            debug!("projection_must_outlive: unique declared bound appears in trait ref");
+            debug!(?unique_bound);
+            debug!("unique declared bound appears in trait ref");
             let category = origin.to_constraint_category();
             self.delegate.push_sub_region_constraint(origin, region, unique_bound, category);
             return;
@@ -454,11 +485,42 @@ where
         // projection outlive; in some cases, this may add insufficient
         // edges into the inference graph, leading to inference failures
         // even though a satisfactory solution exists.
-        let generic = GenericKind::Projection(projection_ty);
-        let verify_bound = self.verify_bound.generic_bound(generic);
+        let verify_bound = self.verify_bound.projection_opaque_bounds(
+            generic,
+            def_id,
+            substs,
+            &mut Default::default(),
+        );
         debug!("projection_must_outlive: pushing {:?}", verify_bound);
         self.delegate.push_verify(origin, generic, region, verify_bound);
     }
+
+    fn substs_must_outlive(
+        &mut self,
+        substs: SubstsRef<'tcx>,
+        origin: infer::SubregionOrigin<'tcx>,
+        region: ty::Region<'tcx>,
+    ) {
+        let constraint = origin.to_constraint_category();
+        for k in substs {
+            match k.unpack() {
+                GenericArgKind::Lifetime(lt) => {
+                    self.delegate.push_sub_region_constraint(
+                        origin.clone(),
+                        region,
+                        lt,
+                        constraint,
+                    );
+                }
+                GenericArgKind::Type(ty) => {
+                    self.type_must_outlive(origin.clone(), ty, region, constraint);
+                }
+                GenericArgKind::Const(_) => {
+                    // Const parameters don't impose constraints.
+                }
+            }
+        }
+    }
 }
 
 impl<'cx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'cx, 'tcx> {
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index e344e192a76..f470b2eb8c1 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -2,11 +2,10 @@ use crate::infer::outlives::components::{compute_components_recursive, Component
 use crate::infer::outlives::env::RegionBoundPairs;
 use crate::infer::region_constraints::VerifyIfEq;
 use crate::infer::{GenericKind, VerifyBound};
-use rustc_data_structures::captures::Captures;
 use rustc_data_structures::sso::SsoHashSet;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::GenericArg;
-use rustc_middle::ty::{self, EarlyBinder, OutlivesPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, EarlyBinder, OutlivesPredicate, SubstsRef, Ty, TyCtxt};
 
 use smallvec::smallvec;
 
@@ -38,20 +37,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
         Self { tcx, region_bound_pairs, implicit_region_bound, param_env }
     }
 
-    /// Returns a "verify bound" that encodes what we know about
-    /// `generic` and the regions it outlives.
-    pub fn generic_bound(&self, generic: GenericKind<'tcx>) -> VerifyBound<'tcx> {
-        let mut visited = SsoHashSet::new();
-        match generic {
-            GenericKind::Param(param_ty) => self.param_bound(param_ty),
-            GenericKind::Projection(projection_ty) => {
-                self.projection_bound(projection_ty, &mut visited)
-            }
-        }
-    }
-
     #[instrument(level = "debug", skip(self))]
-    fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
+    pub fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
         // Start with anything like `T: 'a` we can scrape from the
         // environment. If the environment contains something like
         // `for<'a> T: 'a`, then we know that `T` outlives everything.
@@ -105,41 +92,31 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
     /// the clause from the environment only applies if `'0 = 'a`,
     /// which we don't know yet. But we would still include `'b` in
     /// this list.
-    pub fn projection_approx_declared_bounds_from_env(
+    pub fn approx_declared_bounds_from_env(
         &self,
-        projection_ty: ty::ProjectionTy<'tcx>,
+        generic: GenericKind<'tcx>,
     ) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
-        let projection_ty = GenericKind::Projection(projection_ty).to_ty(self.tcx);
+        let projection_ty = generic.to_ty(self.tcx);
         let erased_projection_ty = self.tcx.erase_regions(projection_ty);
         self.declared_generic_bounds_from_env_for_erased_ty(erased_projection_ty)
     }
 
-    /// Searches the where-clauses in scope for regions that
-    /// `projection_ty` is known to outlive. Currently requires an
-    /// exact match.
-    pub fn projection_declared_bounds_from_trait(
+    #[instrument(level = "debug", skip(self, visited))]
+    pub fn projection_opaque_bounds(
         &self,
-        projection_ty: ty::ProjectionTy<'tcx>,
-    ) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'tcx> {
-        self.declared_projection_bounds_from_trait(projection_ty)
-    }
-
-    pub fn projection_bound(
-        &self,
-        projection_ty: ty::ProjectionTy<'tcx>,
+        generic: GenericKind<'tcx>,
+        def_id: DefId,
+        substs: SubstsRef<'tcx>,
         visited: &mut SsoHashSet<GenericArg<'tcx>>,
     ) -> VerifyBound<'tcx> {
-        debug!("projection_bound(projection_ty={:?})", projection_ty);
-
-        let projection_ty_as_ty =
-            self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs);
+        let generic_ty = generic.to_ty(self.tcx);
 
         // Search the env for where clauses like `P: 'a`.
-        let env_bounds = self
-            .projection_approx_declared_bounds_from_env(projection_ty)
+        let projection_opaque_bounds = self
+            .approx_declared_bounds_from_env(generic)
             .into_iter()
             .map(|binder| {
-                if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == projection_ty_as_ty {
+                if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == generic_ty {
                     // Micro-optimize if this is an exact match (this
                     // occurs often when there are no region variables
                     // involved).
@@ -149,21 +126,19 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
                     VerifyBound::IfEq(verify_if_eq_b)
                 }
             });
-
         // Extend with bounds that we can find from the trait.
-        let trait_bounds = self
-            .projection_declared_bounds_from_trait(projection_ty)
-            .map(|r| VerifyBound::OutlivedBy(r));
+        let trait_bounds =
+            self.declared_region_bounds(def_id, substs).map(|r| VerifyBound::OutlivedBy(r));
 
         // see the extensive comment in projection_must_outlive
         let recursive_bound = {
             let mut components = smallvec![];
-            let ty = self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs);
-            compute_components_recursive(self.tcx, ty.into(), &mut components, visited);
+            compute_components_recursive(self.tcx, generic_ty.into(), &mut components, visited);
             self.bound_from_components(&components, visited)
         };
 
-        VerifyBound::AnyBound(env_bounds.chain(trait_bounds).collect()).or(recursive_bound)
+        VerifyBound::AnyBound(projection_opaque_bounds.chain(trait_bounds).collect())
+            .or(recursive_bound)
     }
 
     fn bound_from_components(
@@ -195,7 +170,18 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
         match *component {
             Component::Region(lt) => VerifyBound::OutlivedBy(lt),
             Component::Param(param_ty) => self.param_bound(param_ty),
-            Component::Projection(projection_ty) => self.projection_bound(projection_ty, visited),
+            Component::Opaque(did, substs) => self.projection_opaque_bounds(
+                GenericKind::Opaque(did, substs),
+                did,
+                substs,
+                visited,
+            ),
+            Component::Projection(projection_ty) => self.projection_opaque_bounds(
+                GenericKind::Projection(projection_ty),
+                projection_ty.item_def_id,
+                projection_ty.substs,
+                visited,
+            ),
             Component::EscapingProjection(ref components) => {
                 self.bound_from_components(components, visited)
             }
@@ -293,30 +279,6 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
     /// }
     /// ```
     ///
-    /// then this function would return `'x`. This is subject to the
-    /// limitations around higher-ranked bounds described in
-    /// `region_bounds_declared_on_associated_item`.
-    fn declared_projection_bounds_from_trait(
-        &self,
-        projection_ty: ty::ProjectionTy<'tcx>,
-    ) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'tcx> {
-        debug!("projection_bounds(projection_ty={:?})", projection_ty);
-        let tcx = self.tcx;
-        self.region_bounds_declared_on_associated_item(projection_ty.item_def_id)
-            .map(move |r| EarlyBinder(r).subst(tcx, projection_ty.substs))
-    }
-
-    /// Given the `DefId` of an associated item, returns any region
-    /// bounds attached to that associated item from the trait definition.
-    ///
-    /// For example:
-    ///
-    /// ```rust
-    /// trait Foo<'a> {
-    ///     type Bar: 'a;
-    /// }
-    /// ```
-    ///
     /// If we were given the `DefId` of `Foo::Bar`, we would return
     /// `'a`. You could then apply the substitutions from the
     /// projection to convert this into your namespace. This also
@@ -336,17 +298,20 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
     ///
     /// This is for simplicity, and because we are not really smart
     /// enough to cope with such bounds anywhere.
-    fn region_bounds_declared_on_associated_item(
+    pub fn declared_region_bounds(
         &self,
-        assoc_item_def_id: DefId,
+        def_id: DefId,
+        substs: SubstsRef<'tcx>,
     ) -> impl Iterator<Item = ty::Region<'tcx>> {
         let tcx = self.tcx;
-        let bounds = tcx.item_bounds(assoc_item_def_id);
+        let bounds = tcx.item_bounds(def_id);
+        trace!("{:#?}", bounds);
         bounds
             .into_iter()
             .filter_map(|p| p.to_opt_type_outlives())
             .filter_map(|p| p.no_bound_vars())
             .map(|b| b.1)
+            .map(move |r| EarlyBinder(r).subst(tcx, substs))
     }
 
     /// Searches through a predicate list for a predicate `T: 'a`.
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index e43d28ee56e..67b3da68720 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -12,8 +12,10 @@ use rustc_data_structures::intern::Interned;
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::undo_log::UndoLogs;
 use rustc_data_structures::unify as ut;
+use rustc_hir::def_id::DefId;
 use rustc_index::vec::IndexVec;
 use rustc_middle::infer::unify_key::{RegionVidKey, UnifiedRegion};
+use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::ReStatic;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{ReLateBound, ReVar};
@@ -168,6 +170,7 @@ pub struct Verify<'tcx> {
 pub enum GenericKind<'tcx> {
     Param(ty::ParamTy),
     Projection(ty::ProjectionTy<'tcx>),
+    Opaque(DefId, SubstsRef<'tcx>),
 }
 
 /// Describes the things that some `GenericKind` value `G` is known to
@@ -747,6 +750,9 @@ impl<'tcx> fmt::Debug for GenericKind<'tcx> {
         match *self {
             GenericKind::Param(ref p) => write!(f, "{:?}", p),
             GenericKind::Projection(ref p) => write!(f, "{:?}", p),
+            GenericKind::Opaque(def_id, substs) => ty::tls::with(|tcx| {
+                write!(f, "{}", tcx.def_path_str_with_substs(def_id, tcx.lift(substs).unwrap()))
+            }),
         }
     }
 }
@@ -756,6 +762,9 @@ impl<'tcx> fmt::Display for GenericKind<'tcx> {
         match *self {
             GenericKind::Param(ref p) => write!(f, "{}", p),
             GenericKind::Projection(ref p) => write!(f, "{}", p),
+            GenericKind::Opaque(def_id, substs) => ty::tls::with(|tcx| {
+                write!(f, "{}", tcx.def_path_str_with_substs(def_id, tcx.lift(substs).unwrap()))
+            }),
         }
     }
 }
@@ -765,6 +774,7 @@ impl<'tcx> GenericKind<'tcx> {
         match *self {
             GenericKind::Param(ref p) => p.to_ty(tcx),
             GenericKind::Projection(ref p) => tcx.mk_projection(p.item_def_id, p.substs),
+            GenericKind::Opaque(def_id, substs) => tcx.mk_opaque(def_id, substs),
         }
     }
 }
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index 909a597e221..e040634edb0 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -2,7 +2,7 @@
 //!
 //! - **Type inference.** The type inference code can be found in the `infer` module;
 //!   this code handles low-level equality and subtyping operations. The
-//!   type check pass in the compiler is found in the `rustc_typeck` crate.
+//!   type check pass in the compiler is found in the `rustc_hir_analysis` crate.
 //!
 //! For more information about how rustc works, see the [rustc dev guide].
 //!
@@ -17,9 +17,7 @@
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
 #![feature(extend_one)]
-#![cfg_attr(bootstrap, feature(label_break_value))]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(if_let_guard)]
 #![feature(min_specialization)]
 #![feature(never_type)]
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index f5a1edf6d81..e12c069dcc1 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -246,6 +246,13 @@ impl<'tcx> Elaborator<'tcx> {
 
                             Component::UnresolvedInferenceVariable(_) => None,
 
+                            Component::Opaque(def_id, substs) => {
+                                let ty = tcx.mk_opaque(def_id, substs);
+                                Some(ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(
+                                    ty, r_min,
+                                )))
+                            }
+
                             Component::Projection(projection) => {
                                 // We might end up here if we have `Foo<<Bar as Baz>::Assoc>: 'a`.
                                 // With this, we can deduce that `<Bar as Baz>::Assoc: 'a`.
@@ -262,8 +269,9 @@ impl<'tcx> Elaborator<'tcx> {
                                 None
                             }
                         })
-                        .map(ty::Binder::dummy)
-                        .map(|predicate_kind| predicate_kind.to_predicate(tcx))
+                        .map(|predicate_kind| {
+                            bound_predicate.rebind(predicate_kind).to_predicate(tcx)
+                        })
                         .filter(|&predicate| visited.insert(predicate))
                         .map(|predicate| {
                             predicate_obligation(
diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml
index da4002d09ad..f3c38875b37 100644
--- a/compiler/rustc_interface/Cargo.toml
+++ b/compiler/rustc_interface/Cargo.toml
@@ -38,7 +38,7 @@ rustc_mir_build = { path = "../rustc_mir_build" }
 rustc_mir_transform = { path = "../rustc_mir_transform" }
 rustc_monomorphize = { path = "../rustc_monomorphize" }
 rustc_passes = { path = "../rustc_passes" }
-rustc_typeck = { path = "../rustc_typeck" }
+rustc_hir_analysis = { path = "../rustc_hir_analysis" }
 rustc_lint = { path = "../rustc_lint" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_plugin_impl = { path = "../rustc_plugin_impl" }
diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs
index 41cd7b0e9b1..a41a749ee68 100644
--- a/compiler/rustc_interface/src/lib.rs
+++ b/compiler/rustc_interface/src/lib.rs
@@ -1,5 +1,4 @@
 #![feature(box_patterns)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(internal_output_capture)]
 #![feature(thread_spawn_unchecked)]
 #![feature(once_cell)]
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index c41b154c3e0..ad3e020b581 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -37,7 +37,6 @@ use rustc_session::{Limit, Session};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::FileName;
 use rustc_trait_selection::traits;
-use rustc_typeck as typeck;
 
 use std::any::Any;
 use std::cell::RefCell;
@@ -736,7 +735,7 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| {
     rustc_mir_transform::provide(providers);
     rustc_monomorphize::provide(providers);
     rustc_privacy::provide(providers);
-    typeck::provide(providers);
+    rustc_hir_analysis::provide(providers);
     ty::provide(providers);
     traits::provide(providers);
     rustc_passes::provide(providers);
@@ -880,7 +879,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
     });
 
     // passes are timed inside typeck
-    typeck::check_crate(tcx)?;
+    rustc_hir_analysis::check_crate(tcx)?;
 
     sess.time("misc_checking_2", || {
         parallel!(
diff --git a/compiler/rustc_interface/src/proc_macro_decls.rs b/compiler/rustc_interface/src/proc_macro_decls.rs
index 5371c513d29..2b1b931b732 100644
--- a/compiler/rustc_interface/src/proc_macro_decls.rs
+++ b/compiler/rustc_interface/src/proc_macro_decls.rs
@@ -1,4 +1,3 @@
-use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
@@ -10,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);
+            finder.decls = Some(id.def_id.def_id);
         }
     }
 
@@ -19,7 +18,7 @@ fn proc_macro_decls_static(tcx: TyCtxt<'_>, (): ()) -> Option<LocalDefId> {
 
 struct Finder<'tcx> {
     tcx: TyCtxt<'tcx>,
-    decls: Option<hir::def_id::LocalDefId>,
+    decls: Option<LocalDefId>,
 }
 
 pub(crate) fn provide(providers: &mut Providers) {
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index c7615a5775e..2cd959689e6 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -758,7 +758,6 @@ fn test_unstable_options_tracking_hash() {
     tracked!(mir_opt_level, Some(4));
     tracked!(move_size_limit, Some(4096));
     tracked!(mutable_noalias, Some(true));
-    tracked!(new_llvm_pass_manager, Some(true));
     tracked!(no_generate_arange_section, true);
     tracked!(no_link, true);
     tracked!(no_unique_section_names, true);
diff --git a/compiler/rustc_lexer/src/cursor.rs b/compiler/rustc_lexer/src/cursor.rs
index 21557a9c854..eceef59802e 100644
--- a/compiler/rustc_lexer/src/cursor.rs
+++ b/compiler/rustc_lexer/src/cursor.rs
@@ -4,8 +4,8 @@ use std::str::Chars;
 ///
 /// Next characters can be peeked via `first` method,
 /// and position can be shifted forward via `bump` method.
-pub(crate) struct Cursor<'a> {
-    initial_len: usize,
+pub struct Cursor<'a> {
+    len_remaining: usize,
     /// Iterator over chars. Slightly faster than a &str.
     chars: Chars<'a>,
     #[cfg(debug_assertions)]
@@ -15,9 +15,9 @@ pub(crate) struct Cursor<'a> {
 pub(crate) const EOF_CHAR: char = '\0';
 
 impl<'a> Cursor<'a> {
-    pub(crate) fn new(input: &'a str) -> Cursor<'a> {
+    pub fn new(input: &'a str) -> Cursor<'a> {
         Cursor {
-            initial_len: input.len(),
+            len_remaining: input.len(),
             chars: input.chars(),
             #[cfg(debug_assertions)]
             prev: EOF_CHAR,
@@ -61,13 +61,13 @@ impl<'a> Cursor<'a> {
     }
 
     /// Returns amount of already consumed symbols.
-    pub(crate) fn len_consumed(&self) -> u32 {
-        (self.initial_len - self.chars.as_str().len()) as u32
+    pub(crate) fn pos_within_token(&self) -> u32 {
+        (self.len_remaining - self.chars.as_str().len()) as u32
     }
 
     /// Resets the number of bytes consumed to 0.
-    pub(crate) fn reset_len_consumed(&mut self) {
-        self.initial_len = self.chars.as_str().len();
+    pub(crate) fn reset_pos_within_token(&mut self) {
+        self.len_remaining = self.chars.as_str().len();
     }
 
     /// Moves to the next character.
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index a79c982649a..c71e6ffe34d 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -29,9 +29,11 @@ pub mod unescape;
 #[cfg(test)]
 mod tests;
 
+pub use crate::cursor::Cursor;
+
 use self::LiteralKind::*;
 use self::TokenKind::*;
-use crate::cursor::{Cursor, EOF_CHAR};
+use crate::cursor::EOF_CHAR;
 use std::convert::TryFrom;
 
 /// Parsed token.
@@ -139,6 +141,9 @@ pub enum TokenKind {
 
     /// Unknown token, not expected by the lexer, e.g. "â„–"
     Unknown,
+
+    /// End of input.
+    Eof,
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -219,13 +224,6 @@ pub fn strip_shebang(input: &str) -> Option<usize> {
     None
 }
 
-/// Parses the first token from the provided input string.
-#[inline]
-pub fn first_token(input: &str) -> Token {
-    debug_assert!(!input.is_empty());
-    Cursor::new(input).advance_token()
-}
-
 /// Validates a raw string literal. Used for getting more information about a
 /// problem with a `RawStr`/`RawByteStr` with a `None` field.
 #[inline]
@@ -243,12 +241,8 @@ pub fn validate_raw_str(input: &str, prefix_len: u32) -> Result<(), RawStrError>
 pub fn tokenize(input: &str) -> impl Iterator<Item = Token> + '_ {
     let mut cursor = Cursor::new(input);
     std::iter::from_fn(move || {
-        if cursor.is_eof() {
-            None
-        } else {
-            cursor.reset_len_consumed();
-            Some(cursor.advance_token())
-        }
+        let token = cursor.advance_token();
+        if token.kind != TokenKind::Eof { Some(token) } else { None }
     })
 }
 
@@ -311,8 +305,11 @@ pub fn is_ident(string: &str) -> bool {
 
 impl Cursor<'_> {
     /// Parses a token from the input string.
-    fn advance_token(&mut self) -> Token {
-        let first_char = self.bump().unwrap();
+    pub fn advance_token(&mut self) -> Token {
+        let first_char = match self.bump() {
+            Some(c) => c,
+            None => return Token::new(TokenKind::Eof, 0),
+        };
         let token_kind = match first_char {
             // Slash, comment or block comment.
             '/' => match self.first() {
@@ -329,7 +326,7 @@ impl Cursor<'_> {
                 ('#', c1) if is_id_start(c1) => self.raw_ident(),
                 ('#', _) | ('"', _) => {
                     let res = self.raw_double_quoted_string(1);
-                    let suffix_start = self.len_consumed();
+                    let suffix_start = self.pos_within_token();
                     if res.is_ok() {
                         self.eat_literal_suffix();
                     }
@@ -344,7 +341,7 @@ impl Cursor<'_> {
                 ('\'', _) => {
                     self.bump();
                     let terminated = self.single_quoted_string();
-                    let suffix_start = self.len_consumed();
+                    let suffix_start = self.pos_within_token();
                     if terminated {
                         self.eat_literal_suffix();
                     }
@@ -354,7 +351,7 @@ impl Cursor<'_> {
                 ('"', _) => {
                     self.bump();
                     let terminated = self.double_quoted_string();
-                    let suffix_start = self.len_consumed();
+                    let suffix_start = self.pos_within_token();
                     if terminated {
                         self.eat_literal_suffix();
                     }
@@ -364,7 +361,7 @@ impl Cursor<'_> {
                 ('r', '"') | ('r', '#') => {
                     self.bump();
                     let res = self.raw_double_quoted_string(2);
-                    let suffix_start = self.len_consumed();
+                    let suffix_start = self.pos_within_token();
                     if res.is_ok() {
                         self.eat_literal_suffix();
                     }
@@ -381,7 +378,7 @@ impl Cursor<'_> {
             // Numeric literal.
             c @ '0'..='9' => {
                 let literal_kind = self.number(c);
-                let suffix_start = self.len_consumed();
+                let suffix_start = self.pos_within_token();
                 self.eat_literal_suffix();
                 TokenKind::Literal { kind: literal_kind, suffix_start }
             }
@@ -420,7 +417,7 @@ impl Cursor<'_> {
             // String literal.
             '"' => {
                 let terminated = self.double_quoted_string();
-                let suffix_start = self.len_consumed();
+                let suffix_start = self.pos_within_token();
                 if terminated {
                     self.eat_literal_suffix();
                 }
@@ -433,7 +430,9 @@ impl Cursor<'_> {
             }
             _ => Unknown,
         };
-        Token::new(token_kind, self.len_consumed())
+        let res = Token::new(token_kind, self.pos_within_token());
+        self.reset_pos_within_token();
+        res
     }
 
     fn line_comment(&mut self) -> TokenKind {
@@ -618,7 +617,7 @@ impl Cursor<'_> {
 
         if !can_be_a_lifetime {
             let terminated = self.single_quoted_string();
-            let suffix_start = self.len_consumed();
+            let suffix_start = self.pos_within_token();
             if terminated {
                 self.eat_literal_suffix();
             }
@@ -643,7 +642,7 @@ impl Cursor<'_> {
         if self.first() == '\'' {
             self.bump();
             let kind = Char { terminated: true };
-            Literal { kind, suffix_start: self.len_consumed() }
+            Literal { kind, suffix_start: self.pos_within_token() }
         } else {
             Lifetime { starts_with_number }
         }
@@ -724,7 +723,7 @@ impl Cursor<'_> {
 
     fn raw_string_unvalidated(&mut self, prefix_len: u32) -> Result<u32, RawStrError> {
         debug_assert!(self.prev() == 'r');
-        let start_pos = self.len_consumed();
+        let start_pos = self.pos_within_token();
         let mut possible_terminator_offset = None;
         let mut max_hashes = 0;
 
@@ -778,7 +777,7 @@ impl Cursor<'_> {
                 // Keep track of possible terminators to give a hint about
                 // where there might be a missing terminator
                 possible_terminator_offset =
-                    Some(self.len_consumed() - start_pos - n_end_hashes + prefix_len);
+                    Some(self.pos_within_token() - start_pos - n_end_hashes + prefix_len);
                 max_hashes = n_end_hashes;
             }
         }
diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs
index 3da6bc14622..8f64b5f5158 100644
--- a/compiler/rustc_lexer/src/unescape.rs
+++ b/compiler/rustc_lexer/src/unescape.rs
@@ -93,7 +93,7 @@ where
         // NOTE: Raw strings do not perform any explicit character escaping, here we
         // only translate CRLF to LF and produce errors on bare CR.
         Mode::RawStr | Mode::RawByteStr => {
-            unescape_raw_str_or_byte_str(literal_text, mode, callback)
+            unescape_raw_str_or_raw_byte_str(literal_text, mode, callback)
         }
     }
 }
@@ -105,7 +105,7 @@ pub fn unescape_byte_literal<F>(literal_text: &str, mode: Mode, callback: &mut F
 where
     F: FnMut(Range<usize>, Result<u8, EscapeError>),
 {
-    assert!(mode.is_bytes());
+    debug_assert!(mode.is_bytes());
     unescape_literal(literal_text, mode, &mut |range, result| {
         callback(range, result.map(byte_from_char));
     })
@@ -129,7 +129,7 @@ pub fn unescape_byte(literal_text: &str) -> Result<u8, (usize, EscapeError)> {
 }
 
 /// What kind of literal do we parse.
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone, Copy, PartialEq)]
 pub enum Mode {
     Char,
     Str,
@@ -140,17 +140,13 @@ pub enum Mode {
 }
 
 impl Mode {
-    pub fn in_single_quotes(self) -> bool {
+    pub fn in_double_quotes(self) -> bool {
         match self {
-            Mode::Char | Mode::Byte => true,
-            Mode::Str | Mode::ByteStr | Mode::RawStr | Mode::RawByteStr => false,
+            Mode::Str | Mode::ByteStr | Mode::RawStr | Mode::RawByteStr => true,
+            Mode::Char | Mode::Byte => false,
         }
     }
 
-    pub fn in_double_quotes(self) -> bool {
-        !self.in_single_quotes()
-    }
-
     pub fn is_bytes(self) -> bool {
         match self {
             Mode::Byte | Mode::ByteStr | Mode::RawByteStr => true,
@@ -184,7 +180,7 @@ fn scan_escape(chars: &mut Chars<'_>, mode: Mode) -> Result<char, EscapeError> {
 
             let value = hi * 16 + lo;
 
-            // For a byte literal verify that it is within ASCII range.
+            // For a non-byte literal verify that it is within ASCII range.
             if !mode.is_bytes() && !is_ascii(value) {
                 return Err(EscapeError::OutOfRangeHexEscape);
             }
@@ -263,6 +259,7 @@ fn ascii_check(first_char: char, mode: Mode) -> Result<char, EscapeError> {
 }
 
 fn unescape_char_or_byte(chars: &mut Chars<'_>, mode: Mode) -> Result<char, EscapeError> {
+    debug_assert!(mode == Mode::Char || mode == Mode::Byte);
     let first_char = chars.next().ok_or(EscapeError::ZeroChars)?;
     let res = match first_char {
         '\\' => scan_escape(chars, mode),
@@ -282,7 +279,7 @@ fn unescape_str_or_byte_str<F>(src: &str, mode: Mode, callback: &mut F)
 where
     F: FnMut(Range<usize>, Result<char, EscapeError>),
 {
-    assert!(mode.in_double_quotes());
+    debug_assert!(mode == Mode::Str || mode == Mode::ByteStr);
     let initial_len = src.len();
     let mut chars = src.chars();
     while let Some(first_char) = chars.next() {
@@ -344,11 +341,11 @@ where
 /// sequence of characters or errors.
 /// NOTE: Raw strings do not perform any explicit character escaping, here we
 /// only translate CRLF to LF and produce errors on bare CR.
-fn unescape_raw_str_or_byte_str<F>(literal_text: &str, mode: Mode, callback: &mut F)
+fn unescape_raw_str_or_raw_byte_str<F>(literal_text: &str, mode: Mode, callback: &mut F)
 where
     F: FnMut(Range<usize>, Result<char, EscapeError>),
 {
-    assert!(mode.in_double_quotes());
+    debug_assert!(mode == Mode::RawStr || mode == Mode::RawByteStr);
     let initial_len = literal_text.len();
 
     let mut chars = literal_text.chars();
@@ -368,7 +365,7 @@ where
 
 fn byte_from_char(c: char) -> u8 {
     let res = c as u32;
-    assert!(res <= u8::MAX as u32, "guaranteed because of Mode::ByteStr");
+    debug_assert!(res <= u8::MAX as u32, "guaranteed because of Mode::ByteStr");
     res as u8
 }
 
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 0ff2ef5cda3..5d69c35ebfc 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -46,8 +46,7 @@ use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::layout::{LayoutError, LayoutOf};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::Instance;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Instance, Ty, TyCtxt, VariantDef};
 use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason};
 use rustc_span::edition::Edition;
 use rustc_span::source_map::Spanned;
@@ -98,30 +97,28 @@ fn pierce_parens(mut expr: &ast::Expr) -> &ast::Expr {
 
 impl EarlyLintPass for WhileTrue {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
-        if let ast::ExprKind::While(cond, _, label) = &e.kind {
-            if let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).kind {
-                if let ast::LitKind::Bool(true) = lit.kind {
-                    if !lit.span.from_expansion() {
-                        let condition_span = e.span.with_hi(cond.span.hi());
-                        cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| {
-                            lint.build(fluent::lint::builtin_while_true)
-                                .span_suggestion_short(
-                                    condition_span,
-                                    fluent::lint::suggestion,
-                                    format!(
-                                        "{}loop",
-                                        label.map_or_else(String::new, |label| format!(
-                                            "{}: ",
-                                            label.ident,
-                                        ))
-                                    ),
-                                    Applicability::MachineApplicable,
-                                )
-                                .emit();
-                        })
-                    }
-                }
-            }
+        if let ast::ExprKind::While(cond, _, label) = &e.kind
+            && let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).kind
+            && let ast::LitKind::Bool(true) = lit.kind
+            && !lit.span.from_expansion()
+        {
+            let condition_span = e.span.with_hi(cond.span.hi());
+            cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| {
+                lint.build(fluent::lint::builtin_while_true)
+                    .span_suggestion_short(
+                        condition_span,
+                        fluent::lint::suggestion,
+                        format!(
+                            "{}loop",
+                            label.map_or_else(String::new, |label| format!(
+                                "{}: ",
+                                label.ident,
+                            ))
+                        ),
+                        Applicability::MachineApplicable,
+                    )
+                    .emit();
+            })
         }
     }
 }
@@ -606,7 +603,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
                 // Issue #11592: traits are always considered exported, even when private.
                 if cx.tcx.visibility(it.def_id)
                     == ty::Visibility::Restricted(
-                        cx.tcx.parent_module_from_def_id(it.def_id).to_def_id(),
+                        cx.tcx.parent_module_from_def_id(it.def_id.def_id).to_def_id(),
                     )
                 {
                     return;
@@ -627,13 +624,13 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
 
         let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id());
 
-        self.check_missing_docs_attrs(cx, it.def_id, article, desc);
+        self.check_missing_docs_attrs(cx, it.def_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());
 
-        self.check_missing_docs_attrs(cx, trait_item.def_id, article, desc);
+        self.check_missing_docs_attrs(cx, trait_item.def_id.def_id, article, desc);
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
@@ -661,12 +658,12 @@ 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, article, desc);
+        self.check_missing_docs_attrs(cx, impl_item.def_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, article, desc);
+        self.check_missing_docs_attrs(cx, foreign_item.def_id.def_id, article, desc);
     }
 
     fn check_field_def(&mut self, cx: &LateContext<'_>, sf: &hir::FieldDef<'_>) {
@@ -719,7 +716,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) {
+        if !cx.access_levels.is_reachable(item.def_id.def_id) {
             return;
         }
         let (def, ty) = match item.kind {
@@ -809,7 +806,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) {
+        if !cx.access_levels.is_reachable(item.def_id.def_id) {
             return;
         }
 
@@ -836,7 +833,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
             debug!("{:?}", self.impling_types);
         }
 
-        if !self.impling_types.as_ref().unwrap().contains(&item.def_id) {
+        if !self.impling_types.as_ref().unwrap().contains(&item.def_id.def_id) {
             cx.struct_span_lint(MISSING_DEBUG_IMPLEMENTATIONS, item.span, |lint| {
                 lint.build(fluent::lint::builtin_missing_debug_impl)
                     .set_arg("debug", cx.tcx.def_path_str(debug))
@@ -1206,7 +1203,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).unwrap(),
+                                cx.tcx.hir().get_generics(it.id.def_id.def_id).unwrap(),
                                 it.span,
                             );
                         }
@@ -1389,11 +1386,11 @@ 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, item.vis_span, true);
+        self.perform_lint(cx, "item", item.def_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, foreign_item.vis_span, true);
+        self.perform_lint(cx, "item", foreign_item.def_id.def_id, foreign_item.vis_span, true);
     }
 
     fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
@@ -1404,7 +1401,7 @@ impl<'tcx> LateLintPass<'tcx> for UnreachablePub {
     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, impl_item.vis_span, false);
+            self.perform_lint(cx, "item", impl_item.def_id.def_id, impl_item.vis_span, false);
         }
     }
 }
@@ -1841,7 +1838,7 @@ declare_lint! {
 }
 
 pub struct UnnameableTestItems {
-    boundary: Option<LocalDefId>, // Id of the item under which things are not nameable
+    boundary: Option<hir::OwnerId>, // Id of the item under which things are not nameable
     items_nameable: bool,
 }
 
@@ -2138,7 +2135,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;
+        let def_id = item.def_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
@@ -2425,12 +2422,63 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
             None
         }
 
-        /// Test if this enum has several actually "existing" variants.
-        /// Zero-sized uninhabited variants do not always have a tag assigned and thus do not "exist".
-        fn is_multi_variant<'tcx>(adt: ty::AdtDef<'tcx>) -> bool {
-            // As an approximation, we only count dataless variants. Those are definitely inhabited.
-            let existing_variants = adt.variants().iter().filter(|v| v.fields.is_empty()).count();
-            existing_variants > 1
+        /// 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,
+            substs: ty::SubstsRef<'tcx>,
+            descr: &str,
+            init: InitKind,
+        ) -> Option<InitError> {
+            variant.fields.iter().find_map(|field| {
+                ty_find_init_error(cx, field.ty(cx.tcx, substs), init).map(|(mut msg, span)| {
+                    if span.is_none() {
+                        // Point to this field, should be helpful for figuring
+                        // out where the source of the error is.
+                        let span = cx.tcx.def_span(field.did);
+                        write!(&mut msg, " (in this {descr})").unwrap();
+                        (msg, Some(span))
+                    } else {
+                        // Just forward.
+                        (msg, span)
+                    }
+                })
+            })
         }
 
         /// Return `Some` only if we are sure this type does *not*
@@ -2468,7 +2516,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
                 RawPtr(_) if init == InitKind::Uninit => {
                     Some(("raw pointers must not be uninitialized".to_string(), None))
                 }
-                // Recurse and checks for some compound types.
+                // Recurse and checks for some compound types. (but not unions)
                 Adt(adt_def, substs) if !adt_def.is_union() => {
                     // First check if this ADT has a layout attribute (like `NonNull` and friends).
                     use std::ops::Bound;
@@ -2476,6 +2524,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
                         // We exploit here that `layout_scalar_valid_range` will never
                         // 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 => {
                             return Some((format!("`{}` must be non-null", ty), None));
                         }
@@ -2492,50 +2541,65 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
                         }
                         _ => {}
                     }
-                    // Now, recurse.
-                    match adt_def.variants().len() {
-                        0 => Some(("enums with no variants have no valid value".to_string(), None)),
-                        1 => {
-                            // Struct, or enum with exactly one variant.
-                            // Proceed recursively, check all fields.
-                            let variant = &adt_def.variant(VariantIdx::from_u32(0));
-                            variant.fields.iter().find_map(|field| {
-                                ty_find_init_error(cx, field.ty(cx.tcx, substs), init).map(
-                                    |(mut msg, span)| {
-                                        if span.is_none() {
-                                            // Point to this field, should be helpful for figuring
-                                            // out where the source of the error is.
-                                            let span = cx.tcx.def_span(field.did);
-                                            write!(
-                                                &mut msg,
-                                                " (in this {} field)",
-                                                adt_def.descr()
-                                            )
-                                            .unwrap();
-                                            (msg, Some(span))
-                                        } else {
-                                            // Just forward.
-                                            (msg, span)
-                                        }
-                                    },
-                                )
-                            })
-                        }
-                        // Multi-variant enum.
-                        _ => {
-                            if init == InitKind::Uninit && is_multi_variant(*adt_def) {
-                                let span = cx.tcx.def_span(adt_def.did());
-                                Some((
-                                    "enums have to be initialized to a variant".to_string(),
-                                    Some(span),
-                                ))
-                            } else {
-                                // In principle, for zero-initialization we could figure out which variant corresponds
-                                // to tag 0, and check that... but for now we just accept all zero-initializations.
-                                None
-                            }
+                    // Handle structs.
+                    if adt_def.is_struct() {
+                        return variant_find_init_error(
+                            cx,
+                            adt_def.non_enum_variant(),
+                            substs,
+                            "struct field",
+                            init,
+                        );
+                    }
+                    // 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 {
+                            // Entirely skip uninhbaited variants.
+                            Some(false) => return None,
+                            // Forward the others, but remember which ones are definitely inhabited.
+                            Some(true) => true,
+                            None => false,
+                        };
+                        Some((variant, definitely_inhabited))
+                    });
+                    let Some(first_variant) = potential_variants.next() else {
+                        return Some(("enums with no inhabited variants have no valid value".to_string(), Some(span)));
+                    };
+                    // So we have at least one potentially inhabited variant. Might we have two?
+                    let Some(second_variant) = potential_variants.next() else {
+                        // There is only one potentially inhabited variant. So we can recursively check that variant!
+                        return variant_find_init_error(
+                            cx,
+                            &first_variant.0,
+                            substs,
+                            "field of the only potentially inhabited enum variant",
+                            init,
+                        );
+                    };
+                    // So we have at least two potentially inhabited variants.
+                    // If we can prove that we have at least two *definitely* inhabited variants,
+                    // then we have a tag and hence leaving this uninit is definitely disallowed.
+                    // (Leaving it zeroed could be okay, depending on which variant is encoded as zero tag.)
+                    if init == InitKind::Uninit {
+                        let definitely_inhabited = (first_variant.1 as usize)
+                            + (second_variant.1 as usize)
+                            + potential_variants
+                                .filter(|(_variant, definitely_inhabited)| *definitely_inhabited)
+                                .count();
+                        if definitely_inhabited > 1 {
+                            return Some((
+                                "enums with multiple inhabited variants have to be initialized to a variant".to_string(),
+                                Some(span),
+                            ));
                         }
                     }
+                    // We couldn't find anything wrong here.
+                    None
                 }
                 Tuple(..) => {
                     // Proceed recursively, check all fields.
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 7ca6ec5d962..cbab56f2066 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -1048,7 +1048,7 @@ impl<'tcx> LateContext<'tcx> {
                 .filter(|typeck_results| typeck_results.hir_owner == id.owner)
                 .or_else(|| {
                     if self.tcx.has_typeck_results(id.owner.to_def_id()) {
-                        Some(self.tcx.typeck(id.owner))
+                        Some(self.tcx.typeck(id.owner.def_id))
                     } else {
                         None
                     }
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index d8a03024d13..9c4f9efde5a 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -244,7 +244,7 @@ fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, path: &Path<'_>) -> Option<String> {
             }
         }
         // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait.
-        Res::SelfTy { trait_: None, alias_to: Some((did, _)) } => {
+        Res::SelfTyAlias { alias_to: did, is_trait_impl: false, .. } => {
             if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() {
                 if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(adt.did())
                 {
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 752a751f6bc..4408f68dd63 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -34,7 +34,7 @@
 #![feature(iter_intersperse)]
 #![feature(iter_order_by)]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
+#![feature(min_specialization)]
 #![feature(never_type)]
 #![recursion_limit = "256"]
 
diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs
index af5e5faf1f5..efaa268647d 100644
--- a/compiler/rustc_lint/src/pass_by_value.rs
+++ b/compiler/rustc_lint/src/pass_by_value.rs
@@ -56,7 +56,7 @@ fn path_for_pass_by_value(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Option<Stri
                 let path_segment = path.segments.last().unwrap();
                 return Some(format!("{}{}", name, gen_args(cx, path_segment)));
             }
-            Res::SelfTy { trait_: None, alias_to: Some((did, _)) } => {
+            Res::SelfTyAlias { alias_to: did, is_trait_impl: false, .. } => {
                 if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() {
                     if cx.tcx.has_attr(adt.did(), sym::rustc_pass_by_value) {
                         return Some(cx.tcx.def_path_str_with_substs(adt.did(), substs));
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 24e18826048..879a3b660b4 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -31,13 +31,12 @@
 #include "llvm/Transforms/IPO/PassManagerBuilder.h"
 #include "llvm/Transforms/IPO/AlwaysInliner.h"
 #include "llvm/Transforms/IPO/FunctionImport.h"
-#if LLVM_VERSION_GE(15, 0)
+#include "llvm/Transforms/IPO/Internalize.h"
 #include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h"
-#endif
 #include "llvm/Transforms/Utils/AddDiscriminators.h"
 #include "llvm/Transforms/Utils/FunctionImportUtils.h"
 #include "llvm/LTO/LTO.h"
-#include "llvm/Bitcode/BitcodeWriterPass.h"
+#include "llvm/Bitcode/BitcodeWriter.h"
 #include "llvm-c/Transforms/PassManagerBuilder.h"
 
 #include "llvm/Transforms/Instrumentation.h"
@@ -93,172 +92,6 @@ extern "C" void LLVMTimeTraceProfilerFinish(const char* FileName) {
   timeTraceProfilerCleanup();
 }
 
-extern "C" LLVMPassRef LLVMRustFindAndCreatePass(const char *PassName) {
-#if LLVM_VERSION_LT(15, 0)
-  StringRef SR(PassName);
-  PassRegistry *PR = PassRegistry::getPassRegistry();
-
-  const PassInfo *PI = PR->getPassInfo(SR);
-  if (PI) {
-    return wrap(PI->createPass());
-  }
-  return nullptr;
-#else
-  report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-extern "C" LLVMPassRef LLVMRustCreateAddressSanitizerFunctionPass(bool Recover) {
-#if LLVM_VERSION_LT(15, 0)
-  const bool CompileKernel = false;
-  const bool UseAfterScope = true;
-
-  return wrap(createAddressSanitizerFunctionPass(CompileKernel, Recover, UseAfterScope));
-#else
-  report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-extern "C" LLVMPassRef LLVMRustCreateModuleAddressSanitizerPass(bool Recover) {
-#if LLVM_VERSION_LT(15, 0)
-  const bool CompileKernel = false;
-
-  return wrap(createModuleAddressSanitizerLegacyPassPass(CompileKernel, Recover));
-#else
-  report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-extern "C" LLVMPassRef LLVMRustCreateMemorySanitizerPass(int TrackOrigins, bool Recover) {
-#if LLVM_VERSION_LT(15, 0)
-  const bool CompileKernel = false;
-
-  return wrap(createMemorySanitizerLegacyPassPass(
-#if LLVM_VERSION_GE(14, 0)
-      MemorySanitizerOptions{TrackOrigins, Recover, CompileKernel, /*EagerChecks=*/true}
-#else
-      MemorySanitizerOptions{TrackOrigins, Recover, CompileKernel}
-#endif
-  ));
-#else
-  report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-extern "C" LLVMPassRef LLVMRustCreateThreadSanitizerPass() {
-#if LLVM_VERSION_LT(15, 0)
-  return wrap(createThreadSanitizerLegacyPassPass());
-#else
-  report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-extern "C" LLVMPassRef LLVMRustCreateHWAddressSanitizerPass(bool Recover) {
-#if LLVM_VERSION_LT(15, 0)
-  const bool CompileKernel = false;
-
-  return wrap(createHWAddressSanitizerLegacyPassPass(CompileKernel, Recover));
-#else
-  report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-extern "C" void LLVMRustAddPass(LLVMPassManagerRef PMR, LLVMPassRef RustPass) {
-#if LLVM_VERSION_LT(15, 0)
-  assert(RustPass);
-  Pass *Pass = unwrap(RustPass);
-  PassManagerBase *PMB = unwrap(PMR);
-  PMB->add(Pass);
-#else
-  report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-extern "C" LLVMPassManagerBuilderRef LLVMRustPassManagerBuilderCreate() {
-#if LLVM_VERSION_LT(15, 0)
-  return LLVMPassManagerBuilderCreate();
-#else
-  report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-extern "C" void LLVMRustPassManagerBuilderDispose(LLVMPassManagerBuilderRef PMB) {
-#if LLVM_VERSION_LT(15, 0)
-  LLVMPassManagerBuilderDispose(PMB);
-#else
-  report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-extern "C" void LLVMRustPassManagerBuilderPopulateFunctionPassManager(
-  LLVMPassManagerBuilderRef PMB, LLVMPassManagerRef PM) {
-#if LLVM_VERSION_LT(15, 0)
-  LLVMPassManagerBuilderPopulateFunctionPassManager(PMB, PM);
-#else
-  report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-extern "C" void LLVMRustPassManagerBuilderPopulateModulePassManager(
-  LLVMPassManagerBuilderRef PMB, LLVMPassManagerRef PM) {
-#if LLVM_VERSION_LT(15, 0)
-  LLVMPassManagerBuilderPopulateModulePassManager(PMB, PM);
-#else
-  report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-extern "C" void LLVMRustPassManagerBuilderPopulateLTOPassManager(
-  LLVMPassManagerBuilderRef PMB, LLVMPassManagerRef PM, bool Internalize, bool RunInliner) {
-#if LLVM_VERSION_LT(15, 0)
-  LLVMPassManagerBuilderPopulateLTOPassManager(PMB, PM, Internalize, RunInliner);
-#else
-  report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-extern "C"
-void LLVMRustPassManagerBuilderPopulateThinLTOPassManager(
-  LLVMPassManagerBuilderRef PMBR,
-  LLVMPassManagerRef PMR
-) {
-#if LLVM_VERSION_LT(15, 0)
-  unwrap(PMBR)->populateThinLTOPassManager(*unwrap(PMR));
-#else
-  report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-extern "C" void LLVMRustPassManagerBuilderUseInlinerWithThreshold(
-  LLVMPassManagerBuilderRef PMB, unsigned Threshold) {
-#if LLVM_VERSION_LT(15, 0)
-  LLVMPassManagerBuilderUseInlinerWithThreshold(PMB, Threshold);
-#else
-  report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-extern "C"
-void LLVMRustAddLastExtensionPasses(
-    LLVMPassManagerBuilderRef PMBR, LLVMPassRef *Passes, size_t NumPasses) {
-#if LLVM_VERSION_LT(15, 0)
-  auto AddExtensionPasses = [Passes, NumPasses](
-      const PassManagerBuilder &Builder, PassManagerBase &PM) {
-    for (size_t I = 0; I < NumPasses; I++) {
-      PM.add(unwrap(Passes[I]));
-    }
-  };
-  // Add the passes to both of the pre-finalization extension points,
-  // so they are run for optimized and non-optimized builds.
-  unwrap(PMBR)->addExtension(PassManagerBuilder::EP_OptimizerLast,
-                             AddExtensionPasses);
-  unwrap(PMBR)->addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
-                             AddExtensionPasses);
-#else
-  report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
 #ifdef LLVM_COMPONENT_X86
 #define SUBTARGET_X86 SUBTARGET(X86)
 #else
@@ -604,47 +437,6 @@ extern "C" void LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) {
   delete unwrap(TM);
 }
 
-extern "C" void LLVMRustConfigurePassManagerBuilder(
-    LLVMPassManagerBuilderRef PMBR, LLVMRustCodeGenOptLevel OptLevel,
-    bool MergeFunctions, bool SLPVectorize, bool LoopVectorize, bool PrepareForThinLTO,
-    const char* PGOGenPath, const char* PGOUsePath, const char* PGOSampleUsePath,
-    int SizeLevel) {
-#if LLVM_VERSION_LT(15, 0)
-  unwrap(PMBR)->MergeFunctions = MergeFunctions;
-  unwrap(PMBR)->SLPVectorize = SLPVectorize;
-  unwrap(PMBR)->OptLevel = fromRust(OptLevel);
-  unwrap(PMBR)->LoopVectorize = LoopVectorize;
-  unwrap(PMBR)->PrepareForThinLTO = PrepareForThinLTO;
-  unwrap(PMBR)->SizeLevel = SizeLevel;
-  unwrap(PMBR)->DisableUnrollLoops = SizeLevel != 0;
-
-  if (PGOGenPath) {
-    assert(!PGOUsePath && !PGOSampleUsePath);
-    unwrap(PMBR)->EnablePGOInstrGen = true;
-    unwrap(PMBR)->PGOInstrGen = PGOGenPath;
-  } else if (PGOUsePath) {
-    assert(!PGOSampleUsePath);
-    unwrap(PMBR)->PGOInstrUse = PGOUsePath;
-  } else if (PGOSampleUsePath) {
-    unwrap(PMBR)->PGOSampleUse = PGOSampleUsePath;
-  }
-#else
-  report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-// Unfortunately, the LLVM C API doesn't provide a way to set the `LibraryInfo`
-// field of a PassManagerBuilder, we expose our own method of doing so.
-extern "C" void LLVMRustAddBuilderLibraryInfo(LLVMPassManagerBuilderRef PMBR,
-                                              LLVMModuleRef M,
-                                              bool DisableSimplifyLibCalls) {
-  Triple TargetTriple(unwrap(M)->getTargetTriple());
-  TargetLibraryInfoImpl *TLI = new TargetLibraryInfoImpl(TargetTriple);
-  if (DisableSimplifyLibCalls)
-    TLI->disableAllFunctions();
-  unwrap(PMBR)->LibraryInfo = TLI;
-}
-
 // Unfortunately, the LLVM C API doesn't provide a way to create the
 // TargetLibraryInfo pass, so we use this method to do so.
 extern "C" void LLVMRustAddLibraryInfo(LLVMPassManagerRef PMR, LLVMModuleRef M,
@@ -656,27 +448,6 @@ extern "C" void LLVMRustAddLibraryInfo(LLVMPassManagerRef PMR, LLVMModuleRef M,
   unwrap(PMR)->add(new TargetLibraryInfoWrapperPass(TLII));
 }
 
-// Unfortunately, the LLVM C API doesn't provide an easy way of iterating over
-// all the functions in a module, so we do that manually here. You'll find
-// similar code in clang's BackendUtil.cpp file.
-extern "C" void LLVMRustRunFunctionPassManager(LLVMPassManagerRef PMR,
-                                               LLVMModuleRef M) {
-  llvm::legacy::FunctionPassManager *P =
-      unwrap<llvm::legacy::FunctionPassManager>(PMR);
-  P->doInitialization();
-
-  // Upgrade all calls to old intrinsics first.
-  for (Module::iterator I = unwrap(M)->begin(), E = unwrap(M)->end(); I != E;)
-    UpgradeCallsToIntrinsic(&*I++); // must be post-increment, as we remove
-
-  for (Module::iterator I = unwrap(M)->begin(), E = unwrap(M)->end(); I != E;
-       ++I)
-    if (!I->isDeclaration())
-      P->run(*I);
-
-  P->doFinalization();
-}
-
 extern "C" void LLVMRustSetLLVMOptions(int Argc, char **Argv) {
   // Initializing the command-line options more than once is not allowed. So,
   // check if they've already been initialized.  (This could happen if we're
@@ -820,7 +591,7 @@ struct LLVMRustSanitizerOptions {
 };
 
 extern "C" LLVMRustResult
-LLVMRustOptimizeWithNewPassManager(
+LLVMRustOptimize(
     LLVMModuleRef ModuleRef,
     LLVMTargetMachineRef TMRef,
     LLVMRustPassBuilderOptLevel OptLevelRust,
@@ -1241,15 +1012,8 @@ extern "C" void LLVMRustPrintPasses() {
   PR->enumerateWith(&Listener);
 }
 
-extern "C" void LLVMRustAddAlwaysInlinePass(LLVMPassManagerBuilderRef PMBR,
-                                            bool AddLifetimes) {
-  unwrap(PMBR)->Inliner = llvm::createAlwaysInlinerLegacyPass(AddLifetimes);
-}
-
 extern "C" void LLVMRustRunRestrictionPass(LLVMModuleRef M, char **Symbols,
                                            size_t Len) {
-  llvm::legacy::PassManager passes;
-
   auto PreserveFunctions = [=](const GlobalValue &GV) {
     for (size_t I = 0; I < Len; I++) {
       if (GV.getName() == Symbols[I]) {
@@ -1259,9 +1023,7 @@ extern "C" void LLVMRustRunRestrictionPass(LLVMModuleRef M, char **Symbols,
     return false;
   };
 
-  passes.add(llvm::createInternalizePass(PreserveFunctions));
-
-  passes.run(*unwrap(M));
+  internalizeModule(*unwrap(M), PreserveFunctions);
 }
 
 extern "C" void
@@ -1282,7 +1044,7 @@ extern "C" void LLVMRustSetModulePIELevel(LLVMModuleRef M) {
 extern "C" void LLVMRustSetModuleCodeModel(LLVMModuleRef M,
                                            LLVMRustCodeModel Model) {
   auto CM = fromRust(Model);
-  if (!CM.hasValue())
+  if (!CM)
     return;
   unwrap(M)->setCodeModel(*CM);
 }
@@ -1610,11 +1372,6 @@ LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin) {
     raw_string_ostream OS(Ret->data);
     {
       if (is_thin) {
-#if LLVM_VERSION_LT(15, 0)
-        legacy::PassManager PM;
-        PM.add(createWriteThinLTOBitcodePass(OS));
-        PM.run(*unwrap(M));
-#else
         PassBuilder PB;
         LoopAnalysisManager LAM;
         FunctionAnalysisManager FAM;
@@ -1628,11 +1385,8 @@ LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin) {
         ModulePassManager MPM;
         MPM.addPass(ThinLTOBitcodeWriterPass(OS, nullptr));
         MPM.run(*unwrap(M), MAM);
-#endif
       } else {
-        legacy::PassManager PM;
-        PM.add(createBitcodeWriterPass(OS));
-        PM.run(*unwrap(M));
+        WriteBitcodeToFile(*unwrap(M), OS);
       }
     }
   }
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index b2cfcf53c59..6f36281af23 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -12,7 +12,7 @@
 #include "llvm/Object/COFFImportFile.h"
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/Pass.h"
-#include "llvm/Bitcode/BitcodeWriterPass.h"
+#include "llvm/Bitcode/BitcodeWriter.h"
 #include "llvm/Support/Signals.h"
 #include "llvm/ADT/Optional.h"
 
@@ -1670,11 +1670,7 @@ LLVMRustModuleBufferCreate(LLVMModuleRef M) {
   auto Ret = std::make_unique<LLVMRustModuleBuffer>();
   {
     raw_string_ostream OS(Ret->data);
-    {
-      legacy::PassManager PM;
-      PM.add(createBitcodeWriterPass(OS));
-      PM.run(*unwrap(M));
-    }
+    WriteBitcodeToFile(*unwrap(M), OS);
   }
   return Ret.release();
 }
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
index 3b8d9594eb9..b9a283552f7 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
@@ -2,10 +2,9 @@
 
 use crate::diagnostics::diagnostic_builder::{DiagnosticDeriveBuilder, DiagnosticDeriveKind};
 use crate::diagnostics::error::{span_err, DiagnosticDeriveError};
-use crate::diagnostics::utils::{build_field_mapping, SetOnce};
+use crate::diagnostics::utils::SetOnce;
 use proc_macro2::TokenStream;
 use quote::quote;
-use syn::spanned::Spanned;
 use synstructure::Structure;
 
 /// The central struct for constructing the `into_diagnostic` method from an annotated struct.
@@ -18,13 +17,7 @@ pub(crate) struct DiagnosticDerive<'a> {
 impl<'a> DiagnosticDerive<'a> {
     pub(crate) fn new(diag: syn::Ident, handler: syn::Ident, structure: Structure<'a>) -> Self {
         Self {
-            builder: DiagnosticDeriveBuilder {
-                diag,
-                fields: build_field_mapping(&structure),
-                kind: DiagnosticDeriveKind::Diagnostic,
-                code: None,
-                slug: None,
-            },
+            builder: DiagnosticDeriveBuilder { diag, kind: DiagnosticDeriveKind::Diagnostic },
             handler,
             structure,
         }
@@ -33,52 +26,35 @@ impl<'a> DiagnosticDerive<'a> {
     pub(crate) fn into_tokens(self) -> TokenStream {
         let DiagnosticDerive { mut structure, handler, mut builder } = self;
 
-        let ast = structure.ast();
-        let implementation = {
-            if let syn::Data::Struct(..) = ast.data {
-                let preamble = builder.preamble(&structure);
-                let (attrs, args) = builder.body(&mut structure);
-
-                let span = ast.span().unwrap();
-                let diag = &builder.diag;
-                let init = match builder.slug.value() {
-                    None => {
-                        span_err(span, "diagnostic slug not specified")
-                            .help(&format!(
-                                "specify the slug as the first argument to the `#[diag(...)]` attribute, \
-                                such as `#[diag(typeck::example_error)]`",
-                            ))
-                            .emit();
-                        return DiagnosticDeriveError::ErrorHandled.to_compile_error();
-                    }
-                    Some(slug) => {
-                        quote! {
-                            let mut #diag = #handler.struct_diagnostic(rustc_errors::fluent::#slug);
-                        }
-                    }
-                };
-
-                quote! {
-                    #init
-                    #preamble
-                    match self {
-                        #attrs
-                    }
-                    match self {
-                        #args
+        let implementation = builder.each_variant(&mut structure, |mut builder, variant| {
+            let preamble = builder.preamble(&variant);
+            let body = builder.body(&variant);
+
+            let diag = &builder.parent.diag;
+            let init = match builder.slug.value_ref() {
+                None => {
+                    span_err(builder.span, "diagnostic slug not specified")
+                        .help(&format!(
+                            "specify the slug as the first argument to the `#[diag(...)]` \
+                            attribute, such as `#[diag(typeck::example_error)]`",
+                        ))
+                        .emit();
+                    return DiagnosticDeriveError::ErrorHandled.to_compile_error();
+                }
+                Some(slug) => {
+                    quote! {
+                        let mut #diag = #handler.struct_diagnostic(rustc_errors::fluent::#slug);
                     }
-                    #diag
                 }
-            } else {
-                span_err(
-                    ast.span().unwrap(),
-                    "`#[derive(Diagnostic)]` can only be used on structs",
-                )
-                .emit();
+            };
 
-                DiagnosticDeriveError::ErrorHandled.to_compile_error()
+            quote! {
+                #init
+                #preamble
+                #body
+                #diag
             }
-        };
+        });
 
         structure.gen_impl(quote! {
             gen impl<'__diagnostic_handler_sess, G>
@@ -107,13 +83,7 @@ pub(crate) struct LintDiagnosticDerive<'a> {
 impl<'a> LintDiagnosticDerive<'a> {
     pub(crate) fn new(diag: syn::Ident, structure: Structure<'a>) -> Self {
         Self {
-            builder: DiagnosticDeriveBuilder {
-                diag,
-                fields: build_field_mapping(&structure),
-                kind: DiagnosticDeriveKind::LintDiagnostic,
-                code: None,
-                slug: None,
-            },
+            builder: DiagnosticDeriveBuilder { diag, kind: DiagnosticDeriveKind::LintDiagnostic },
             structure,
         }
     }
@@ -121,54 +91,35 @@ impl<'a> LintDiagnosticDerive<'a> {
     pub(crate) fn into_tokens(self) -> TokenStream {
         let LintDiagnosticDerive { mut structure, mut builder } = self;
 
-        let ast = structure.ast();
-        let implementation = {
-            if let syn::Data::Struct(..) = ast.data {
-                let preamble = builder.preamble(&structure);
-                let (attrs, args) = builder.body(&mut structure);
-
-                let diag = &builder.diag;
-                let span = ast.span().unwrap();
-                let init = match builder.slug.value() {
-                    None => {
-                        span_err(span, "diagnostic slug not specified")
-                            .help(&format!(
-                                "specify the slug as the first argument to the attribute, such as \
-                                 `#[diag(typeck::example_error)]`",
-                            ))
-                            .emit();
-                        return DiagnosticDeriveError::ErrorHandled.to_compile_error();
-                    }
-                    Some(slug) => {
-                        quote! {
-                            let mut #diag = #diag.build(rustc_errors::fluent::#slug);
-                        }
-                    }
-                };
-
-                let implementation = quote! {
-                    #init
-                    #preamble
-                    match self {
-                        #attrs
-                    }
-                    match self {
-                        #args
+        let implementation = builder.each_variant(&mut structure, |mut builder, variant| {
+            let preamble = builder.preamble(&variant);
+            let body = builder.body(&variant);
+
+            let diag = &builder.parent.diag;
+            let init = match builder.slug.value_ref() {
+                None => {
+                    span_err(builder.span, "diagnostic slug not specified")
+                        .help(&format!(
+                            "specify the slug as the first argument to the attribute, such as \
+                             `#[diag(typeck::example_error)]`",
+                        ))
+                        .emit();
+                    return DiagnosticDeriveError::ErrorHandled.to_compile_error();
+                }
+                Some(slug) => {
+                    quote! {
+                        let mut #diag = #diag.build(rustc_errors::fluent::#slug);
                     }
-                    #diag.emit();
-                };
-
-                implementation
-            } else {
-                span_err(
-                    ast.span().unwrap(),
-                    "`#[derive(LintDiagnostic)]` can only be used on structs",
-                )
-                .emit();
+                }
+            };
 
-                DiagnosticDeriveError::ErrorHandled.to_compile_error()
+            quote! {
+                #init
+                #preamble
+                #body
+                #diag.emit();
             }
-        };
+        });
 
         let diag = &builder.diag;
         structure.gen_impl(quote! {
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
index 32d6ba62a0d..9e88dc7a913 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
@@ -5,18 +5,16 @@ use crate::diagnostics::error::{
     DiagnosticDeriveError,
 };
 use crate::diagnostics::utils::{
-    report_error_if_not_applied_to_span, report_type_error, type_is_unit, type_matches_path,
-    Applicability, FieldInfo, FieldInnerTy, HasFieldMap, SetOnce,
+    bind_style_of_field, build_field_mapping, 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,
 };
 use proc_macro2::{Ident, Span, TokenStream};
 use quote::{format_ident, quote};
-use std::collections::HashMap;
-use std::str::FromStr;
 use syn::{
-    parse_quote, spanned::Spanned, Attribute, Field, Meta, MetaList, MetaNameValue, NestedMeta,
-    Path, Type,
+    parse_quote, spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta, Path, Type,
 };
-use synstructure::{BindingInfo, Structure};
+use synstructure::{BindingInfo, Structure, VariantInfo};
 
 /// What kind of diagnostic is being derived - a fatal/error/warning or a lint?
 #[derive(Copy, Clone, PartialEq, Eq)]
@@ -25,36 +23,114 @@ pub(crate) enum DiagnosticDeriveKind {
     LintDiagnostic,
 }
 
-/// Tracks persistent information required for building up individual calls to diagnostic methods
-/// for generated diagnostic derives - both `Diagnostic` for fatal/errors/warnings and
-/// `LintDiagnostic` for lints.
+/// Tracks persistent information required for the entire type when building up individual calls to
+/// diagnostic methods for generated diagnostic derives - both `Diagnostic` for
+/// fatal/errors/warnings and `LintDiagnostic` for lints.
 pub(crate) struct DiagnosticDeriveBuilder {
     /// The identifier to use for the generated `DiagnosticBuilder` instance.
     pub diag: syn::Ident,
+    /// Kind of diagnostic that should be derived.
+    pub kind: DiagnosticDeriveKind,
+}
+
+/// Tracks persistent information required for a specific variant when building up individual calls
+/// to diagnostic methods for generated diagnostic derives - both `Diagnostic` for
+/// fatal/errors/warnings and `LintDiagnostic` for lints.
+pub(crate) struct DiagnosticDeriveVariantBuilder<'parent> {
+    /// The parent builder for the entire type.
+    pub parent: &'parent DiagnosticDeriveBuilder,
+
+    /// Span of the struct or the enum variant.
+    pub span: proc_macro::Span,
 
     /// Store a map of field name to its corresponding field. This is built on construction of the
     /// derive builder.
-    pub fields: HashMap<String, TokenStream>,
+    pub field_map: FieldMap,
 
-    /// Kind of diagnostic that should be derived.
-    pub kind: DiagnosticDeriveKind,
     /// Slug is a mandatory part of the struct attribute as corresponds to the Fluent message that
     /// has the actual diagnostic message.
-    pub slug: Option<(Path, proc_macro::Span)>,
+    pub slug: SpannedOption<Path>,
     /// Error codes are a optional part of the struct attribute - this is only set to detect
     /// multiple specifications.
-    pub code: Option<(String, proc_macro::Span)>,
+    pub code: SpannedOption<()>,
 }
 
-impl HasFieldMap for DiagnosticDeriveBuilder {
+impl<'a> HasFieldMap for DiagnosticDeriveVariantBuilder<'a> {
     fn get_field_binding(&self, field: &String) -> Option<&TokenStream> {
-        self.fields.get(field)
+        self.field_map.get(field)
     }
 }
 
 impl DiagnosticDeriveBuilder {
-    pub fn preamble<'s>(&mut self, structure: &Structure<'s>) -> TokenStream {
+    /// Call `f` for the struct or for each variant of the enum, returning a `TokenStream` with the
+    /// tokens from `f` wrapped in an `match` expression. Emits errors for use of derive on unions
+    /// or attributes on the type itself when input is an enum.
+    pub fn each_variant<'s, F>(&mut self, structure: &mut Structure<'s>, f: F) -> TokenStream
+    where
+        F: for<'a, 'v> Fn(DiagnosticDeriveVariantBuilder<'a>, &VariantInfo<'v>) -> TokenStream,
+    {
         let ast = structure.ast();
+        let span = ast.span().unwrap();
+        match ast.data {
+            syn::Data::Struct(..) | syn::Data::Enum(..) => (),
+            syn::Data::Union(..) => {
+                span_err(span, "diagnostic derives can only be used on structs and enums");
+            }
+        }
+
+        if matches!(ast.data, syn::Data::Enum(..)) {
+            for attr in &ast.attrs {
+                span_err(
+                    attr.span().unwrap(),
+                    "unsupported type attribute for diagnostic derive enum",
+                )
+                .emit();
+            }
+        }
+
+        for variant in structure.variants_mut() {
+            // First, change the binding style of each field based on the code that will be
+            // generated for the field - e.g. `set_arg` calls needs by-move bindings, whereas
+            // `set_primary_span` only needs by-ref.
+            variant.bind_with(|bi| bind_style_of_field(bi.ast()).0);
+
+            // Then, perform a stable sort on bindings which generates code for by-ref bindings
+            // before code generated for by-move bindings. Any code generated for the by-ref
+            // bindings which creates a reference to the by-move fields will happen before the
+            // by-move bindings move those fields and make them inaccessible.
+            variant.bindings_mut().sort_by_cached_key(|bi| bind_style_of_field(bi.ast()));
+        }
+
+        let variants = structure.each_variant(|variant| {
+            let span = match structure.ast().data {
+                syn::Data::Struct(..) => span,
+                // There isn't a good way to get the span of the variant, so the variant's
+                // name will need to do.
+                _ => variant.ast().ident.span().unwrap(),
+            };
+            let builder = DiagnosticDeriveVariantBuilder {
+                parent: &self,
+                span,
+                field_map: build_field_mapping(variant),
+                slug: None,
+                code: None,
+            };
+            f(builder, variant)
+        });
+
+        quote! {
+            match self {
+                #variants
+            }
+        }
+    }
+}
+
+impl<'a> DiagnosticDeriveVariantBuilder<'a> {
+    /// Generates calls to `code` and similar functions based on the attributes on the type or
+    /// variant.
+    pub fn preamble<'s>(&mut self, variant: &VariantInfo<'s>) -> TokenStream {
+        let ast = variant.ast();
         let attrs = &ast.attrs;
         let preamble = attrs.iter().map(|attr| {
             self.generate_structure_code_for_attr(attr).unwrap_or_else(|v| v.to_compile_error())
@@ -65,66 +141,46 @@ impl DiagnosticDeriveBuilder {
         }
     }
 
-    pub fn body<'s>(&mut self, structure: &mut Structure<'s>) -> (TokenStream, TokenStream) {
-        // Keep track of which fields need to be handled with a by-move binding.
-        let mut needs_moved = std::collections::HashSet::new();
-
-        // Generates calls to `span_label` and similar functions based on the attributes
-        // on fields. Code for suggestions uses formatting machinery and the value of
-        // other fields - because any given field can be referenced multiple times, it
-        // should be accessed through a borrow. When passing fields to `add_subdiagnostic`
-        // or `set_arg` (which happens below) for Fluent, we want to move the data, so that
-        // has to happen in a separate pass over the fields.
-        let attrs = structure
-            .clone()
-            .filter(|field_binding| {
-                let ast = &field_binding.ast();
-                !self.needs_move(ast) || {
-                    needs_moved.insert(field_binding.binding.clone());
-                    false
-                }
-            })
-            .each(|field_binding| self.generate_field_attrs_code(field_binding));
-
-        structure.bind_with(|_| synstructure::BindStyle::Move);
-        // When a field has attributes like `#[label]` or `#[note]` then it doesn't
-        // need to be passed as an argument to the diagnostic. But when a field has no
-        // attributes or a `#[subdiagnostic]` attribute then it must be passed as an
-        // argument to the diagnostic so that it can be referred to by Fluent messages.
-        let args = structure
-            .filter(|field_binding| needs_moved.contains(&field_binding.binding))
-            .each(|field_binding| self.generate_field_attrs_code(field_binding));
-
-        (attrs, args)
+    /// Generates calls to `span_label` and similar functions based on the attributes on fields or
+    /// calls to `set_arg` when no attributes are present.
+    ///
+    /// Expects use of `Self::each_variant` which will have sorted bindings so that by-ref bindings
+    /// (which may create references to by-move bindings) have their code generated first -
+    /// necessary as code for suggestions uses formatting machinery and the value of other fields
+    /// (any given field can be referenced multiple times, so must be accessed through a borrow);
+    /// and when passing fields to `add_subdiagnostic` or `set_arg` for Fluent, fields must be
+    /// accessed by-move.
+    pub fn body<'s>(&mut self, variant: &VariantInfo<'s>) -> TokenStream {
+        let mut body = quote! {};
+        for binding in variant.bindings() {
+            body.extend(self.generate_field_attrs_code(binding));
+        }
+        body
     }
 
-    /// Returns `true` if `field` should generate a `set_arg` call rather than any other diagnostic
-    /// call (like `span_label`).
-    fn should_generate_set_arg(&self, field: &Field) -> bool {
-        field.attrs.is_empty()
-    }
+    /// Parse a `SubdiagnosticKind` from an `Attribute`.
+    fn parse_subdiag_attribute(
+        &self,
+        attr: &Attribute,
+    ) -> Result<(SubdiagnosticKind, Path), DiagnosticDeriveError> {
+        let (subdiag, slug) = SubdiagnosticKind::from_attr(attr, self)?;
 
-    /// Returns `true` if `field` needs to have code generated in the by-move branch of the
-    /// generated derive rather than the by-ref branch.
-    fn needs_move(&self, field: &Field) -> bool {
-        let generates_set_arg = self.should_generate_set_arg(field);
-        let is_multispan = type_matches_path(&field.ty, &["rustc_errors", "MultiSpan"]);
-        // FIXME(davidtwco): better support for one field needing to be in the by-move and
-        // by-ref branches.
-        let is_subdiagnostic = field
-            .attrs
-            .iter()
-            .map(|attr| attr.path.segments.last().unwrap().ident.to_string())
-            .any(|attr| attr == "subdiagnostic");
-
-        // `set_arg` calls take their argument by-move..
-        generates_set_arg
-            // If this is a `MultiSpan` field then it needs to be moved to be used by any
-            // attribute..
-            || is_multispan
-            // If this a `#[subdiagnostic]` then it needs to be moved as the other diagnostic is
-            // unlikely to be `Copy`..
-            || is_subdiagnostic
+        if let SubdiagnosticKind::MultipartSuggestion { .. } = subdiag {
+            let meta = attr.parse_meta()?;
+            throw_invalid_attr!(attr, &meta, |diag| diag
+                .help("consider creating a `Subdiagnostic` instead"));
+        }
+
+        let slug = slug.unwrap_or_else(|| match subdiag {
+            SubdiagnosticKind::Label => parse_quote! { _subdiag::label },
+            SubdiagnosticKind::Note => parse_quote! { _subdiag::note },
+            SubdiagnosticKind::Help => parse_quote! { _subdiag::help },
+            SubdiagnosticKind::Warn => parse_quote! { _subdiag::warn },
+            SubdiagnosticKind::Suggestion { .. } => parse_quote! { _subdiag::suggestion },
+            SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(),
+        });
+
+        Ok((subdiag, slug))
     }
 
     /// Establishes state in the `DiagnosticDeriveBuilder` resulting from the struct
@@ -134,99 +190,65 @@ impl DiagnosticDeriveBuilder {
         &mut self,
         attr: &Attribute,
     ) -> Result<TokenStream, DiagnosticDeriveError> {
-        let diag = &self.diag;
-        let span = attr.span().unwrap();
+        let diag = &self.parent.diag;
 
         let name = attr.path.segments.last().unwrap().ident.to_string();
         let name = name.as_str();
         let meta = attr.parse_meta()?;
 
-        let is_diag = name == "diag";
-
-        let nested = match meta {
-            // Most attributes are lists, like `#[diag(..)]` for most cases or
-            // `#[help(..)]`/`#[note(..)]` when the user is specifying a alternative slug.
-            Meta::List(MetaList { ref nested, .. }) => nested,
-            // Subdiagnostics without spans can be applied to the type too, and these are just
-            // paths: `#[help]`, `#[note]` and `#[warning]`
-            Meta::Path(_) if !is_diag => {
-                let fn_name = if name == "warning" {
-                    Ident::new("warn", attr.span())
-                } else {
-                    Ident::new(name, attr.span())
-                };
-                return Ok(quote! { #diag.#fn_name(rustc_errors::fluent::_subdiag::#fn_name); });
-            }
-            _ => throw_invalid_attr!(attr, &meta),
-        };
-
-        // Check the kind before doing any further processing so that there aren't misleading
-        // "no kind specified" errors if there are failures later.
-        match name {
-            "error" | "lint" => throw_invalid_attr!(attr, &meta, |diag| {
-                diag.help("`error` and `lint` have been replaced by `diag`")
-            }),
-            "warn_" => throw_invalid_attr!(attr, &meta, |diag| {
-                diag.help("`warn_` have been replaced by `warning`")
-            }),
-            "diag" | "help" | "note" | "warning" => (),
-            _ => throw_invalid_attr!(attr, &meta, |diag| {
-                diag.help("only `diag`, `help`, `note` and `warning` are valid attributes")
-            }),
-        }
+        if name == "diag" {
+            let Meta::List(MetaList { ref nested, .. }) = meta else {
+                throw_invalid_attr!(
+                    attr,
+                    &meta
+                );
+            };
 
-        // First nested element should always be the path, e.g. `#[diag(typeck::invalid)]` or
-        // `#[help(typeck::another_help)]`.
-        let mut nested_iter = nested.into_iter();
-        if let Some(nested_attr) = nested_iter.next() {
-            // Report an error if there are any other list items after the path.
-            if !is_diag && nested_iter.next().is_some() {
-                throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
-                    diag.help(
-                        "`help`, `note` and `warning` struct attributes can only have one argument",
-                    )
-                });
-            }
+            let mut nested_iter = nested.into_iter().peekable();
 
-            match nested_attr {
-                NestedMeta::Meta(Meta::Path(path)) => {
-                    if is_diag {
-                        self.slug.set_once((path.clone(), span));
-                    } else {
-                        let fn_name = proc_macro2::Ident::new(name, attr.span());
-                        return Ok(quote! { #diag.#fn_name(rustc_errors::fluent::#path); });
-                    }
-                }
-                NestedMeta::Meta(meta @ Meta::NameValue(_))
-                    if is_diag && meta.path().segments.last().unwrap().ident == "code" =>
-                {
-                    // don't error for valid follow-up attributes
+            match nested_iter.peek() {
+                Some(NestedMeta::Meta(Meta::Path(slug))) => {
+                    self.slug.set_once(slug.clone(), slug.span().unwrap());
+                    nested_iter.next();
                 }
-                nested_attr => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
-                    diag.help("first argument of the attribute should be the diagnostic slug")
-                }),
+                Some(NestedMeta::Meta(Meta::NameValue { .. })) => {}
+                Some(nested_attr) => throw_invalid_nested_attr!(attr, &nested_attr, |diag| diag
+                    .help("a diagnostic slug is required as the first argument")),
+                None => throw_invalid_attr!(attr, &meta, |diag| diag
+                    .help("a diagnostic slug is required as the first argument")),
             };
-        }
 
-        // Remaining attributes are optional, only `code = ".."` at the moment.
-        let mut tokens = Vec::new();
-        for nested_attr in nested_iter {
-            let meta = match nested_attr {
-                syn::NestedMeta::Meta(meta) => meta,
-                _ => throw_invalid_nested_attr!(attr, &nested_attr),
-            };
+            // Remaining attributes are optional, only `code = ".."` at the moment.
+            let mut tokens = TokenStream::new();
+            for nested_attr in nested_iter {
+                let (value, path) = match nested_attr {
+                    NestedMeta::Meta(Meta::NameValue(MetaNameValue {
+                        lit: syn::Lit::Str(value),
+                        path,
+                        ..
+                    })) => (value, path),
+                    NestedMeta::Meta(Meta::Path(_)) => {
+                        invalid_nested_attr(attr, &nested_attr)
+                            .help("diagnostic slug must be the first argument")
+                            .emit();
+                        continue;
+                    }
+                    _ => {
+                        invalid_nested_attr(attr, &nested_attr).emit();
+                        continue;
+                    }
+                };
 
-            let path = meta.path();
-            let nested_name = path.segments.last().unwrap().ident.to_string();
-            // Struct attributes are only allowed to be applied once, and the diagnostic
-            // changes will be set in the initialisation code.
-            if let Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) = &meta {
-                let span = s.span().unwrap();
+                let nested_name = path.segments.last().unwrap().ident.to_string();
+                // Struct attributes are only allowed to be applied once, and the diagnostic
+                // changes will be set in the initialisation code.
+                let span = value.span().unwrap();
                 match nested_name.as_str() {
                     "code" => {
-                        self.code.set_once((s.value(), span));
-                        let code = &self.code.as_ref().map(|(v, _)| v);
-                        tokens.push(quote! {
+                        self.code.set_once((), span);
+
+                        let code = value.value();
+                        tokens.extend(quote! {
                             #diag.code(rustc_errors::DiagnosticId::Error(#code.to_string()));
                         });
                     }
@@ -234,21 +256,33 @@ impl DiagnosticDeriveBuilder {
                         .help("only `code` is a valid nested attributes following the slug")
                         .emit(),
                 }
-            } else {
-                invalid_nested_attr(attr, &nested_attr).emit()
             }
+            return Ok(tokens);
         }
 
-        Ok(tokens.into_iter().collect())
+        let (subdiag, slug) = self.parse_subdiag_attribute(attr)?;
+        let fn_ident = format_ident!("{}", subdiag);
+        match subdiag {
+            SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => {
+                Ok(self.add_subdiagnostic(&fn_ident, slug))
+            }
+            SubdiagnosticKind::Label | SubdiagnosticKind::Suggestion { .. } => {
+                throw_invalid_attr!(attr, &meta, |diag| diag
+                    .help("`#[label]` and `#[suggestion]` can only be applied to fields"));
+            }
+            SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(),
+        }
     }
 
     fn generate_field_attrs_code(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream {
         let field = binding_info.ast();
         let field_binding = &binding_info.binding;
 
-        if self.should_generate_set_arg(&field) {
-            let diag = &self.diag;
+        if should_generate_set_arg(&field) {
+            let diag = &self.parent.diag;
             let ident = field.ident.as_ref().unwrap();
+            // strip `r#` prefix, if present
+            let ident = format_ident!("{}", ident);
             return quote! {
                 #diag.set_arg(
                     stringify!(#ident),
@@ -257,7 +291,7 @@ impl DiagnosticDeriveBuilder {
             };
         }
 
-        let needs_move = self.needs_move(&field);
+        let needs_move = bind_style_of_field(&field).is_move();
         let inner_ty = FieldInnerTy::from_type(&field.ty);
 
         field
@@ -303,232 +337,83 @@ impl DiagnosticDeriveBuilder {
         info: FieldInfo<'_>,
         binding: TokenStream,
     ) -> Result<TokenStream, DiagnosticDeriveError> {
-        let meta = attr.parse_meta()?;
-        match meta {
-            Meta::Path(_) => self.generate_inner_field_code_path(attr, info, binding),
-            Meta::List(MetaList { .. }) => self.generate_inner_field_code_list(attr, info, binding),
-            _ => throw_invalid_attr!(attr, &meta),
-        }
-    }
-
-    fn generate_inner_field_code_path(
-        &mut self,
-        attr: &Attribute,
-        info: FieldInfo<'_>,
-        binding: TokenStream,
-    ) -> Result<TokenStream, DiagnosticDeriveError> {
-        assert!(matches!(attr.parse_meta()?, Meta::Path(_)));
-        let diag = &self.diag;
-
+        let diag = &self.parent.diag;
         let meta = attr.parse_meta()?;
 
-        let ident = &attr.path.segments.last().unwrap().ident;
-        let name = ident.to_string();
-        let name = name.as_str();
-        match name {
-            "skip_arg" => {
-                // Don't need to do anything - by virtue of the attribute existing, the
-                // `set_arg` call will not be generated.
-                Ok(quote! {})
-            }
-            "primary_span" => {
-                match self.kind {
+        if let Meta::Path(_) = meta {
+            let ident = &attr.path.segments.last().unwrap().ident;
+            let name = ident.to_string();
+            let name = name.as_str();
+            match name {
+                "skip_arg" => {
+                    // Don't need to do anything - by virtue of the attribute existing, the
+                    // `set_arg` call will not be generated.
+                    return Ok(quote! {});
+                }
+                "primary_span" => match self.parent.kind {
                     DiagnosticDeriveKind::Diagnostic => {
                         report_error_if_not_applied_to_span(attr, &info)?;
 
-                        Ok(quote! {
+                        return Ok(quote! {
                             #diag.set_span(#binding);
-                        })
+                        });
                     }
                     DiagnosticDeriveKind::LintDiagnostic => {
                         throw_invalid_attr!(attr, &meta, |diag| {
                             diag.help("the `primary_span` field attribute is not valid for lint diagnostics")
                         })
                     }
-                }
+                },
+                "subdiagnostic" => return Ok(quote! { #diag.subdiagnostic(#binding); }),
+                _ => {}
             }
-            "label" => {
+        }
+
+        let (subdiag, slug) = self.parse_subdiag_attribute(attr)?;
+
+        let fn_ident = format_ident!("{}", subdiag);
+        match subdiag {
+            SubdiagnosticKind::Label => {
                 report_error_if_not_applied_to_span(attr, &info)?;
-                Ok(self.add_spanned_subdiagnostic(binding, ident, parse_quote! { _subdiag::label }))
+                Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug))
             }
-            "note" | "help" | "warning" => {
-                let warn_ident = Ident::new("warn", Span::call_site());
-                let (ident, path) = match name {
-                    "note" => (ident, parse_quote! { _subdiag::note }),
-                    "help" => (ident, parse_quote! { _subdiag::help }),
-                    "warning" => (&warn_ident, parse_quote! { _subdiag::warn }),
-                    _ => unreachable!(),
-                };
+            SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => {
                 if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
-                    Ok(self.add_spanned_subdiagnostic(binding, ident, path))
+                    Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug))
                 } else if type_is_unit(&info.ty) {
-                    Ok(self.add_subdiagnostic(ident, path))
+                    Ok(self.add_subdiagnostic(&fn_ident, slug))
                 } else {
                     report_type_error(attr, "`Span` or `()`")?
                 }
             }
-            "subdiagnostic" => Ok(quote! { #diag.subdiagnostic(#binding); }),
-            _ => throw_invalid_attr!(attr, &meta, |diag| {
-                diag.help(
-                    "only `skip_arg`, `primary_span`, `label`, `note`, `help` and `subdiagnostic` \
-                     are valid field attributes",
-                )
-            }),
-        }
-    }
-
-    fn generate_inner_field_code_list(
-        &mut self,
-        attr: &Attribute,
-        info: FieldInfo<'_>,
-        binding: TokenStream,
-    ) -> Result<TokenStream, DiagnosticDeriveError> {
-        let meta = attr.parse_meta()?;
-        let Meta::List(MetaList { ref path, ref nested, .. }) = meta  else { unreachable!() };
-
-        let ident = &attr.path.segments.last().unwrap().ident;
-        let name = path.segments.last().unwrap().ident.to_string();
-        let name = name.as_ref();
-        match name {
-            "suggestion" | "suggestion_short" | "suggestion_hidden" | "suggestion_verbose" => {
-                return self.generate_inner_field_code_suggestion(attr, info);
-            }
-            "label" | "help" | "note" | "warning" => (),
-            _ => throw_invalid_attr!(attr, &meta, |diag| {
-                diag.help(
-                    "only `label`, `help`, `note`, `warn` or `suggestion{,_short,_hidden,_verbose}` are \
-                     valid field attributes",
-                )
-            }),
-        }
-
-        // For `#[label(..)]`, `#[note(..)]` and `#[help(..)]`, the first nested element must be a
-        // path, e.g. `#[label(typeck::label)]`.
-        let mut nested_iter = nested.into_iter();
-        let msg = match nested_iter.next() {
-            Some(NestedMeta::Meta(Meta::Path(path))) => path.clone(),
-            Some(nested_attr) => throw_invalid_nested_attr!(attr, &nested_attr),
-            None => throw_invalid_attr!(attr, &meta),
-        };
-
-        // None of these attributes should have anything following the slug.
-        if nested_iter.next().is_some() {
-            throw_invalid_attr!(attr, &meta);
-        }
-
-        match name {
-            "label" => {
-                report_error_if_not_applied_to_span(attr, &info)?;
-                Ok(self.add_spanned_subdiagnostic(binding, ident, msg))
-            }
-            "note" | "help" if type_matches_path(&info.ty, &["rustc_span", "Span"]) => {
-                Ok(self.add_spanned_subdiagnostic(binding, ident, msg))
-            }
-            "note" | "help" if type_is_unit(&info.ty) => Ok(self.add_subdiagnostic(ident, msg)),
-            // `warning` must be special-cased because the attribute `warn` already has meaning and
-            // so isn't used, despite the diagnostic API being named `warn`.
-            "warning" if type_matches_path(&info.ty, &["rustc_span", "Span"]) => Ok(self
-                .add_spanned_subdiagnostic(binding, &Ident::new("warn", Span::call_site()), msg)),
-            "warning" if type_is_unit(&info.ty) => {
-                Ok(self.add_subdiagnostic(&Ident::new("warn", Span::call_site()), msg))
-            }
-            "note" | "help" | "warning" => report_type_error(attr, "`Span` or `()`")?,
-            _ => unreachable!(),
-        }
-    }
-
-    fn generate_inner_field_code_suggestion(
-        &mut self,
-        attr: &Attribute,
-        info: FieldInfo<'_>,
-    ) -> Result<TokenStream, DiagnosticDeriveError> {
-        let diag = &self.diag;
-
-        let mut meta = attr.parse_meta()?;
-        let Meta::List(MetaList { ref path, ref mut nested, .. }) = meta  else { unreachable!() };
-
-        let (span_field, mut applicability) = self.span_and_applicability_of_ty(info)?;
-
-        let mut msg = None;
-        let mut code = None;
-
-        let mut nested_iter = nested.into_iter().peekable();
-        if let Some(nested_attr) = nested_iter.peek() {
-            if let NestedMeta::Meta(Meta::Path(path)) = nested_attr {
-                msg = Some(path.clone());
-            }
-        };
-        // Move the iterator forward if a path was found (don't otherwise so that
-        // code/applicability can be found or an error emitted).
-        if msg.is_some() {
-            let _ = nested_iter.next();
-        }
-
-        for nested_attr in nested_iter {
-            let meta = match nested_attr {
-                syn::NestedMeta::Meta(ref meta) => meta,
-                syn::NestedMeta::Lit(_) => throw_invalid_nested_attr!(attr, &nested_attr),
-            };
-
-            let nested_name = meta.path().segments.last().unwrap().ident.to_string();
-            let nested_name = nested_name.as_str();
-            match meta {
-                Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => {
-                    let span = meta.span().unwrap();
-                    match nested_name {
-                        "code" => {
-                            let formatted_str = self.build_format(&s.value(), s.span());
-                            code = Some(formatted_str);
-                        }
-                        "applicability" => {
-                            applicability = match applicability {
-                                Some(v) => {
-                                    span_err(
-                                        span,
-                                        "applicability cannot be set in both the field and \
-                                         attribute",
-                                    )
-                                    .emit();
-                                    Some(v)
-                                }
-                                None => match Applicability::from_str(&s.value()) {
-                                    Ok(v) => Some(quote! { #v }),
-                                    Err(()) => {
-                                        span_err(span, "invalid applicability").emit();
-                                        None
-                                    }
-                                },
-                            }
-                        }
-                        _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
-                            diag.help(
-                                "only `message`, `code` and `applicability` are valid field \
-                                 attributes",
-                            )
-                        }),
-                    }
+            SubdiagnosticKind::Suggestion {
+                suggestion_kind,
+                applicability: static_applicability,
+                code,
+            } => {
+                let (span_field, mut applicability) = self.span_and_applicability_of_ty(info)?;
+
+                if let Some((static_applicability, span)) = static_applicability {
+                    applicability.set_once(quote! { #static_applicability }, span);
                 }
-                _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
-                    if matches!(meta, Meta::Path(_)) {
-                        diag.help("a diagnostic slug must be the first argument to the attribute")
-                    } else {
-                        diag
-                    }
-                }),
+
+                let applicability = applicability
+                    .value()
+                    .unwrap_or_else(|| quote! { rustc_errors::Applicability::Unspecified });
+                let style = suggestion_kind.to_suggestion_style();
+
+                Ok(quote! {
+                    #diag.span_suggestion_with_style(
+                        #span_field,
+                        rustc_errors::fluent::#slug,
+                        #code,
+                        #applicability,
+                        #style
+                    );
+                })
             }
+            SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(),
         }
-
-        let applicability =
-            applicability.unwrap_or_else(|| quote!(rustc_errors::Applicability::Unspecified));
-
-        let name = path.segments.last().unwrap().ident.to_string();
-        let method = format_ident!("span_{}", name);
-
-        let msg = msg.unwrap_or_else(|| parse_quote! { _subdiag::suggestion });
-        let msg = quote! { rustc_errors::fluent::#msg };
-        let code = code.unwrap_or_else(|| quote! { String::new() });
-
-        Ok(quote! { #diag.#method(#span_field, #msg, #code, #applicability); })
     }
 
     /// Adds a spanned subdiagnostic by generating a `diag.span_$kind` call with the current slug
@@ -539,7 +424,7 @@ impl DiagnosticDeriveBuilder {
         kind: &Ident,
         fluent_attr_identifier: Path,
     ) -> TokenStream {
-        let diag = &self.diag;
+        let diag = &self.parent.diag;
         let fn_name = format_ident!("span_{}", kind);
         quote! {
             #diag.#fn_name(
@@ -552,7 +437,7 @@ impl DiagnosticDeriveBuilder {
     /// Adds a subdiagnostic by generating a `diag.span_$kind` call with the current slug
     /// and `fluent_attr_identifier`.
     fn add_subdiagnostic(&self, kind: &Ident, fluent_attr_identifier: Path) -> TokenStream {
-        let diag = &self.diag;
+        let diag = &self.parent.diag;
         quote! {
             #diag.#kind(rustc_errors::fluent::#fluent_attr_identifier);
         }
@@ -561,7 +446,7 @@ impl DiagnosticDeriveBuilder {
     fn span_and_applicability_of_ty(
         &self,
         info: FieldInfo<'_>,
-    ) -> Result<(TokenStream, Option<TokenStream>), DiagnosticDeriveError> {
+    ) -> Result<(TokenStream, SpannedOption<TokenStream>), DiagnosticDeriveError> {
         match &info.ty {
             // If `ty` is `Span` w/out applicability, then use `Applicability::Unspecified`.
             ty @ Type::Path(..) if type_matches_path(ty, &["rustc_span", "Span"]) => {
@@ -573,46 +458,37 @@ impl DiagnosticDeriveBuilder {
                 let mut span_idx = None;
                 let mut applicability_idx = None;
 
+                fn type_err(span: &Span) -> Result<!, DiagnosticDeriveError> {
+                    span_err(span.unwrap(), "wrong types for suggestion")
+                        .help(
+                            "`#[suggestion(...)]` on a tuple field must be applied to fields \
+                             of type `(Span, Applicability)`",
+                        )
+                        .emit();
+                    Err(DiagnosticDeriveError::ErrorHandled)
+                }
+
                 for (idx, elem) in tup.elems.iter().enumerate() {
                     if type_matches_path(elem, &["rustc_span", "Span"]) {
-                        if span_idx.is_none() {
-                            span_idx = Some(syn::Index::from(idx));
-                        } else {
-                            throw_span_err!(
-                                info.span.unwrap(),
-                                "type of field annotated with `#[suggestion(...)]` contains more \
-                                 than one `Span`"
-                            );
-                        }
+                        span_idx.set_once(syn::Index::from(idx), elem.span().unwrap());
                     } else if type_matches_path(elem, &["rustc_errors", "Applicability"]) {
-                        if applicability_idx.is_none() {
-                            applicability_idx = Some(syn::Index::from(idx));
-                        } else {
-                            throw_span_err!(
-                                info.span.unwrap(),
-                                "type of field annotated with `#[suggestion(...)]` contains more \
-                                 than one Applicability"
-                            );
-                        }
+                        applicability_idx.set_once(syn::Index::from(idx), elem.span().unwrap());
+                    } else {
+                        type_err(&elem.span())?;
                     }
                 }
 
-                if let Some(span_idx) = span_idx {
-                    let binding = &info.binding.binding;
-                    let span = quote!(#binding.#span_idx);
-                    let applicability = applicability_idx
-                        .map(|applicability_idx| quote!(#binding.#applicability_idx))
-                        .unwrap_or_else(|| quote!(rustc_errors::Applicability::Unspecified));
-
-                    return Ok((span, Some(applicability)));
-                }
+                let Some((span_idx, _)) = span_idx else {
+                    type_err(&tup.span())?;
+                };
+                let Some((applicability_idx, applicability_span)) = applicability_idx else {
+                    type_err(&tup.span())?;
+                };
+                let binding = &info.binding.binding;
+                let span = quote!(#binding.#span_idx);
+                let applicability = quote!(#binding.#applicability_idx);
 
-                throw_span_err!(info.span.unwrap(), "wrong types for suggestion", |diag| {
-                    diag.help(
-                        "`#[suggestion(...)]` on a tuple field must be applied to fields of type \
-                         `(Span, Applicability)`",
-                    )
-                });
+                Ok((span, Some((applicability, applicability_span))))
             }
             // If `ty` isn't a `Span` or `(Span, Applicability)` then emit an error.
             _ => throw_span_err!(info.span.unwrap(), "wrong field type for suggestion", |diag| {
diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
index bdeca3420bc..9a2588513f0 100644
--- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
@@ -1,102 +1,19 @@
 #![deny(unused_must_use)]
 
 use crate::diagnostics::error::{
-    span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err, DiagnosticDeriveError,
+    invalid_attr, span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err,
+    DiagnosticDeriveError,
 };
 use crate::diagnostics::utils::{
-    report_error_if_not_applied_to_applicability, report_error_if_not_applied_to_span,
-    Applicability, FieldInfo, FieldInnerTy, HasFieldMap, SetOnce,
+    build_field_mapping, 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 std::collections::HashMap;
-use std::fmt;
-use std::str::FromStr;
 use syn::{spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta, Path};
 use synstructure::{BindingInfo, Structure, VariantInfo};
 
-/// Which kind of suggestion is being created?
-#[derive(Clone, Copy)]
-enum SubdiagnosticSuggestionKind {
-    /// `#[suggestion]`
-    Normal,
-    /// `#[suggestion_short]`
-    Short,
-    /// `#[suggestion_hidden]`
-    Hidden,
-    /// `#[suggestion_verbose]`
-    Verbose,
-}
-
-impl FromStr for SubdiagnosticSuggestionKind {
-    type Err = ();
-
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        match s {
-            "" => Ok(SubdiagnosticSuggestionKind::Normal),
-            "_short" => Ok(SubdiagnosticSuggestionKind::Short),
-            "_hidden" => Ok(SubdiagnosticSuggestionKind::Hidden),
-            "_verbose" => Ok(SubdiagnosticSuggestionKind::Verbose),
-            _ => Err(()),
-        }
-    }
-}
-
-impl SubdiagnosticSuggestionKind {
-    pub fn to_suggestion_style(&self) -> TokenStream {
-        match self {
-            SubdiagnosticSuggestionKind::Normal => {
-                quote! { rustc_errors::SuggestionStyle::ShowCode }
-            }
-            SubdiagnosticSuggestionKind::Short => {
-                quote! { rustc_errors::SuggestionStyle::HideCodeInline }
-            }
-            SubdiagnosticSuggestionKind::Hidden => {
-                quote! { rustc_errors::SuggestionStyle::HideCodeAlways }
-            }
-            SubdiagnosticSuggestionKind::Verbose => {
-                quote! { rustc_errors::SuggestionStyle::ShowAlways }
-            }
-        }
-    }
-}
-
-/// Which kind of subdiagnostic is being created from a variant?
-#[derive(Clone)]
-enum SubdiagnosticKind {
-    /// `#[label(...)]`
-    Label,
-    /// `#[note(...)]`
-    Note,
-    /// `#[help(...)]`
-    Help,
-    /// `#[warning(...)]`
-    Warn,
-    /// `#[suggestion{,_short,_hidden,_verbose}]`
-    Suggestion { suggestion_kind: SubdiagnosticSuggestionKind, code: TokenStream },
-    /// `#[multipart_suggestion{,_short,_hidden,_verbose}]`
-    MultipartSuggestion { suggestion_kind: SubdiagnosticSuggestionKind },
-}
-
-impl quote::IdentFragment for SubdiagnosticKind {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            SubdiagnosticKind::Label => write!(f, "label"),
-            SubdiagnosticKind::Note => write!(f, "note"),
-            SubdiagnosticKind::Help => write!(f, "help"),
-            SubdiagnosticKind::Warn => write!(f, "warn"),
-            SubdiagnosticKind::Suggestion { .. } => write!(f, "suggestion_with_style"),
-            SubdiagnosticKind::MultipartSuggestion { .. } => {
-                write!(f, "multipart_suggestion_with_style")
-            }
-        }
-    }
-
-    fn span(&self) -> Option<proc_macro2::Span> {
-        None
-    }
-}
-
 /// The central struct for constructing the `add_to_diagnostic` method from an annotated struct.
 pub(crate) struct SubdiagnosticDerive<'a> {
     structure: Structure<'a>,
@@ -136,21 +53,11 @@ impl<'a> SubdiagnosticDerive<'a> {
 
             structure.bind_with(|_| synstructure::BindStyle::Move);
             let variants_ = structure.each_variant(|variant| {
-                // Build the mapping of field names to fields. This allows attributes to peek
-                // values from other fields.
-                let mut fields_map = HashMap::new();
-                for binding in variant.bindings() {
-                    let field = binding.ast();
-                    if let Some(ident) = &field.ident {
-                        fields_map.insert(ident.to_string(), quote! { #binding });
-                    }
-                }
-
                 let mut builder = SubdiagnosticDeriveBuilder {
                     diag: &diag,
                     variant,
                     span,
-                    fields: fields_map,
+                    fields: build_field_mapping(variant),
                     span_field: None,
                     applicability: None,
                     has_suggestion_parts: false,
@@ -192,13 +99,13 @@ struct SubdiagnosticDeriveBuilder<'a> {
 
     /// Store a map of field name to its corresponding field. This is built on construction of the
     /// derive builder.
-    fields: HashMap<String, TokenStream>,
+    fields: FieldMap,
 
     /// Identifier for the binding to the `#[primary_span]` field.
-    span_field: Option<(proc_macro2::Ident, proc_macro::Span)>,
-    /// If a suggestion, the identifier for the binding to the `#[applicability]` field or a
-    /// `rustc_errors::Applicability::*` variant directly.
-    applicability: Option<(TokenStream, proc_macro::Span)>,
+    span_field: SpannedOption<proc_macro2::Ident>,
+
+    /// The binding to the `#[applicability]` field, if present.
+    applicability: SpannedOption<TokenStream>,
 
     /// Set to true when a `#[suggestion_part]` field is encountered, used to generate an error
     /// during finalization if still `false`.
@@ -217,6 +124,7 @@ struct KindsStatistics {
     has_multipart_suggestion: bool,
     all_multipart_suggestions: bool,
     has_normal_suggestion: bool,
+    all_applicabilities_static: bool,
 }
 
 impl<'a> FromIterator<&'a SubdiagnosticKind> for KindsStatistics {
@@ -225,8 +133,15 @@ impl<'a> FromIterator<&'a SubdiagnosticKind> for KindsStatistics {
             has_multipart_suggestion: false,
             all_multipart_suggestions: true,
             has_normal_suggestion: false,
+            all_applicabilities_static: true,
         };
+
         for kind in kinds {
+            if let SubdiagnosticKind::MultipartSuggestion { applicability: None, .. }
+            | SubdiagnosticKind::Suggestion { applicability: None, .. } = kind
+            {
+                ret.all_applicabilities_static = false;
+            }
             if let SubdiagnosticKind::MultipartSuggestion { .. } = kind {
                 ret.has_multipart_suggestion = true;
             } else {
@@ -246,129 +161,14 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
         let mut kind_slugs = vec![];
 
         for attr in self.variant.ast().attrs {
-            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 Meta::List(MetaList { ref nested, .. }) = meta else {
-                throw_invalid_attr!(attr, &meta);
-            };
-
-            let mut kind = match name {
-                "label" => SubdiagnosticKind::Label,
-                "note" => SubdiagnosticKind::Note,
-                "help" => SubdiagnosticKind::Help,
-                "warning" => SubdiagnosticKind::Warn,
-                _ => {
-                    if let Some(suggestion_kind) =
-                        name.strip_prefix("suggestion").and_then(|s| s.parse().ok())
-                    {
-                        SubdiagnosticKind::Suggestion { suggestion_kind, code: TokenStream::new() }
-                    } else if let Some(suggestion_kind) =
-                        name.strip_prefix("multipart_suggestion").and_then(|s| s.parse().ok())
-                    {
-                        SubdiagnosticKind::MultipartSuggestion { suggestion_kind }
-                    } else {
-                        throw_invalid_attr!(attr, &meta);
-                    }
-                }
-            };
-
-            let mut slug = None;
-            let mut code = None;
-
-            let mut nested_iter = nested.into_iter();
-            if let Some(nested_attr) = nested_iter.next() {
-                match nested_attr {
-                    NestedMeta::Meta(Meta::Path(path)) => {
-                        slug.set_once((path.clone(), span));
-                    }
-                    NestedMeta::Meta(meta @ Meta::NameValue(_))
-                        if matches!(
-                            meta.path().segments.last().unwrap().ident.to_string().as_str(),
-                            "code" | "applicability"
-                        ) =>
-                    {
-                        // Don't error for valid follow-up attributes.
-                    }
-                    nested_attr => {
-                        throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
-                            diag.help(
-                                "first argument of the attribute should be the diagnostic \
-                                 slug",
-                            )
-                        })
-                    }
-                };
-            }
-
-            for nested_attr in nested_iter {
-                let meta = match nested_attr {
-                    NestedMeta::Meta(ref meta) => meta,
-                    _ => throw_invalid_nested_attr!(attr, &nested_attr),
-                };
-
-                let span = meta.span().unwrap();
-                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,
-                    Meta::Path(_) => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
-                        diag.help("a diagnostic slug must be the first argument to the attribute")
-                    }),
-                    _ => throw_invalid_nested_attr!(attr, &nested_attr),
-                };
+            let (kind, slug) = SubdiagnosticKind::from_attr(attr, self)?;
 
-                match nested_name {
-                    "code" => {
-                        if matches!(kind, SubdiagnosticKind::Suggestion { .. }) {
-                            let formatted_str = self.build_format(&value.value(), value.span());
-                            code.set_once((formatted_str, span));
-                        } else {
-                            span_err(
-                                span,
-                                &format!(
-                                    "`code` is not a valid nested attribute of a `{}` attribute",
-                                    name
-                                ),
-                            )
-                            .emit();
-                        }
-                    }
-                    "applicability" => {
-                        if matches!(
-                            kind,
-                            SubdiagnosticKind::Suggestion { .. }
-                                | SubdiagnosticKind::MultipartSuggestion { .. }
-                        ) {
-                            let value =
-                                Applicability::from_str(&value.value()).unwrap_or_else(|()| {
-                                    span_err(span, "invalid applicability").emit();
-                                    Applicability::Unspecified
-                                });
-                            self.applicability.set_once((quote! { #value }, span));
-                        } else {
-                            span_err(
-                                span,
-                                &format!(
-                                    "`applicability` is not a valid nested attribute of a `{}` attribute",
-                                    name
-                                )
-                            ).emit();
-                        }
-                    }
-                    _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
-                        diag.help("only `code` and `applicability` are valid nested attributes")
-                    }),
-                }
-            }
+            let Some(slug) = slug else {
+                let name = attr.path.segments.last().unwrap().ident.to_string();
+                let name = name.as_str();
 
-            let Some((slug, _)) = slug else {
                 throw_span_err!(
-                    span,
+                    attr.span().unwrap(),
                     &format!(
                         "diagnostic slug must be first argument of a `#[{}(...)]` attribute",
                         name
@@ -376,21 +176,7 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
                 );
             };
 
-            match kind {
-                SubdiagnosticKind::Suggestion { code: ref mut code_field, .. } => {
-                    let Some((code, _)) = code else {
-                        throw_span_err!(span, "suggestion without `code = \"...\"`");
-                    };
-                    *code_field = code;
-                }
-                SubdiagnosticKind::Label
-                | SubdiagnosticKind::Note
-                | SubdiagnosticKind::Help
-                | SubdiagnosticKind::Warn
-                | SubdiagnosticKind::MultipartSuggestion { .. } => {}
-            }
-
-            kind_slugs.push((kind, slug))
+            kind_slugs.push((kind, slug));
         }
 
         Ok(kind_slugs)
@@ -403,6 +189,9 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
 
         let diag = &self.diag;
         let ident = ast.ident.as_ref().unwrap();
+        // strip `r#` prefix, if present
+        let ident = format_ident!("{}", ident);
+
         quote! {
             #diag.set_arg(
                 stringify!(#ident),
@@ -474,18 +263,18 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
             "skip_arg" => Ok(quote! {}),
             "primary_span" => {
                 if kind_stats.has_multipart_suggestion {
-                    throw_invalid_attr!(attr, &Meta::Path(path), |diag| {
-                        diag.help(
+                    invalid_attr(attr, &Meta::Path(path))
+                        .help(
                             "multipart suggestions use one or more `#[suggestion_part]`s rather \
                             than one `#[primary_span]`",
                         )
-                    })
-                }
-
-                report_error_if_not_applied_to_span(attr, &info)?;
+                        .emit();
+                } else {
+                    report_error_if_not_applied_to_span(attr, &info)?;
 
-                let binding = info.binding.binding.clone();
-                self.span_field.set_once((binding, span));
+                    let binding = info.binding.binding.clone();
+                    self.span_field.set_once(binding, span);
+                }
 
                 Ok(quote! {})
             }
@@ -495,28 +284,39 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
                 if kind_stats.has_multipart_suggestion {
                     span_err(span, "`#[suggestion_part(...)]` attribute without `code = \"...\"`")
                         .emit();
-                    Ok(quote! {})
                 } else {
-                    throw_invalid_attr!(attr, &Meta::Path(path), |diag| {
-                        diag.help(
-                                "`#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead",
-                            )
-                    });
+                    invalid_attr(attr, &Meta::Path(path))
+                        .help(
+                            "`#[suggestion_part(...)]` is only valid in multipart suggestions, \
+                             use `#[primary_span]` instead",
+                        )
+                        .emit();
                 }
+
+                Ok(quote! {})
             }
             "applicability" => {
                 if kind_stats.has_multipart_suggestion || kind_stats.has_normal_suggestion {
                     report_error_if_not_applied_to_applicability(attr, &info)?;
 
+                    if kind_stats.all_applicabilities_static {
+                        span_err(
+                            span,
+                            "`#[applicability]` has no effect if all `#[suggestion]`/\
+                             `#[multipart_suggestion]` attributes have a static \
+                             `applicability = \"...\"`",
+                        )
+                        .emit();
+                    }
                     let binding = info.binding.binding.clone();
-                    self.applicability.set_once((quote! { #binding }, span));
+                    self.applicability.set_once(quote! { #binding }, span);
                 } else {
                     span_err(span, "`#[applicability]` is only valid on suggestions").emit();
                 }
 
                 Ok(quote! {})
             }
-            _ => throw_invalid_attr!(attr, &Meta::Path(path), |diag| {
+            _ => {
                 let mut span_attrs = vec![];
                 if kind_stats.has_multipart_suggestion {
                     span_attrs.push("suggestion_part");
@@ -524,11 +324,16 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
                 if !kind_stats.all_multipart_suggestions {
                     span_attrs.push("primary_span")
                 }
-                diag.help(format!(
-                    "only `{}`, `applicability` and `skip_arg` are valid field attributes",
-                    span_attrs.join(", ")
-                ))
-            }),
+
+                invalid_attr(attr, &Meta::Path(path))
+                    .help(format!(
+                        "only `{}`, `applicability` and `skip_arg` are valid field attributes",
+                        span_attrs.join(", ")
+                    ))
+                    .emit();
+
+                Ok(quote! {})
+            }
         }
     }
 
@@ -577,7 +382,7 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
                     match nested_name {
                         "code" => {
                             let formatted_str = self.build_format(&value.value(), value.span());
-                            code.set_once((formatted_str, span));
+                            code.set_once(formatted_str, span);
                         }
                         _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
                             diag.help("`code` is the only valid nested attribute")
@@ -635,11 +440,7 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
             .map(|binding| self.generate_field_attr_code(binding, kind_stats))
             .collect();
 
-        let span_field = self.span_field.as_ref().map(|(span, _)| span);
-        let applicability = self.applicability.take().map_or_else(
-            || quote! { rustc_errors::Applicability::Unspecified },
-            |(applicability, _)| applicability,
-        );
+        let span_field = self.span_field.value_ref();
 
         let diag = &self.diag;
         let mut calls = TokenStream::new();
@@ -647,7 +448,13 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
             let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind);
             let message = quote! { rustc_errors::fluent::#slug };
             let call = match kind {
-                SubdiagnosticKind::Suggestion { suggestion_kind, code } => {
+                SubdiagnosticKind::Suggestion { suggestion_kind, applicability, code } => {
+                    let applicability = applicability
+                        .value()
+                        .map(|a| quote! { #a })
+                        .or_else(|| self.applicability.take().value())
+                        .unwrap_or_else(|| quote! { rustc_errors::Applicability::Unspecified });
+
                     if let Some(span) = span_field {
                         let style = suggestion_kind.to_suggestion_style();
 
@@ -657,7 +464,13 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
                         quote! { unreachable!(); }
                     }
                 }
-                SubdiagnosticKind::MultipartSuggestion { suggestion_kind } => {
+                SubdiagnosticKind::MultipartSuggestion { suggestion_kind, applicability } => {
+                    let applicability = applicability
+                        .value()
+                        .map(|a| quote! { #a })
+                        .or_else(|| self.applicability.take().value())
+                        .unwrap_or_else(|| quote! { rustc_errors::Applicability::Unspecified });
+
                     if !self.has_suggestion_parts {
                         span_err(
                             self.span,
diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs
index ad9ecd39b9e..162699c2868 100644
--- a/compiler/rustc_macros/src/diagnostics/utils.rs
+++ b/compiler/rustc_macros/src/diagnostics/utils.rs
@@ -1,11 +1,18 @@
-use crate::diagnostics::error::{span_err, throw_span_err, DiagnosticDeriveError};
+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 quote::{format_ident, quote, ToTokens};
+use std::cmp::Ordering;
 use std::collections::{BTreeSet, HashMap};
+use std::fmt;
 use std::str::FromStr;
-use syn::{spanned::Spanned, Attribute, Meta, Type, TypeTuple};
-use synstructure::{BindingInfo, Structure};
+use syn::{spanned::Spanned, Attribute, Field, Meta, Type, TypeTuple};
+use syn::{MetaList, MetaNameValue, NestedMeta, Path};
+use synstructure::{BindStyle, BindingInfo, VariantInfo};
+
+use super::error::invalid_nested_attr;
 
 /// Checks whether the type name of `ty` matches `name`.
 ///
@@ -172,13 +179,17 @@ pub(crate) struct FieldInfo<'a> {
 /// Small helper trait for abstracting over `Option` fields that contain a value and a `Span`
 /// for error reporting if they are set more than once.
 pub(crate) trait SetOnce<T> {
-    fn set_once(&mut self, _: (T, Span));
+    fn set_once(&mut self, value: T, span: Span);
 
     fn value(self) -> Option<T>;
+    fn value_ref(&self) -> Option<&T>;
 }
 
-impl<T> SetOnce<T> for Option<(T, Span)> {
-    fn set_once(&mut self, (value, span): (T, Span)) {
+/// An [`Option<T>`] that keeps track of the span that caused it to be set; used with [`SetOnce`].
+pub(super) type SpannedOption<T> = Option<(T, Span)>;
+
+impl<T> SetOnce<T> for SpannedOption<T> {
+    fn set_once(&mut self, value: T, span: Span) {
         match self {
             None => {
                 *self = Some((value, span));
@@ -194,8 +205,14 @@ impl<T> SetOnce<T> for Option<(T, Span)> {
     fn value(self) -> Option<T> {
         self.map(|(v, _)| v)
     }
+
+    fn value_ref(&self) -> Option<&T> {
+        self.as_ref().map(|(v, _)| v)
+    }
 }
 
+pub(super) type FieldMap = HashMap<String, TokenStream>;
+
 pub(crate) trait HasFieldMap {
     /// Returns the binding for the field with the given name, if it exists on the type.
     fn get_field_binding(&self, field: &String) -> Option<&TokenStream>;
@@ -303,6 +320,7 @@ pub(crate) trait HasFieldMap {
 
 /// `Applicability` of a suggestion - mirrors `rustc_errors::Applicability` - and used to represent
 /// the user's selection of applicability if specified in an attribute.
+#[derive(Clone, Copy)]
 pub(crate) enum Applicability {
     MachineApplicable,
     MaybeIncorrect,
@@ -345,17 +363,322 @@ impl quote::ToTokens for Applicability {
 
 /// Build the mapping of field names to fields. This allows attributes to peek values from
 /// other fields.
-pub(crate) fn build_field_mapping<'a>(structure: &Structure<'a>) -> HashMap<String, TokenStream> {
-    let mut fields_map = HashMap::new();
-
-    let ast = structure.ast();
-    if let syn::Data::Struct(syn::DataStruct { fields, .. }) = &ast.data {
-        for field in fields.iter() {
-            if let Some(ident) = &field.ident {
-                fields_map.insert(ident.to_string(), quote! { &self.#ident });
+pub(super) fn build_field_mapping<'v>(variant: &VariantInfo<'v>) -> HashMap<String, TokenStream> {
+    let mut fields_map = FieldMap::new();
+    for binding in variant.bindings() {
+        if let Some(ident) = &binding.ast().ident {
+            fields_map.insert(ident.to_string(), quote! { #binding });
+        }
+    }
+    fields_map
+}
+
+/// Possible styles for suggestion subdiagnostics.
+#[derive(Clone, Copy)]
+pub(super) enum SuggestionKind {
+    /// `#[suggestion]`
+    Normal,
+    /// `#[suggestion_short]`
+    Short,
+    /// `#[suggestion_hidden]`
+    Hidden,
+    /// `#[suggestion_verbose]`
+    Verbose,
+}
+
+impl FromStr for SuggestionKind {
+    type Err = ();
+
+    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),
+            _ => Err(()),
+        }
+    }
+}
+
+impl SuggestionKind {
+    pub fn to_suggestion_style(&self) -> TokenStream {
+        match self {
+            SuggestionKind::Normal => {
+                quote! { rustc_errors::SuggestionStyle::ShowCode }
+            }
+            SuggestionKind::Short => {
+                quote! { rustc_errors::SuggestionStyle::HideCodeInline }
+            }
+            SuggestionKind::Hidden => {
+                quote! { rustc_errors::SuggestionStyle::HideCodeAlways }
+            }
+            SuggestionKind::Verbose => {
+                quote! { rustc_errors::SuggestionStyle::ShowAlways }
             }
         }
     }
+}
 
-    fields_map
+/// Types of subdiagnostics that can be created using attributes
+#[derive(Clone)]
+pub(super) enum SubdiagnosticKind {
+    /// `#[label(...)]`
+    Label,
+    /// `#[note(...)]`
+    Note,
+    /// `#[help(...)]`
+    Help,
+    /// `#[warning(...)]`
+    Warn,
+    /// `#[suggestion{,_short,_hidden,_verbose}]`
+    Suggestion {
+        suggestion_kind: SuggestionKind,
+        applicability: SpannedOption<Applicability>,
+        code: TokenStream,
+    },
+    /// `#[multipart_suggestion{,_short,_hidden,_verbose}]`
+    MultipartSuggestion {
+        suggestion_kind: SuggestionKind,
+        applicability: SpannedOption<Applicability>,
+    },
+}
+
+impl SubdiagnosticKind {
+    /// Constructs a `SubdiagnosticKind` from a field or type attribute such as `#[note]`,
+    /// `#[error(parser::add_paren)]` or `#[suggestion(code = "...")]`. Returns the
+    /// `SubdiagnosticKind` and the diagnostic slug, if specified.
+    pub(super) fn from_attr(
+        attr: &Attribute,
+        fields: &impl HasFieldMap,
+    ) -> Result<(SubdiagnosticKind, Option<Path>), DiagnosticDeriveError> {
+        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,
+            _ => {
+                if let Some(suggestion_kind) =
+                    name.strip_prefix("suggestion").and_then(|s| s.parse().ok())
+                {
+                    SubdiagnosticKind::Suggestion {
+                        suggestion_kind,
+                        applicability: None,
+                        code: TokenStream::new(),
+                    }
+                } else if let Some(suggestion_kind) =
+                    name.strip_prefix("multipart_suggestion").and_then(|s| s.parse().ok())
+                {
+                    SubdiagnosticKind::MultipartSuggestion { suggestion_kind, applicability: None }
+                } else {
+                    throw_invalid_attr!(attr, &meta);
+                }
+            }
+        };
+
+        let nested = match meta {
+            Meta::List(MetaList { ref nested, .. }) => {
+                // An attribute with properties, such as `#[suggestion(code = "...")]` or
+                // `#[error(some::slug)]`
+                nested
+            }
+            Meta::Path(_) => {
+                // An attribute without a slug or other properties, such as `#[note]` - return
+                // without further processing.
+                //
+                // Only allow this if there are no mandatory properties, such as `code = "..."` in
+                // `#[suggestion(...)]`
+                match kind {
+                    SubdiagnosticKind::Label
+                    | SubdiagnosticKind::Note
+                    | SubdiagnosticKind::Help
+                    | SubdiagnosticKind::Warn
+                    | SubdiagnosticKind::MultipartSuggestion { .. } => return Ok((kind, None)),
+                    SubdiagnosticKind::Suggestion { .. } => {
+                        throw_span_err!(span, "suggestion without `code = \"...\"`")
+                    }
+                }
+            }
+            _ => {
+                throw_invalid_attr!(attr, &meta)
+            }
+        };
+
+        let mut code = None;
+
+        let mut nested_iter = nested.into_iter().peekable();
+
+        // Peek at the first nested attribute: if it's a slug path, consume it.
+        let slug = if let Some(NestedMeta::Meta(Meta::Path(path))) = nested_iter.peek() {
+            let path = path.clone();
+            // Advance the iterator.
+            nested_iter.next();
+            Some(path)
+        } else {
+            None
+        };
+
+        for nested_attr in nested_iter {
+            let meta = match nested_attr {
+                NestedMeta::Meta(ref meta) => meta,
+                NestedMeta::Lit(_) => {
+                    invalid_nested_attr(attr, &nested_attr).emit();
+                    continue;
+                }
+            };
+
+            let span = meta.span().unwrap();
+            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,
+                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;
+                }
+            };
+
+            match (nested_name, &mut kind) {
+                ("code", SubdiagnosticKind::Suggestion { .. }) => {
+                    let formatted_str = fields.build_format(&value.value(), value.span());
+                    code.set_once(formatted_str, span);
+                }
+                (
+                    "applicability",
+                    SubdiagnosticKind::Suggestion { ref mut applicability, .. }
+                    | SubdiagnosticKind::MultipartSuggestion { ref mut applicability, .. },
+                ) => {
+                    let value = Applicability::from_str(&value.value()).unwrap_or_else(|()| {
+                        span_err(span, "invalid applicability").emit();
+                        Applicability::Unspecified
+                    });
+                    applicability.set_once(value, span);
+                }
+
+                // Invalid nested attribute
+                (_, SubdiagnosticKind::Suggestion { .. }) => {
+                    invalid_nested_attr(attr, &nested_attr)
+                        .help("only `code` and `applicability` are valid nested attributes")
+                        .emit();
+                }
+                (_, SubdiagnosticKind::MultipartSuggestion { .. }) => {
+                    invalid_nested_attr(attr, &nested_attr)
+                        .help("only `applicability` is a valid nested attributes")
+                        .emit()
+                }
+                _ => {
+                    invalid_nested_attr(attr, &nested_attr).emit();
+                }
+            }
+        }
+
+        match kind {
+            SubdiagnosticKind::Suggestion { code: ref mut code_field, .. } => {
+                *code_field = if let Some((code, _)) = code {
+                    code
+                } else {
+                    span_err(span, "suggestion without `code = \"...\"`").emit();
+                    quote! { "" }
+                }
+            }
+            SubdiagnosticKind::Label
+            | SubdiagnosticKind::Note
+            | SubdiagnosticKind::Help
+            | SubdiagnosticKind::Warn
+            | SubdiagnosticKind::MultipartSuggestion { .. } => {}
+        }
+
+        Ok((kind, slug))
+    }
+}
+
+impl quote::IdentFragment for SubdiagnosticKind {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            SubdiagnosticKind::Label => write!(f, "label"),
+            SubdiagnosticKind::Note => write!(f, "note"),
+            SubdiagnosticKind::Help => write!(f, "help"),
+            SubdiagnosticKind::Warn => write!(f, "warn"),
+            SubdiagnosticKind::Suggestion { .. } => write!(f, "suggestion_with_style"),
+            SubdiagnosticKind::MultipartSuggestion { .. } => {
+                write!(f, "multipart_suggestion_with_style")
+            }
+        }
+    }
+
+    fn span(&self) -> Option<proc_macro2::Span> {
+        None
+    }
+}
+
+/// Wrapper around `synstructure::BindStyle` which implements `Ord`.
+#[derive(PartialEq, Eq)]
+pub(super) struct OrderedBindStyle(pub(super) BindStyle);
+
+impl OrderedBindStyle {
+    /// Is `BindStyle::Move` or `BindStyle::MoveMut`?
+    pub(super) fn is_move(&self) -> bool {
+        matches!(self.0, BindStyle::Move | BindStyle::MoveMut)
+    }
+}
+
+impl Ord for OrderedBindStyle {
+    fn cmp(&self, other: &Self) -> Ordering {
+        match (self.is_move(), other.is_move()) {
+            // If both `self` and `other` are the same, then ordering is equal.
+            (true, true) | (false, false) => Ordering::Equal,
+            // If `self` is not a move then it should be considered less than `other` (so that
+            // references are sorted first).
+            (false, _) => Ordering::Less,
+            // If `self` is a move then it must be greater than `other` (again, so that references
+            // are sorted first).
+            (true, _) => Ordering::Greater,
+        }
+    }
+}
+
+impl PartialOrd for OrderedBindStyle {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+/// Returns `true` if `field` should generate a `set_arg` call rather than any other diagnostic
+/// call (like `span_label`).
+pub(super) fn should_generate_set_arg(field: &Field) -> bool {
+    field.attrs.is_empty()
+}
+
+/// Returns `true` if `field` needs to have code generated in the by-move branch of the
+/// generated derive rather than the by-ref branch.
+pub(super) fn bind_style_of_field(field: &Field) -> OrderedBindStyle {
+    let generates_set_arg = should_generate_set_arg(field);
+    let is_multispan = type_matches_path(&field.ty, &["rustc_errors", "MultiSpan"]);
+    // FIXME(davidtwco): better support for one field needing to be in the by-move and
+    // by-ref branches.
+    let is_subdiagnostic = field
+        .attrs
+        .iter()
+        .map(|attr| attr.path.segments.last().unwrap().ident.to_string())
+        .any(|attr| attr == "subdiagnostic");
+
+    // `set_arg` calls take their argument by-move..
+    let needs_move = generates_set_arg
+        // If this is a `MultiSpan` field then it needs to be moved to be used by any
+        // attribute..
+        || is_multispan
+        // If this a `#[subdiagnostic]` then it needs to be moved as the other diagnostic is
+        // unlikely to be `Copy`..
+        || is_subdiagnostic;
+
+    OrderedBindStyle(if needs_move { BindStyle::Move } else { BindStyle::Ref })
 }
diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs
index 8fd23ee5ced..36bda3e0f6b 100644
--- a/compiler/rustc_macros/src/lib.rs
+++ b/compiler/rustc_macros/src/lib.rs
@@ -1,5 +1,4 @@
 #![feature(allow_internal_unstable)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(never_type)]
 #![feature(proc_macro_diagnostic)]
 #![feature(proc_macro_span)]
diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs
index 6f5604b7e11..98cf6fef54a 100644
--- a/compiler/rustc_metadata/src/lib.rs
+++ b/compiler/rustc_metadata/src/lib.rs
@@ -2,10 +2,8 @@
 #![feature(decl_macro)]
 #![feature(drain_filter)]
 #![feature(generators)]
-#![cfg_attr(bootstrap, feature(generic_associated_types))]
 #![feature(iter_from_generator)]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(once_cell)]
 #![feature(proc_macro_internals)]
 #![feature(macro_metavar_expr)]
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 2a986c41d72..9abb5c74895 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -382,7 +382,7 @@ impl<'tcx> Collector<'tcx> {
                             let link_ordinal_attr = self
                                 .tcx
                                 .hir()
-                                .attrs(self.tcx.hir().local_def_id_to_hir_id(child_item.id.def_id))
+                                .attrs(child_item.id.def_id.into())
                                 .iter()
                                 .find(|a| a.has_name(sym::link_ordinal))
                                 .unwrap();
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index dede1b2122a..466da175810 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -223,6 +223,15 @@ provide! { tcx, def_id, other, cdata,
     fn_arg_names => { table }
     generator_kind => { table }
     trait_def => { table }
+    collect_trait_impl_trait_tys => {
+        Ok(cdata
+            .root
+            .tables
+            .trait_impl_trait_tys
+            .get(cdata, def_id.index)
+            .map(|lazy| lazy.decode((cdata, tcx)))
+            .process_decoded(tcx, || panic!("{:?} does not have trait_impl_trait_tys", def_id)))
+     }
 
     visibility => { cdata.get_visibility(def_id.index) }
     adt_def => { cdata.get_adt_def(def_id.index, tcx) }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 67c28461ce5..1a7a3c65c3b 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1059,6 +1059,34 @@ fn should_encode_const(def_kind: DefKind) -> bool {
     }
 }
 
+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;
+    }
+
+    let Some(item) = tcx.opt_associated_item(def_id) else { return false; };
+    if item.container != ty::AssocItemContainer::ImplContainer {
+        return false;
+    }
+
+    let Some(trait_item_def_id) = item.trait_item_def_id else { return false; };
+
+    // FIXME(RPITIT): This does a somewhat manual walk through the signature
+    // of the trait fn to look for any RPITITs, but that's kinda doing a lot
+    // of work. We can probably remove this when we refactor RPITITs to be
+    // associated types.
+    tcx.fn_sig(trait_item_def_id).skip_binder().output().walk().any(|arg| {
+        if let ty::GenericArgKind::Type(ty) = arg.unpack()
+            && let ty::Projection(data) = ty.kind()
+            && tcx.def_kind(data.item_def_id) == DefKind::ImplTraitPlaceholder
+        {
+            true
+        } else {
+            false
+        }
+    })
+}
+
 impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     fn encode_attrs(&mut self, def_id: LocalDefId) {
         let mut attrs = self
@@ -1128,6 +1156,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             if let DefKind::Trait | DefKind::TraitAlias = def_kind {
                 record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id));
             }
+            if should_encode_trait_impl_trait_tys(tcx, def_id)
+                && let Ok(table) = self.tcx.collect_trait_impl_trait_tys(def_id)
+            {
+                record!(self.tables.trait_impl_trait_tys[def_id] <- table);
+            }
         }
         let inherent_impls = tcx.crate_inherent_impls(());
         for (def_id, implementations) in inherent_impls.inherent_impls.iter() {
@@ -1217,14 +1250,14 @@ 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.local_def_index;
+                                yield foreign_item.id.def_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.local_def_index;
+                            yield item_id.def_id.def_id.local_def_index;
                         }
                         _ => continue,
                     }
@@ -1446,7 +1479,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, m);
+                return self.encode_info_for_mod(item.def_id.def_id, m);
             }
             hir::ItemKind::OpaqueTy(..) => {
                 self.encode_explicit_item_bounds(def_id);
@@ -1840,7 +1873,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         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.to_def_id()) {
+                if let Some(trait_ref) = tcx.impl_trait_ref(id.def_id) {
                     let simplified_self_ty = fast_reject::simplify_type(
                         self.tcx,
                         trait_ref.self_ty(),
@@ -1850,7 +1883,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                     fx_hash_map
                         .entry(trait_ref.def_id)
                         .or_default()
-                        .push((id.def_id.local_def_index, simplified_self_ty));
+                        .push((id.def_id.def_id.local_def_index, simplified_self_ty));
                 }
             }
         }
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 748b3afec37..6d7345570af 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -1,6 +1,7 @@
 use crate::creader::CrateMetadataRef;
 use decoder::Metadata;
 use def_path_hash_map::DefPathHashMapRef;
+use rustc_data_structures::fx::FxHashMap;
 use table::TableBuilder;
 
 use rustc_ast as ast;
@@ -399,6 +400,8 @@ define_tables! {
     macro_definition: Table<DefIndex, LazyValue<ast::MacArgs>>,
     proc_macro: Table<DefIndex, MacroKind>,
     module_reexports: Table<DefIndex, LazyArray<ModChild>>,
+
+    trait_impl_trait_tys: Table<DefIndex, LazyValue<FxHashMap<DefId, Ty<'static>>>>,
 }
 
 #[derive(TyEncodable, TyDecodable)]
diff --git a/compiler/rustc_middle/benches/lib.rs b/compiler/rustc_middle/benches/lib.rs
deleted file mode 100644
index 237751bcbd7..00000000000
--- a/compiler/rustc_middle/benches/lib.rs
+++ /dev/null
@@ -1,54 +0,0 @@
-#![feature(test)]
-
-extern crate test;
-
-use test::Bencher;
-
-// Static/dynamic method dispatch
-
-struct Struct {
-    field: isize,
-}
-
-trait Trait {
-    fn method(&self) -> isize;
-}
-
-impl Trait for Struct {
-    fn method(&self) -> isize {
-        self.field
-    }
-}
-
-#[bench]
-fn trait_vtable_method_call(b: &mut Bencher) {
-    let s = Struct { field: 10 };
-    let t = &s as &dyn Trait;
-    b.iter(|| t.method());
-}
-
-#[bench]
-fn trait_static_method_call(b: &mut Bencher) {
-    let s = Struct { field: 10 };
-    b.iter(|| s.method());
-}
-
-// Overhead of various match forms
-
-#[bench]
-fn option_some(b: &mut Bencher) {
-    let x = Some(10);
-    b.iter(|| match x {
-        Some(y) => y,
-        None => 11,
-    });
-}
-
-#[bench]
-fn vec_pattern(b: &mut Bencher) {
-    let x = [1, 2, 3, 4, 5, 6];
-    b.iter(|| match x {
-        [1, 2, 3, ..] => 10,
-        _ => 11,
-    });
-}
diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs
index 1fa0c6babab..40b9d73db94 100644
--- a/compiler/rustc_middle/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs
@@ -62,86 +62,13 @@ use crate::ty::TyCtxt;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
 use rustc_hir::definitions::DefPathHash;
-use rustc_hir::HirId;
+use rustc_hir::{HirId, OwnerId};
 use rustc_query_system::dep_graph::FingerprintStyle;
 use rustc_span::symbol::Symbol;
 use std::hash::Hash;
 
 pub use rustc_query_system::dep_graph::{DepContext, DepNodeParams};
 
-/// This struct stores metadata about each DepKind.
-///
-/// Information is retrieved by indexing the `DEP_KINDS` array using the integer value
-/// of the `DepKind`. Overall, this allows to implement `DepContext` using this manual
-/// jump table instead of large matches.
-pub struct DepKindStruct<'tcx> {
-    /// Anonymous queries cannot be replayed from one compiler invocation to the next.
-    /// When their result is needed, it is recomputed. They are useful for fine-grained
-    /// dependency tracking, and caching within one compiler invocation.
-    pub is_anon: bool,
-
-    /// Eval-always queries do not track their dependencies, and are always recomputed, even if
-    /// their inputs have not changed since the last compiler invocation. The result is still
-    /// cached within one compiler invocation.
-    pub is_eval_always: bool,
-
-    /// Whether the query key can be recovered from the hashed fingerprint.
-    /// See [DepNodeParams] trait for the behaviour of each key type.
-    pub fingerprint_style: FingerprintStyle,
-
-    /// The red/green evaluation system will try to mark a specific DepNode in the
-    /// dependency graph as green by recursively trying to mark the dependencies of
-    /// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode`
-    /// where we don't know if it is red or green and we therefore actually have
-    /// to recompute its value in order to find out. Since the only piece of
-    /// information that we have at that point is the `DepNode` we are trying to
-    /// re-evaluate, we need some way to re-run a query from just that. This is what
-    /// `force_from_dep_node()` implements.
-    ///
-    /// In the general case, a `DepNode` consists of a `DepKind` and an opaque
-    /// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint
-    /// is usually constructed by computing a stable hash of the query-key that the
-    /// `DepNode` corresponds to. Consequently, it is not in general possible to go
-    /// back from hash to query-key (since hash functions are not reversible). For
-    /// this reason `force_from_dep_node()` is expected to fail from time to time
-    /// because we just cannot find out, from the `DepNode` alone, what the
-    /// corresponding query-key is and therefore cannot re-run the query.
-    ///
-    /// The system deals with this case letting `try_mark_green` fail which forces
-    /// the root query to be re-evaluated.
-    ///
-    /// Now, if `force_from_dep_node()` would always fail, it would be pretty useless.
-    /// Fortunately, we can use some contextual information that will allow us to
-    /// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we
-    /// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a
-    /// valid `DefPathHash`. Since we also always build a huge table that maps every
-    /// `DefPathHash` in the current codebase to the corresponding `DefId`, we have
-    /// everything we need to re-run the query.
-    ///
-    /// Take the `mir_promoted` query as an example. Like many other queries, it
-    /// just has a single parameter: the `DefId` of the item it will compute the
-    /// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode`
-    /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode`
-    /// is actually a `DefPathHash`, and can therefore just look up the corresponding
-    /// `DefId` in `tcx.def_path_hash_to_def_id`.
-    pub force_from_dep_node: Option<fn(tcx: TyCtxt<'tcx>, dep_node: DepNode) -> bool>,
-
-    /// Invoke a query to put the on-disk cached value in memory.
-    pub try_load_from_on_disk_cache: Option<fn(TyCtxt<'tcx>, DepNode)>,
-}
-
-impl DepKind {
-    #[inline(always)]
-    pub fn fingerprint_style(self, tcx: TyCtxt<'_>) -> FingerprintStyle {
-        // Only fetch the DepKindStruct once.
-        let data = tcx.query_kind(self);
-        if data.is_anon {
-            return FingerprintStyle::Opaque;
-        }
-        data.fingerprint_style
-    }
-}
-
 macro_rules! define_dep_nodes {
     (
      $($(#[$attr:meta])*
@@ -159,7 +86,7 @@ macro_rules! define_dep_nodes {
             $( $( #[$attr] )* $variant),*
         }
 
-        fn dep_kind_from_label_string(label: &str) -> Result<DepKind, ()> {
+        pub(super) fn dep_kind_from_label_string(label: &str) -> Result<DepKind, ()> {
             match label {
                 $(stringify!($variant) => Ok(DepKind::$variant),)*
                 _ => Err(()),
@@ -214,11 +141,6 @@ static_assert_size!(DepNode, 18);
 static_assert_size!(DepNode, 24);
 
 pub trait DepNodeExt: Sized {
-    /// Construct a DepNode from the given DepKind and DefPathHash. This
-    /// method will assert that the given DepKind actually requires a
-    /// single DefId/DefPathHash parameter.
-    fn from_def_path_hash(tcx: TyCtxt<'_>, def_path_hash: DefPathHash, kind: DepKind) -> Self;
-
     /// Extracts the DefId corresponding to this DepNode. This will work
     /// if two conditions are met:
     ///
@@ -243,14 +165,6 @@ pub trait DepNodeExt: Sized {
 }
 
 impl DepNodeExt for DepNode {
-    /// Construct a DepNode from the given DepKind and DefPathHash. This
-    /// method will assert that the given DepKind actually requires a
-    /// single DefId/DefPathHash parameter.
-    fn from_def_path_hash(tcx: TyCtxt<'_>, def_path_hash: DefPathHash, kind: DepKind) -> DepNode {
-        debug_assert!(kind.fingerprint_style(tcx) == FingerprintStyle::DefPathHash);
-        DepNode { kind, hash: def_path_hash.0.into() }
-    }
-
     /// Extracts the DefId corresponding to this DepNode. This will work
     /// if two conditions are met:
     ///
@@ -262,7 +176,7 @@ impl DepNodeExt for DepNode {
     /// refers to something from the previous compilation session that
     /// has been removed.
     fn extract_def_id<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> {
-        if self.kind.fingerprint_style(tcx) == FingerprintStyle::DefPathHash {
+        if tcx.fingerprint_style(self.kind) == FingerprintStyle::DefPathHash {
             Some(tcx.def_path_hash_to_def_id(DefPathHash(self.hash.into()), &mut || {
                 panic!("Failed to extract DefId: {:?} {}", self.kind, self.hash)
             }))
@@ -279,7 +193,7 @@ impl DepNodeExt for DepNode {
     ) -> Result<DepNode, ()> {
         let kind = dep_kind_from_label_string(label)?;
 
-        match kind.fingerprint_style(tcx) {
+        match tcx.fingerprint_style(kind) {
             FingerprintStyle::Opaque => Err(()),
             FingerprintStyle::Unit => Ok(DepNode::new_no_params(tcx, kind)),
             FingerprintStyle::DefPathHash => {
@@ -355,6 +269,28 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for LocalDefId {
     }
 }
 
+impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for OwnerId {
+    #[inline(always)]
+    fn fingerprint_style() -> FingerprintStyle {
+        FingerprintStyle::DefPathHash
+    }
+
+    #[inline(always)]
+    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
+        self.to_def_id().to_fingerprint(tcx)
+    }
+
+    #[inline(always)]
+    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
+        self.to_def_id().to_debug_str(tcx)
+    }
+
+    #[inline(always)]
+    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
+        dep_node.extract_def_id(tcx).map(|id| OwnerId { def_id: id.expect_local() })
+    }
+}
+
 impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for CrateNum {
     #[inline(always)]
     fn fingerprint_style() -> FingerprintStyle {
diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs
index c8b3b52b0fb..2e62bebc852 100644
--- a/compiler/rustc_middle/src/dep_graph/mod.rs
+++ b/compiler/rustc_middle/src/dep_graph/mod.rs
@@ -11,15 +11,17 @@ pub use rustc_query_system::dep_graph::{
     SerializedDepNodeIndex, WorkProduct, WorkProductId,
 };
 
-pub use dep_node::{label_strs, DepKind, DepKindStruct, DepNode, DepNodeExt};
+pub use dep_node::{label_strs, DepKind, DepNode, DepNodeExt};
 pub(crate) use dep_node::{make_compile_codegen_unit, make_compile_mono_item};
 
 pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepKind>;
+
 pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps<DepKind>;
 pub type TaskDepsRef<'a> = rustc_query_system::dep_graph::TaskDepsRef<'a, DepKind>;
 pub type DepGraphQuery = rustc_query_system::dep_graph::DepGraphQuery<DepKind>;
 pub type SerializedDepGraph = rustc_query_system::dep_graph::SerializedDepGraph<DepKind>;
 pub type EdgeFilter = rustc_query_system::dep_graph::debug::EdgeFilter<DepKind>;
+pub type DepKindStruct<'tcx> = rustc_query_system::dep_graph::DepKindStruct<TyCtxt<'tcx>>;
 
 impl rustc_query_system::dep_graph::DepKind for DepKind {
     const NULL: Self = DepKind::Null;
@@ -91,50 +93,8 @@ impl<'tcx> DepContext for TyCtxt<'tcx> {
         self.sess
     }
 
-    #[inline(always)]
-    fn fingerprint_style(&self, kind: DepKind) -> rustc_query_system::dep_graph::FingerprintStyle {
-        kind.fingerprint_style(*self)
-    }
-
-    #[inline(always)]
-    fn is_eval_always(&self, kind: DepKind) -> bool {
-        self.query_kind(kind).is_eval_always
-    }
-
-    fn try_force_from_dep_node(&self, dep_node: DepNode) -> bool {
-        debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node);
-
-        // We must avoid ever having to call `force_from_dep_node()` for a
-        // `DepNode::codegen_unit`:
-        // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we
-        // would always end up having to evaluate the first caller of the
-        // `codegen_unit` query that *is* reconstructible. This might very well be
-        // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just
-        // to re-trigger calling the `codegen_unit` query with the right key. At
-        // that point we would already have re-done all the work we are trying to
-        // avoid doing in the first place.
-        // The solution is simple: Just explicitly call the `codegen_unit` query for
-        // each CGU, right after partitioning. This way `try_mark_green` will always
-        // hit the cache instead of having to go through `force_from_dep_node`.
-        // This assertion makes sure, we actually keep applying the solution above.
-        debug_assert!(
-            dep_node.kind != DepKind::codegen_unit,
-            "calling force_from_dep_node() on DepKind::codegen_unit"
-        );
-
-        let cb = self.query_kind(dep_node.kind);
-        if let Some(f) = cb.force_from_dep_node {
-            f(*self, dep_node);
-            true
-        } else {
-            false
-        }
-    }
-
-    fn try_load_from_on_disk_cache(&self, dep_node: DepNode) {
-        let cb = self.query_kind(dep_node.kind);
-        if let Some(f) = cb.try_load_from_on_disk_cache {
-            f(*self, dep_node)
-        }
+    #[inline]
+    fn dep_kind_info(&self, dep_kind: DepKind) -> &DepKindStruct<'tcx> {
+        &self.query_kinds[dep_kind as usize]
     }
 }
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 30a23c342b3..b5f7b26ea7a 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -93,7 +93,7 @@ pub struct ParentOwnerIterator<'hir> {
 }
 
 impl<'hir> Iterator for ParentOwnerIterator<'hir> {
-    type Item = (LocalDefId, OwnerNode<'hir>);
+    type Item = (OwnerId, OwnerNode<'hir>);
 
     fn next(&mut self) -> Option<Self::Item> {
         if self.current_id.local_id.index() != 0 {
@@ -107,13 +107,13 @@ impl<'hir> Iterator for ParentOwnerIterator<'hir> {
         }
         loop {
             // There are nodes that do not have entries, so we need to skip them.
-            let parent_id = self.map.def_key(self.current_id.owner).parent;
+            let parent_id = self.map.def_key(self.current_id.owner.def_id).parent;
 
-            let parent_id = parent_id.map_or(CRATE_HIR_ID.owner, |local_def_index| {
+            let parent_id = parent_id.map_or(CRATE_OWNER_ID, |local_def_index| {
                 let def_id = LocalDefId { local_def_index };
                 self.map.local_def_id_to_hir_id(def_id).owner
             });
-            self.current_id = HirId::make_owner(parent_id);
+            self.current_id = HirId::make_owner(parent_id.def_id);
 
             // If this `HirId` doesn't have an entry, skip it and look for its `parent_id`.
             if let Some(node) = self.map.tcx.hir_owner(self.current_id.owner) {
@@ -131,7 +131,7 @@ impl<'hir> Map<'hir> {
 
     #[inline]
     pub fn root_module(self) -> &'hir Mod<'hir> {
-        match self.tcx.hir_owner(CRATE_DEF_ID).map(|o| o.node) {
+        match self.tcx.hir_owner(CRATE_OWNER_ID).map(|o| o.node) {
             Some(OwnerNode::Crate(item)) => item,
             _ => bug!(),
         }
@@ -186,7 +186,7 @@ impl<'hir> Map<'hir> {
     #[inline]
     pub fn opt_local_def_id(self, hir_id: HirId) -> Option<LocalDefId> {
         if hir_id.local_id == ItemLocalId::new(0) {
-            Some(hir_id.owner)
+            Some(hir_id.owner.def_id)
         } else {
             self.tcx
                 .hir_owner_nodes(hir_id.owner)
@@ -352,7 +352,7 @@ impl<'hir> Map<'hir> {
     }
 
     pub fn get_generics(self, id: LocalDefId) -> Option<&'hir Generics<'hir>> {
-        let node = self.tcx.hir_owner(id)?;
+        let node = self.tcx.hir_owner(OwnerId { def_id: id })?;
         node.node.generics()
     }
 
@@ -532,7 +532,7 @@ impl<'hir> Map<'hir> {
 
     pub fn get_module(self, module: LocalDefId) -> (&'hir Mod<'hir>, Span, HirId) {
         let hir_id = HirId::make_owner(module);
-        match self.tcx.hir_owner(module).map(|o| o.node) {
+        match self.tcx.hir_owner(hir_id.owner).map(|o| o.node) {
             Some(OwnerNode::Item(&Item { span, kind: ItemKind::Mod(ref m), .. })) => {
                 (m, span, hir_id)
             }
@@ -622,14 +622,14 @@ impl<'hir> Map<'hir> {
     pub fn for_each_module(self, mut f: impl FnMut(LocalDefId)) {
         let crate_items = self.tcx.hir_crate_items(());
         for module in crate_items.submodules.iter() {
-            f(*module)
+            f(module.def_id)
         }
     }
 
     #[inline]
     pub fn par_for_each_module(self, f: impl Fn(LocalDefId) + Sync + Send) {
         let crate_items = self.tcx.hir_crate_items(());
-        par_for_each_in(&crate_items.submodules[..], |module| f(*module))
+        par_for_each_in(&crate_items.submodules[..], |module| f(module.def_id))
     }
 
     /// Returns an iterator for the nodes in the ancestor tree of the `current_id`
@@ -721,27 +721,27 @@ impl<'hir> Map<'hir> {
         None
     }
 
-    /// Retrieves the `HirId` for `id`'s parent item, or `id` itself if no
+    /// Retrieves the `OwnerId` for `id`'s parent item, or `id` itself if no
     /// parent item is in this map. The "parent item" is the closest parent node
     /// in the HIR which is recorded by the map and is an item, either an item
     /// in a module, trait, or impl.
-    pub fn get_parent_item(self, hir_id: HirId) -> LocalDefId {
+    pub fn get_parent_item(self, hir_id: HirId) -> OwnerId {
         if let Some((def_id, _node)) = self.parent_owner_iter(hir_id).next() {
             def_id
         } else {
-            CRATE_DEF_ID
+            CRATE_OWNER_ID
         }
     }
 
-    /// Returns the `HirId` of `id`'s nearest module parent, or `id` itself if no
+    /// Returns the `OwnerId` of `id`'s nearest module parent, or `id` itself if no
     /// module parent is in this map.
-    pub(super) fn get_module_parent_node(self, hir_id: HirId) -> LocalDefId {
+    pub(super) fn get_module_parent_node(self, hir_id: HirId) -> OwnerId {
         for (def_id, node) in self.parent_owner_iter(hir_id) {
             if let OwnerNode::Item(&Item { kind: ItemKind::Mod(_), .. }) = node {
                 return def_id;
             }
         }
-        CRATE_DEF_ID
+        CRATE_OWNER_ID
     }
 
     /// When on an if expression, a match arm tail expression or a match arm, give back
@@ -814,30 +814,30 @@ impl<'hir> Map<'hir> {
         }
         bug!(
             "expected foreign mod or inlined parent, found {}",
-            self.node_to_string(HirId::make_owner(parent))
+            self.node_to_string(HirId::make_owner(parent.def_id))
         )
     }
 
-    pub fn expect_owner(self, id: LocalDefId) -> OwnerNode<'hir> {
+    pub fn expect_owner(self, id: OwnerId) -> OwnerNode<'hir> {
         self.tcx.hir_owner(id).unwrap_or_else(|| bug!("expected owner for {:?}", id)).node
     }
 
     pub fn expect_item(self, id: LocalDefId) -> &'hir Item<'hir> {
-        match self.tcx.hir_owner(id) {
+        match self.tcx.hir_owner(OwnerId { def_id: id }) {
             Some(Owner { node: OwnerNode::Item(item), .. }) => item,
             _ => bug!("expected item, found {}", self.node_to_string(HirId::make_owner(id))),
         }
     }
 
     pub fn expect_impl_item(self, id: LocalDefId) -> &'hir ImplItem<'hir> {
-        match self.tcx.hir_owner(id) {
+        match self.tcx.hir_owner(OwnerId { def_id: id }) {
             Some(Owner { node: OwnerNode::ImplItem(item), .. }) => item,
             _ => bug!("expected impl item, found {}", self.node_to_string(HirId::make_owner(id))),
         }
     }
 
     pub fn expect_trait_item(self, id: LocalDefId) -> &'hir TraitItem<'hir> {
-        match self.tcx.hir_owner(id) {
+        match self.tcx.hir_owner(OwnerId { def_id: id }) {
             Some(Owner { node: OwnerNode::TraitItem(item), .. }) => item,
             _ => bug!("expected trait item, found {}", self.node_to_string(HirId::make_owner(id))),
         }
@@ -850,11 +850,14 @@ impl<'hir> Map<'hir> {
         }
     }
 
-    pub fn expect_foreign_item(self, id: LocalDefId) -> &'hir ForeignItem<'hir> {
+    pub fn expect_foreign_item(self, id: OwnerId) -> &'hir ForeignItem<'hir> {
         match self.tcx.hir_owner(id) {
             Some(Owner { node: OwnerNode::ForeignItem(item), .. }) => item,
             _ => {
-                bug!("expected foreign item, found {}", self.node_to_string(HirId::make_owner(id)))
+                bug!(
+                    "expected foreign item, found {}",
+                    self.node_to_string(HirId::make_owner(id.def_id))
+                )
             }
         }
     }
@@ -1290,7 +1293,7 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems {
     // A "crate collector" and "module collector" start at a
     // module item (the former starts at the crate root) but only
     // the former needs to collect it. ItemCollector does not do this for us.
-    collector.submodules.push(CRATE_DEF_ID);
+    collector.submodules.push(CRATE_OWNER_ID);
     tcx.hir().walk_toplevel_module(&mut collector);
 
     let ItemCollector {
@@ -1318,7 +1321,7 @@ struct ItemCollector<'tcx> {
     // otherwise it collects items in some module.
     crate_collector: bool,
     tcx: TyCtxt<'tcx>,
-    submodules: Vec<LocalDefId>,
+    submodules: Vec<OwnerId>,
     items: Vec<ItemId>,
     trait_items: Vec<TraitItemId>,
     impl_items: Vec<ImplItemId>,
@@ -1350,7 +1353,7 @@ 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);
+            self.body_owners.push(item.def_id.def_id);
         }
 
         self.items.push(item.item_id());
@@ -1386,7 +1389,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);
+            self.body_owners.push(item.def_id.def_id);
         }
 
         self.trait_items.push(item.trait_item_id());
@@ -1395,7 +1398,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);
+            self.body_owners.push(item.def_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 211a614717f..1ce98a03c8a 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -39,7 +39,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Owner<'tcx> {
 /// bodies.  The Ids are in visitor order.  This is used to partition a pass between modules.
 #[derive(Debug, HashStable, Encodable, Decodable)]
 pub struct ModuleItems {
-    submodules: Box<[LocalDefId]>,
+    submodules: Box<[OwnerId]>,
     items: Box<[ItemId]>,
     trait_items: Box<[TraitItemId]>,
     impl_items: Box<[ImplItemId]>,
@@ -67,10 +67,10 @@ impl ModuleItems {
     pub fn definitions(&self) -> impl Iterator<Item = LocalDefId> + '_ {
         self.items
             .iter()
-            .map(|id| id.def_id)
-            .chain(self.trait_items.iter().map(|id| id.def_id))
-            .chain(self.impl_items.iter().map(|id| id.def_id))
-            .chain(self.foreign_items.iter().map(|id| id.def_id))
+            .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))
     }
 
     pub fn par_items(&self, f: impl Fn(ItemId) + Send + Sync) {
@@ -97,7 +97,7 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     pub fn parent_module(self, id: HirId) -> LocalDefId {
-        self.parent_module_from_def_id(id.owner)
+        self.parent_module_from_def_id(id.owner.def_id)
     }
 
     pub fn impl_subject(self, def_id: DefId) -> ImplSubject<'tcx> {
@@ -110,13 +110,13 @@ impl<'tcx> TyCtxt<'tcx> {
 pub fn provide(providers: &mut Providers) {
     providers.parent_module_from_def_id = |tcx, id| {
         let hir = tcx.hir();
-        hir.get_module_parent_node(hir.local_def_id_to_hir_id(id))
+        hir.get_module_parent_node(hir.local_def_id_to_hir_id(id)).def_id
     };
     providers.hir_crate_items = map::hir_crate_items;
     providers.crate_hash = map::crate_hash;
     providers.hir_module_items = map::hir_module_items;
     providers.hir_owner = |tcx, id| {
-        let owner = tcx.hir_crate(()).owners.get(id)?.as_owner()?;
+        let owner = tcx.hir_crate(()).owners.get(id.def_id)?.as_owner()?;
         let node = owner.node();
         Some(Owner { node, hash_without_bodies: owner.nodes.hash_without_bodies })
     };
@@ -128,21 +128,24 @@ pub fn provide(providers: &mut Providers) {
             MaybeOwner::NonOwner(hir_id) => hir_id,
         }
     };
-    providers.hir_owner_nodes = |tcx, id| tcx.hir_crate(()).owners[id].map(|i| &i.nodes);
+    providers.hir_owner_nodes = |tcx, id| tcx.hir_crate(()).owners[id.def_id].map(|i| &i.nodes);
     providers.hir_owner_parent = |tcx, id| {
         // Accessing the local_parent is ok since its value is hashed as part of `id`'s DefPathHash.
-        tcx.opt_local_parent(id).map_or(CRATE_HIR_ID, |parent| {
+        tcx.opt_local_parent(id.def_id).map_or(CRATE_HIR_ID, |parent| {
             let mut parent_hir_id = tcx.hir().local_def_id_to_hir_id(parent);
-            if let Some(local_id) =
-                tcx.hir_crate(()).owners[parent_hir_id.owner].unwrap().parenting.get(&id)
+            if let Some(local_id) = tcx.hir_crate(()).owners[parent_hir_id.owner.def_id]
+                .unwrap()
+                .parenting
+                .get(&id.def_id)
             {
                 parent_hir_id.local_id = *local_id;
             }
             parent_hir_id
         })
     };
-    providers.hir_attrs =
-        |tcx, id| tcx.hir_crate(()).owners[id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs);
+    providers.hir_attrs = |tcx, id| {
+        tcx.hir_crate(()).owners[id.def_id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs)
+    };
     providers.source_span =
         |tcx, def_id| tcx.resolutions(()).source_span.get(def_id).copied().unwrap_or(DUMMY_SP);
     providers.def_span = |tcx, def_id| {
@@ -177,6 +180,7 @@ pub fn provide(providers: &mut Providers) {
         let id = id.expect_local();
         tcx.resolutions(()).expn_that_defined.get(&id).copied().unwrap_or(ExpnId::root())
     };
-    providers.in_scope_traits_map =
-        |tcx, id| tcx.hir_crate(()).owners[id].as_owner().map(|owner_info| &owner_info.trait_map);
+    providers.in_scope_traits_map = |tcx, id| {
+        tcx.hir_crate(()).owners[id.def_id].as_owner().map(|owner_info| &owner_info.trait_map)
+    };
 }
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 01b9277b983..a180706e1cf 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -31,7 +31,6 @@
 #![feature(discriminant_kind)]
 #![feature(exhaustive_patterns)]
 #![feature(get_mut_unchecked)]
-#![cfg_attr(bootstrap, feature(generic_associated_types))]
 #![feature(if_let_guard)]
 #![feature(map_first_last)]
 #![feature(negative_impls)]
@@ -40,7 +39,6 @@
 #![feature(new_uninit)]
 #![feature(once_cell)]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(min_specialization)]
 #![feature(trusted_len)]
 #![feature(type_alias_impl_trait)]
diff --git a/compiler/rustc_middle/src/middle/resolve_lifetime.rs b/compiler/rustc_middle/src/middle/resolve_lifetime.rs
index 2a1a0bbe2ae..c3bf1c717d9 100644
--- a/compiler/rustc_middle/src/middle/resolve_lifetime.rs
+++ b/compiler/rustc_middle/src/middle/resolve_lifetime.rs
@@ -3,8 +3,8 @@
 use crate::ty;
 
 use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::ItemLocalId;
+use rustc_hir::def_id::DefId;
+use rustc_hir::{ItemLocalId, OwnerId};
 use rustc_macros::HashStable;
 
 #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)]
@@ -49,7 +49,7 @@ pub enum ObjectLifetimeDefault {
 pub struct ResolveLifetimes {
     /// Maps from every use of a named (not anonymous) lifetime to a
     /// `Region` describing how that region is bound
-    pub defs: FxHashMap<LocalDefId, FxHashMap<ItemLocalId, Region>>,
+    pub defs: FxHashMap<OwnerId, FxHashMap<ItemLocalId, Region>>,
 
-    pub late_bound_vars: FxHashMap<LocalDefId, FxHashMap<ItemLocalId, Vec<ty::BoundVariableKind>>>,
+    pub late_bound_vars: FxHashMap<OwnerId, FxHashMap<ItemLocalId, Vec<ty::BoundVariableKind>>>,
 }
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 21ae121e1ce..fdda62719ee 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -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),
+            MonoItem::GlobalAsm(item_id) => Some(item_id.def_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.index()),
+                    MonoItem::GlobalAsm(item_id) => Some(item_id.def_id.def_id.index()),
                 },
                 item.symbol_name(tcx),
             )
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 568d63fb062..ee8377d1987 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -1242,7 +1242,6 @@ pub enum BinOp {
 mod size_asserts {
     use super::*;
     // These are in alphabetical order, which is easy to maintain.
-    #[cfg(not(bootstrap))]
     static_assert_size!(AggregateKind<'_>, 40);
     static_assert_size!(Operand<'_>, 24);
     static_assert_size!(Place<'_>, 16);
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 121a5b9f492..fb867f8b46b 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -73,7 +73,7 @@ rustc_queries! {
     ///
     /// This can be conveniently accessed by methods on `tcx.hir()`.
     /// Avoid calling this query directly.
-    query hir_owner(key: LocalDefId) -> Option<crate::hir::Owner<'tcx>> {
+    query hir_owner(key: hir::OwnerId) -> Option<crate::hir::Owner<'tcx>> {
         desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) }
     }
 
@@ -89,7 +89,7 @@ rustc_queries! {
     ///
     /// This can be conveniently accessed by methods on `tcx.hir()`.
     /// Avoid calling this query directly.
-    query hir_owner_parent(key: LocalDefId) -> hir::HirId {
+    query hir_owner_parent(key: hir::OwnerId) -> hir::HirId {
         desc { |tcx| "HIR parent of `{}`", tcx.def_path_str(key.to_def_id()) }
     }
 
@@ -97,7 +97,7 @@ rustc_queries! {
     ///
     /// This can be conveniently accessed by methods on `tcx.hir()`.
     /// Avoid calling this query directly.
-    query hir_owner_nodes(key: LocalDefId) -> hir::MaybeOwner<&'tcx hir::OwnerNodes<'tcx>> {
+    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()) }
     }
 
@@ -105,7 +105,7 @@ rustc_queries! {
     ///
     /// This can be conveniently accessed by methods on `tcx.hir()`.
     /// Avoid calling this query directly.
-    query hir_attrs(key: LocalDefId) -> &'tcx hir::AttributeMap<'tcx> {
+    query hir_attrs(key: hir::OwnerId) -> &'tcx hir::AttributeMap<'tcx> {
         desc { |tcx| "HIR owner attributes in `{}`", tcx.def_path_str(key.to_def_id()) }
     }
 
@@ -1126,6 +1126,11 @@ rustc_queries! {
         desc { |tcx| "checking whether `{}` is `doc(hidden)`", tcx.def_path_str(def_id) }
     }
 
+    /// Determines whether an item is annotated with `doc(notable_trait)`.
+    query is_doc_notable_trait(def_id: DefId) -> bool {
+        desc { |tcx| "checking whether `{}` is `doc(notable_trait)`", tcx.def_path_str(def_id) }
+    }
+
     /// Returns the attributes on the item at `def_id`.
     ///
     /// Do not use this directly, use `tcx.get_attrs` instead.
@@ -1404,7 +1409,7 @@ rustc_queries! {
     query specializes(_: (DefId, DefId)) -> bool {
         desc { "computing whether impls specialize one another" }
     }
-    query in_scope_traits_map(_: LocalDefId)
+    query in_scope_traits_map(_: hir::OwnerId)
         -> Option<&'tcx FxHashMap<ItemLocalId, Box<[TraitCandidate]>>> {
         desc { "traits in scope at a block" }
     }
@@ -1419,7 +1424,7 @@ rustc_queries! {
         separate_provide_extern
     }
 
-    query check_well_formed(key: LocalDefId) -> () {
+    query check_well_formed(key: hir::OwnerId) -> () {
         desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key.to_def_id()) }
     }
 
@@ -1586,7 +1591,7 @@ rustc_queries! {
         arena_cache
         desc { "resolving lifetimes" }
     }
-    query named_region_map(_: LocalDefId) ->
+    query named_region_map(_: hir::OwnerId) ->
         Option<&'tcx FxHashMap<ItemLocalId, Region>> {
         desc { "looking up a named region" }
     }
@@ -1602,7 +1607,7 @@ rustc_queries! {
         desc { "looking up lifetime defaults for generic parameter `{}`", tcx.def_path_str(key) }
         separate_provide_extern
     }
-    query late_bound_vars_map(_: LocalDefId)
+    query late_bound_vars_map(_: hir::OwnerId)
         -> Option<&'tcx FxHashMap<ItemLocalId, Vec<ty::BoundVariableKind>>> {
         desc { "looking up late bound vars" }
     }
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 86b4150505f..84374a25ed8 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -852,12 +852,8 @@ mod size_asserts {
     static_assert_size!(Block, 56);
     static_assert_size!(Expr<'_>, 64);
     static_assert_size!(ExprKind<'_>, 40);
-    #[cfg(not(bootstrap))]
     static_assert_size!(Pat<'_>, 72);
-    #[cfg(not(bootstrap))]
     static_assert_size!(PatKind<'_>, 56);
-    #[cfg(not(bootstrap))]
     static_assert_size!(Stmt<'_>, 48);
-    #[cfg(not(bootstrap))]
     static_assert_size!(StmtKind<'_>, 40);
 }
diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs
index 0e6cacb9fd0..fb152b63f63 100644
--- a/compiler/rustc_middle/src/traits/query.rs
+++ b/compiler/rustc_middle/src/traits/query.rs
@@ -8,8 +8,9 @@
 use crate::error::DropCheckOverflow;
 use crate::infer::canonical::{Canonical, QueryResponse};
 use crate::ty::error::TypeError;
-use crate::ty::subst::GenericArg;
+use crate::ty::subst::{GenericArg, SubstsRef};
 use crate::ty::{self, Ty, TyCtxt};
+use rustc_hir::def_id::DefId;
 use rustc_span::source_map::Span;
 use std::iter::FromIterator;
 
@@ -219,4 +220,5 @@ pub enum OutlivesBound<'tcx> {
     RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
     RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
     RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>),
+    RegionSubOpaque(ty::Region<'tcx>, DefId, SubstsRef<'tcx>),
 }
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 2e596b27527..74ce0b38ed2 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -438,7 +438,8 @@ impl<'tcx> AdtDef<'tcx> {
             | Res::Def(DefKind::Union, _)
             | Res::Def(DefKind::TyAlias, _)
             | Res::Def(DefKind::AssocTy, _)
-            | Res::SelfTy { .. }
+            | Res::SelfTyParam { .. }
+            | Res::SelfTyAlias { .. }
             | Res::SelfCtor(..) => self.non_enum_variant(),
             _ => bug!("unexpected res {:?} in variant_of_res", res),
         }
diff --git a/compiler/rustc_middle/src/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs
index 981e2d3b6d2..2de27102bcc 100644
--- a/compiler/rustc_middle/src/ty/cast.rs
+++ b/compiler/rustc_middle/src/ty/cast.rs
@@ -38,7 +38,7 @@ pub enum CastTy<'tcx> {
 }
 
 /// Cast Kind. See [RFC 401](https://rust-lang.github.io/rfcs/0401-coercions.html)
-/// (or librustc_typeck/check/cast.rs).
+/// (or rustc_hir_analysis/check/cast.rs).
 #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
 pub enum CastKind {
     CoercionCast,
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 8c44f4a98df..4781585b82c 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1,7 +1,7 @@
 //! Type context book-keeping.
 
 use crate::arena::Arena;
-use crate::dep_graph::{DepGraph, DepKind, DepKindStruct};
+use crate::dep_graph::{DepGraph, DepKindStruct};
 use crate::hir::place::Place as HirPlace;
 use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
 use crate::lint::{struct_lint_level, LintLevelSource};
@@ -40,6 +40,7 @@ use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
 use rustc_hir::definitions::Definitions;
+use rustc_hir::hir_id::OwnerId;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{
@@ -289,7 +290,7 @@ pub struct CommonConsts<'tcx> {
 }
 
 pub struct LocalTableInContext<'a, V> {
-    hir_owner: LocalDefId,
+    hir_owner: OwnerId,
     data: &'a ItemLocalMap<V>,
 }
 
@@ -301,7 +302,7 @@ pub struct LocalTableInContext<'a, V> {
 /// would result in lookup errors, or worse, in silently wrong data being
 /// stored/returned.
 #[inline]
-fn validate_hir_id_for_typeck_results(hir_owner: LocalDefId, hir_id: hir::HirId) {
+fn validate_hir_id_for_typeck_results(hir_owner: OwnerId, hir_id: hir::HirId) {
     if hir_id.owner != hir_owner {
         invalid_hir_id_for_typeck_results(hir_owner, hir_id);
     }
@@ -309,7 +310,7 @@ fn validate_hir_id_for_typeck_results(hir_owner: LocalDefId, hir_id: hir::HirId)
 
 #[cold]
 #[inline(never)]
-fn invalid_hir_id_for_typeck_results(hir_owner: LocalDefId, hir_id: hir::HirId) {
+fn invalid_hir_id_for_typeck_results(hir_owner: OwnerId, hir_id: hir::HirId) {
     ty::tls::with(|tcx| {
         bug!(
             "node {} with HirId::owner {:?} cannot be placed in TypeckResults with hir_owner {:?}",
@@ -345,7 +346,7 @@ impl<'a, V> ::std::ops::Index<hir::HirId> for LocalTableInContext<'a, V> {
 }
 
 pub struct LocalTableInContextMut<'a, V> {
-    hir_owner: LocalDefId,
+    hir_owner: OwnerId,
     data: &'a mut ItemLocalMap<V>,
 }
 
@@ -417,7 +418,7 @@ pub struct GeneratorDiagnosticData<'tcx> {
 #[derive(TyEncodable, TyDecodable, Debug, HashStable)]
 pub struct TypeckResults<'tcx> {
     /// The `HirId::owner` all `ItemLocalId`s in this table are relative to.
-    pub hir_owner: LocalDefId,
+    pub hir_owner: OwnerId,
 
     /// Resolved definitions for `<T>::X` associated paths and
     /// method calls, including those of overloaded operators.
@@ -573,7 +574,7 @@ pub struct TypeckResults<'tcx> {
 
     /// Tracks the rvalue scoping rules which defines finer scoping for rvalue expressions
     /// by applying extended parameter rules.
-    /// Details may be find in `rustc_typeck::check::rvalue_scopes`.
+    /// Details may be find in `rustc_hir_analysis::check::rvalue_scopes`.
     pub rvalue_scopes: RvalueScopes,
 
     /// Stores the type, expression, span and optional scope span of all types
@@ -592,7 +593,7 @@ pub struct TypeckResults<'tcx> {
 }
 
 impl<'tcx> TypeckResults<'tcx> {
-    pub fn new(hir_owner: LocalDefId) -> TypeckResults<'tcx> {
+    pub fn new(hir_owner: OwnerId) -> TypeckResults<'tcx> {
         TypeckResults {
             hir_owner,
             type_dependent_defs: Default::default(),
@@ -1084,7 +1085,7 @@ pub struct GlobalCtxt<'tcx> {
 
     pub queries: &'tcx dyn query::QueryEngine<'tcx>,
     pub query_caches: query::QueryCaches<'tcx>,
-    query_kinds: &'tcx [DepKindStruct<'tcx>],
+    pub(crate) query_kinds: &'tcx [DepKindStruct<'tcx>],
 
     // Internal caches for metadata decoding. No need to track deps on this.
     pub ty_rcache: Lock<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
@@ -1291,10 +1292,6 @@ impl<'tcx> TyCtxt<'tcx> {
         }
     }
 
-    pub(crate) fn query_kind(self, k: DepKind) -> &'tcx DepKindStruct<'tcx> {
-        &self.query_kinds[k as usize]
-    }
-
     /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used.
     #[track_caller]
     pub fn ty_error(self) -> Ty<'tcx> {
@@ -1726,7 +1723,7 @@ impl<'tcx> TyCtxt<'tcx> {
 
     #[inline]
     pub fn local_visibility(self, def_id: LocalDefId) -> Visibility {
-        self.visibility(def_id.to_def_id()).expect_local()
+        self.visibility(def_id).expect_local()
     }
 }
 
@@ -2907,7 +2904,7 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     pub fn is_late_bound(self, id: HirId) -> bool {
-        self.is_late_bound_map(id.owner).map_or(false, |set| {
+        self.is_late_bound_map(id.owner.def_id).map_or(false, |set| {
             let def_id = self.hir().local_def_id(id);
             set.contains(&def_id)
         })
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 01e1e97b21a..52f16ad88f6 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -861,7 +861,7 @@ fn foo(&self) -> Self::T { String::new() }
         // When `body_owner` is an `impl` or `trait` item, look in its associated types for
         // `expected` and point at it.
         let parent_id = self.hir().get_parent_item(hir_id);
-        let item = self.hir().find_by_def_id(parent_id);
+        let item = self.hir().find_by_def_id(parent_id.def_id);
         debug!("expected_projection parent item {:?}", item);
         match item {
             Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., items), .. })) => {
diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs
index 9c8dc30e2db..0257ca7b29c 100644
--- a/compiler/rustc_middle/src/ty/parameterized.rs
+++ b/compiler/rustc_middle/src/ty/parameterized.rs
@@ -1,3 +1,4 @@
+use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::{DefId, DefIndex};
 use rustc_index::vec::{Idx, IndexVec};
 
@@ -29,6 +30,10 @@ impl<I: Idx + 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for IndexVe
     type Value<'tcx> = IndexVec<I, T::Value<'tcx>>;
 }
 
+impl<I: 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for FxHashMap<I, T> {
+    type Value<'tcx> = FxHashMap<I, T::Value<'tcx>>;
+}
+
 impl<T: ParameterizedOverTcx> ParameterizedOverTcx for ty::Binder<'static, T> {
     type Value<'tcx> = ty::Binder<'tcx, T::Value<'tcx>>;
 }
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 99e5722ddad..f69ac076820 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1562,7 +1562,9 @@ pub struct FmtPrinterData<'a, 'tcx> {
     in_value: bool,
     pub print_alloc_ids: bool,
 
+    // set of all named (non-anonymous) region names
     used_region_names: FxHashSet<Symbol>,
+
     region_index: usize,
     binder_depth: usize,
     printed_type_count: usize,
@@ -2118,23 +2120,31 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
     where
         T: Print<'tcx, Self, Output = Self, Error = fmt::Error> + TypeFoldable<'tcx>,
     {
-        fn name_by_region_index(index: usize) -> Symbol {
-            match index {
-                0 => Symbol::intern("'r"),
-                1 => Symbol::intern("'s"),
-                i => Symbol::intern(&format!("'t{}", i - 2)),
+        fn name_by_region_index(
+            index: usize,
+            available_names: &mut Vec<Symbol>,
+            num_available: usize,
+        ) -> Symbol {
+            if let Some(name) = available_names.pop() {
+                name
+            } else {
+                Symbol::intern(&format!("'z{}", index - num_available))
             }
         }
 
+        debug!("name_all_regions");
+
         // Replace any anonymous late-bound regions with named
         // variants, using new unique identifiers, so that we can
         // clearly differentiate between named and unnamed regions in
         // the output. We'll probably want to tweak this over time to
         // decide just how much information to give.
         if self.binder_depth == 0 {
-            self.prepare_late_bound_region_info(value);
+            self.prepare_region_info(value);
         }
 
+        debug!("self.used_region_names: {:?}", &self.used_region_names);
+
         let mut empty = true;
         let mut start_or_continue = |cx: &mut Self, start: &str, cont: &str| {
             let w = if empty {
@@ -2151,13 +2161,30 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
 
         define_scoped_cx!(self);
 
+        let possible_names =
+            ('a'..='z').rev().map(|s| Symbol::intern(&format!("'{s}"))).collect::<Vec<_>>();
+
+        let mut available_names = possible_names
+            .into_iter()
+            .filter(|name| !self.used_region_names.contains(&name))
+            .collect::<Vec<_>>();
+        debug!(?available_names);
+        let num_available = available_names.len();
+
         let mut region_index = self.region_index;
-        let mut next_name = |this: &Self| loop {
-            let name = name_by_region_index(region_index);
-            region_index += 1;
-            if !this.used_region_names.contains(&name) {
-                break name;
+        let mut next_name = |this: &Self| {
+            let mut name;
+
+            loop {
+                name = name_by_region_index(region_index, &mut available_names, num_available);
+                region_index += 1;
+
+                if !this.used_region_names.contains(&name) {
+                    break;
+                }
             }
+
+            name
         };
 
         // If we want to print verbosely, then print *all* binders, even if they
@@ -2178,6 +2205,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
                         ty::BrAnon(_) | ty::BrEnv => {
                             start_or_continue(&mut self, "for<", ", ");
                             let name = next_name(&self);
+                            debug!(?name);
                             do_continue(&mut self, name);
                             ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
                         }
@@ -2271,29 +2299,37 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
         Ok(inner)
     }
 
-    fn prepare_late_bound_region_info<T>(&mut self, value: &ty::Binder<'tcx, T>)
+    fn prepare_region_info<T>(&mut self, value: &ty::Binder<'tcx, T>)
     where
         T: TypeVisitable<'tcx>,
     {
-        struct LateBoundRegionNameCollector<'a, 'tcx> {
-            used_region_names: &'a mut FxHashSet<Symbol>,
+        struct RegionNameCollector<'tcx> {
+            used_region_names: FxHashSet<Symbol>,
             type_collector: SsoHashSet<Ty<'tcx>>,
         }
 
-        impl<'tcx> ty::visit::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_, 'tcx> {
+        impl<'tcx> RegionNameCollector<'tcx> {
+            fn new() -> Self {
+                RegionNameCollector {
+                    used_region_names: Default::default(),
+                    type_collector: SsoHashSet::new(),
+                }
+            }
+        }
+
+        impl<'tcx> ty::visit::TypeVisitor<'tcx> for RegionNameCollector<'tcx> {
             type BreakTy = ();
 
             fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
                 trace!("address: {:p}", r.0.0);
-                if let ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) = *r {
-                    self.used_region_names.insert(name);
-                } else if let ty::RePlaceholder(ty::PlaceholderRegion {
-                    name: ty::BrNamed(_, name),
-                    ..
-                }) = *r
-                {
+
+                // Collect all named lifetimes. These allow us to prevent duplication
+                // of already existing lifetime names when introducing names for
+                // anonymous late-bound regions.
+                if let Some(name) = r.get_name() {
                     self.used_region_names.insert(name);
                 }
+
                 r.super_visit_with(self)
             }
 
@@ -2309,12 +2345,9 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
             }
         }
 
-        self.used_region_names.clear();
-        let mut collector = LateBoundRegionNameCollector {
-            used_region_names: &mut self.used_region_names,
-            type_collector: SsoHashSet::new(),
-        };
+        let mut collector = RegionNameCollector::new();
         value.visit_with(&mut collector);
+        self.used_region_names = collector.used_region_names;
         self.region_index = 0;
     }
 }
diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs
index 00da260b1dc..169da348a29 100644
--- a/compiler/rustc_middle/src/ty/query.rs
+++ b/compiler/rustc_middle/src/ty/query.rs
@@ -44,6 +44,7 @@ use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId};
+use rustc_hir::hir_id::OwnerId;
 use rustc_hir::lang_items::{LangItem, LanguageItems};
 use rustc_hir::{Crate, ItemLocalId, TraitCandidate};
 use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
@@ -336,7 +337,7 @@ macro_rules! define_callbacks {
 rustc_query_append! { define_callbacks! }
 
 mod sealed {
-    use super::{DefId, LocalDefId};
+    use super::{DefId, LocalDefId, OwnerId};
 
     /// An analogue of the `Into` trait that's intended only for query parameters.
     ///
@@ -366,6 +367,13 @@ mod sealed {
             self.to_def_id()
         }
     }
+
+    impl IntoQueryParam<DefId> for OwnerId {
+        #[inline(always)]
+        fn into_query_param(self) -> DefId {
+            self.to_def_id()
+        }
+    }
 }
 
 use sealed::IntoQueryParam;
diff --git a/compiler/rustc_middle/src/ty/rvalue_scopes.rs b/compiler/rustc_middle/src/ty/rvalue_scopes.rs
index e86dafae338..e79b79a25ae 100644
--- a/compiler/rustc_middle/src/ty/rvalue_scopes.rs
+++ b/compiler/rustc_middle/src/ty/rvalue_scopes.rs
@@ -3,7 +3,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
 
 /// `RvalueScopes` is a mapping from sub-expressions to _extended_ lifetime as determined by
-/// rules laid out in `rustc_typeck::check::rvalue_scopes`.
+/// rules laid out in `rustc_hir_analysis::check::rvalue_scopes`.
 #[derive(TyEncodable, TyDecodable, Clone, Debug, Default, Eq, PartialEq, HashStable)]
 pub struct RvalueScopes {
     map: FxHashMap<hir::ItemLocalId, Option<Scope>>,
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 258fb2e2f9f..2f6ec836c3c 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -85,6 +85,17 @@ impl BoundRegionKind {
             _ => false,
         }
     }
+
+    pub fn get_name(&self) -> Option<Symbol> {
+        if self.is_named() {
+            match *self {
+                BoundRegionKind::BrNamed(_, name) => return Some(name),
+                _ => unreachable!(),
+            }
+        }
+
+        None
+    }
 }
 
 pub trait Article {
@@ -304,7 +315,7 @@ impl<'tcx> ClosureSubsts<'tcx> {
     /// closure.
     // FIXME(eddyb) this should be unnecessary, as the shallowly resolved
     // type is known at the time of the creation of `ClosureSubsts`,
-    // see `rustc_typeck::check::closure`.
+    // see `rustc_hir_analysis::check::closure`.
     pub fn sig_as_fn_ptr_ty(self) -> Ty<'tcx> {
         self.split().closure_sig_as_fn_ptr_ty.expect_ty()
     }
@@ -1445,6 +1456,23 @@ impl<'tcx> Region<'tcx> {
         *self.0.0
     }
 
+    pub fn get_name(self) -> Option<Symbol> {
+        if self.has_name() {
+            let name = match *self {
+                ty::ReEarlyBound(ebr) => Some(ebr.name),
+                ty::ReLateBound(_, br) => br.kind.get_name(),
+                ty::ReFree(fr) => fr.bound_region.get_name(),
+                ty::ReStatic => Some(kw::StaticLifetime),
+                ty::RePlaceholder(placeholder) => placeholder.name.get_name(),
+                _ => None,
+            };
+
+            return name;
+        }
+
+        None
+    }
+
     /// Is this region named by the user?
     pub fn has_name(self) -> bool {
         match *self {
@@ -2093,7 +2121,7 @@ impl<'tcx> Ty<'tcx> {
     ///
     /// Note that during type checking, we use an inference variable
     /// to represent the closure kind, because it has not yet been
-    /// inferred. Once upvar inference (in `rustc_typeck/src/check/upvar.rs`)
+    /// inferred. Once upvar inference (in `rustc_hir_analysis/src/check/upvar.rs`)
     /// is complete, that type variable will be unified.
     pub fn to_opt_closure_kind(self) -> Option<ty::ClosureKind> {
         match self.kind() {
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index a939be32fff..36eb2ab5157 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -492,6 +492,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
 }
 
 impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for &'tcx ty::List<T> {
+    #[inline]
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|t| t.visit_with(visitor))
     }
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index d93aab04e99..713f9067a85 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -1289,12 +1289,24 @@ pub fn is_doc_hidden(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
         .any(|items| items.iter().any(|item| item.has_name(sym::hidden)))
 }
 
+/// Determines whether an item is annotated with `doc(notable_trait)`.
+pub fn is_doc_notable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+    tcx.get_attrs(def_id, sym::doc)
+        .filter_map(|attr| attr.meta_item_list())
+        .any(|items| items.iter().any(|item| item.has_name(sym::notable_trait)))
+}
+
 /// Determines whether an item is an intrinsic by Abi.
 pub fn is_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
     matches!(tcx.fn_sig(def_id).abi(), Abi::RustIntrinsic | Abi::PlatformIntrinsic)
 }
 
 pub fn provide(providers: &mut ty::query::Providers) {
-    *providers =
-        ty::query::Providers { normalize_opaque_types, is_doc_hidden, is_intrinsic, ..*providers }
+    *providers = ty::query::Providers {
+        normalize_opaque_types,
+        is_doc_hidden,
+        is_doc_notable_trait,
+        is_intrinsic,
+        ..*providers
+    }
 }
diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs
index 4bab583c960..fc1b301402b 100644
--- a/compiler/rustc_mir_build/src/build/block.rs
+++ b/compiler/rustc_mir_build/src/build/block.rs
@@ -221,27 +221,37 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
                     let init = &this.thir[*initializer];
                     let initializer_span = init.span;
-                    this.declare_bindings(
-                        visibility_scope,
-                        remainder_span,
-                        pattern,
-                        ArmHasGuard(false),
-                        Some((None, initializer_span)),
-                    );
-                    this.visit_primary_bindings(
-                        pattern,
-                        UserTypeProjections::none(),
-                        &mut |this, _, _, _, node, span, _, _| {
-                            this.storage_live_binding(block, node, span, OutsideGuard, true);
-                            this.schedule_drop_for_binding(node, span, OutsideGuard);
-                        },
-                    );
                     let failure = unpack!(
                         block = this.in_opt_scope(
                             opt_destruction_scope.map(|de| (de, source_info)),
                             |this| {
                                 let scope = (*init_scope, source_info);
                                 this.in_scope(scope, *lint_level, |this| {
+                                    this.declare_bindings(
+                                        visibility_scope,
+                                        remainder_span,
+                                        pattern,
+                                        ArmHasGuard(false),
+                                        Some((None, initializer_span)),
+                                    );
+                                    this.visit_primary_bindings(
+                                        pattern,
+                                        UserTypeProjections::none(),
+                                        &mut |this, _, _, _, node, span, _, _| {
+                                            this.storage_live_binding(
+                                                block,
+                                                node,
+                                                span,
+                                                OutsideGuard,
+                                                true,
+                                            );
+                                            this.schedule_drop_for_binding(
+                                                node,
+                                                span,
+                                                OutsideGuard,
+                                            );
+                                        },
+                                    );
                                     this.ast_let_else(
                                         block,
                                         init,
@@ -306,7 +316,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                                             ArmHasGuard(false),
                                             Some((None, initializer_span)),
                                         );
-                                        this.expr_into_pattern(block, &pattern, init) // irrefutable pattern
+                                        this.expr_into_pattern(block, &pattern, init)
+                                        // irrefutable pattern
                                     })
                                 },
                             )
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 495738ebe1c..988ebccb633 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -364,7 +364,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                     // If the called function has target features the calling function hasn't,
                     // the call requires `unsafe`. Don't check this on wasm
                     // targets, though. For more information on wasm see the
-                    // is_like_wasm check in typeck/src/collect.rs
+                    // is_like_wasm check in hir_analysis/src/collect.rs
                     if !self.tcx.sess.target.options.is_like_wasm
                         && !self
                             .tcx
diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs
index 0c0a2fe9c9e..8236b1528c0 100644
--- a/compiler/rustc_mir_build/src/lib.rs
+++ b/compiler/rustc_mir_build/src/lib.rs
@@ -6,7 +6,6 @@
 #![feature(control_flow_enum)]
 #![feature(if_let_guard)]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(min_specialization)]
 #![feature(once_cell)]
 #![recursion_limit = "256"]
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 3f8a9d21cd8..bcf2ed68172 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -998,7 +998,7 @@ impl<'tcx> Cx<'tcx> {
             .temporary_scope(self.region_scope_tree, closure_expr.hir_id.local_id);
         let var_ty = place.base_ty;
 
-        // The result of capture analysis in `rustc_typeck/check/upvar.rs`represents a captured path
+        // The result of capture analysis in `rustc_hir_analysis/check/upvar.rs`represents a captured path
         // as it's seen for use within the closure and not at the time of closure creation.
         //
         // That is we see expect to see it start from a captured upvar and not something that is local
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 11645f840c1..895af80bd7f 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -86,7 +86,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         // ```
         //
         // the type assigned to `Some(n)` in `unadjusted_pat` would be `Option<i32>` (this is
-        // determined in rustc_typeck::check::match). The adjustments would be
+        // determined in rustc_hir_analysis::check::match). The adjustments would be
         //
         // `vec![&&Option<i32>, &Option<i32>]`.
         //
@@ -433,7 +433,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 | DefKind::AssocTy,
                 _,
             )
-            | Res::SelfTy { .. }
+            | Res::SelfTyParam { .. }
+            | Res::SelfTyAlias { .. }
             | Res::SelfCtor(..) => PatKind::Leaf { subpatterns },
             _ => {
                 let pattern_error = match res {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index 02e047afaf3..22b58837148 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -746,7 +746,7 @@ impl<'p, 'tcx> Witness<'p, 'tcx> {
 /// Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns`
 /// is not exhaustive enough.
 ///
-/// NB: The partner lint for structs lives in `compiler/rustc_typeck/src/check/pat.rs`.
+/// NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`.
 fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>(
     cx: &MatchCheckCtxt<'p, 'tcx>,
     scrut_ty: Ty<'tcx>,
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index b45c32ee986..b471d04fd60 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -1,7 +1,6 @@
 #![feature(associated_type_defaults)]
 #![feature(box_patterns)]
 #![feature(exact_size_is_empty)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(min_specialization)]
 #![feature(once_cell)]
 #![feature(stmt_expr_attributes)]
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index e6fc8559571..2230c3399f0 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -1,7 +1,6 @@
 #![allow(rustc::potential_query_instability)]
 #![feature(box_patterns)]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(map_try_insert)]
 #![feature(min_specialization)]
 #![feature(never_type)]
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index f1a25a60d52..5cd7a7f760f 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -1246,7 +1246,7 @@ impl<'v> RootCollector<'_, 'v> {
                 }
             }
             DefKind::Fn => {
-                self.push_if_root(id.def_id);
+                self.push_if_root(id.def_id.def_id);
             }
             _ => {}
         }
@@ -1254,7 +1254,7 @@ impl<'v> RootCollector<'_, 'v> {
 
     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);
+            self.push_if_root(id.def_id.def_id);
         }
     }
 
diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs
index ba6ce9fd40f..42781bd25f0 100644
--- a/compiler/rustc_monomorphize/src/lib.rs
+++ b/compiler/rustc_monomorphize/src/lib.rs
@@ -1,6 +1,5 @@
 #![feature(array_windows)]
 #![feature(control_flow_enum)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
 #![deny(rustc::untranslatable_diagnostic)]
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
new file mode 100644
index 00000000000..98fee997427
--- /dev/null
+++ b/compiler/rustc_parse/src/errors.rs
@@ -0,0 +1,1251 @@
+use rustc_ast::token::Token;
+use rustc_ast::Path;
+use rustc_errors::{fluent, AddToDiagnostic, Applicability, EmissionGuarantee, IntoDiagnostic};
+use rustc_macros::{Diagnostic, Subdiagnostic};
+use rustc_session::errors::ExprParenthesesNeeded;
+use rustc_span::symbol::Ident;
+use rustc_span::{Span, Symbol};
+
+use crate::parser::TokenDescription;
+
+#[derive(Diagnostic)]
+#[diag(parser::maybe_report_ambiguous_plus)]
+pub(crate) struct AmbiguousPlus {
+    pub sum_ty: String,
+    #[primary_span]
+    #[suggestion(code = "({sum_ty})")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::maybe_recover_from_bad_type_plus, code = "E0178")]
+pub(crate) struct BadTypePlus {
+    pub ty: String,
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub sub: BadTypePlusSub,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum BadTypePlusSub {
+    #[suggestion(
+        parser::add_paren,
+        code = "{sum_with_parens}",
+        applicability = "machine-applicable"
+    )]
+    AddParen {
+        sum_with_parens: String,
+        #[primary_span]
+        span: Span,
+    },
+    #[label(parser::forgot_paren)]
+    ForgotParen {
+        #[primary_span]
+        span: Span,
+    },
+    #[label(parser::expect_path)]
+    ExpectPath {
+        #[primary_span]
+        span: Span,
+    },
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::maybe_recover_from_bad_qpath_stage_2)]
+pub(crate) struct BadQPathStage2 {
+    #[primary_span]
+    #[suggestion(code = "", applicability = "maybe-incorrect")]
+    pub span: Span,
+    pub ty: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::incorrect_semicolon)]
+pub(crate) struct IncorrectSemicolon<'a> {
+    #[primary_span]
+    #[suggestion_short(code = "", applicability = "machine-applicable")]
+    pub span: Span,
+    #[help]
+    pub opt_help: Option<()>,
+    pub name: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::incorrect_use_of_await)]
+pub(crate) struct IncorrectUseOfAwait {
+    #[primary_span]
+    #[suggestion(parser::parentheses_suggestion, code = "", applicability = "machine-applicable")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::incorrect_use_of_await)]
+pub(crate) struct IncorrectAwait {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(parser::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)]
+pub(crate) struct InInTypo {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(code = "", applicability = "machine-applicable")]
+    pub sugg_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::invalid_variable_declaration)]
+pub(crate) struct InvalidVariableDeclaration {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub sub: InvalidVariableDeclarationSub,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum InvalidVariableDeclarationSub {
+    #[suggestion(
+        parser::switch_mut_let_order,
+        applicability = "maybe-incorrect",
+        code = "let mut"
+    )]
+    SwitchMutLetOrder(#[primary_span] Span),
+    #[suggestion(
+        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")]
+    UseLetNotAuto(#[primary_span] Span),
+    #[suggestion(parser::use_let_not_var, applicability = "machine-applicable", code = "let")]
+    UseLetNotVar(#[primary_span] Span),
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::invalid_comparison_operator)]
+pub(crate) struct InvalidComparisonOperator {
+    #[primary_span]
+    pub span: Span,
+    pub invalid: String,
+    #[subdiagnostic]
+    pub sub: InvalidComparisonOperatorSub,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum InvalidComparisonOperatorSub {
+    #[suggestion_short(
+        parser::use_instead,
+        applicability = "machine-applicable",
+        code = "{correct}"
+    )]
+    Correctable {
+        #[primary_span]
+        span: Span,
+        invalid: String,
+        correct: String,
+    },
+    #[label(parser::spaceship_operator_invalid)]
+    Spaceship(#[primary_span] Span),
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::invalid_logical_operator)]
+#[note]
+pub(crate) struct InvalidLogicalOperator {
+    #[primary_span]
+    pub span: Span,
+    pub incorrect: String,
+    #[subdiagnostic]
+    pub sub: InvalidLogicalOperatorSub,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum InvalidLogicalOperatorSub {
+    #[suggestion_short(
+        parser::use_amp_amp_for_conjunction,
+        applicability = "machine-applicable",
+        code = "&&"
+    )]
+    Conjunction(#[primary_span] Span),
+    #[suggestion_short(
+        parser::use_pipe_pipe_for_disjunction,
+        applicability = "machine-applicable",
+        code = "||"
+    )]
+    Disjunction(#[primary_span] Span),
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::tilde_is_not_unary_operator)]
+pub(crate) struct TildeAsUnaryOperator(
+    #[primary_span]
+    #[suggestion_short(applicability = "machine-applicable", code = "!")]
+    pub Span,
+);
+
+#[derive(Diagnostic)]
+#[diag(parser::unexpected_token_after_not)]
+pub(crate) struct NotAsNegationOperator {
+    #[primary_span]
+    pub negated: Span,
+    pub negated_desc: String,
+    #[subdiagnostic]
+    pub sub: NotAsNegationOperatorSub,
+}
+
+#[derive(Subdiagnostic)]
+pub enum NotAsNegationOperatorSub {
+    #[suggestion_short(
+        parser::unexpected_token_after_not_default,
+        applicability = "machine-applicable",
+        code = "!"
+    )]
+    SuggestNotDefault(#[primary_span] Span),
+
+    #[suggestion_short(
+        parser::unexpected_token_after_not_bitwise,
+        applicability = "machine-applicable",
+        code = "!"
+    )]
+    SuggestNotBitwise(#[primary_span] Span),
+
+    #[suggestion_short(
+        parser::unexpected_token_after_not_logical,
+        applicability = "machine-applicable",
+        code = "!"
+    )]
+    SuggestNotLogical(#[primary_span] Span),
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::malformed_loop_label)]
+pub(crate) struct MalformedLoopLabel {
+    #[primary_span]
+    #[suggestion(applicability = "machine-applicable", code = "{correct_label}")]
+    pub span: Span,
+    pub correct_label: Ident,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::lifetime_in_borrow_expression)]
+pub(crate) struct LifetimeInBorrowExpression {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(applicability = "machine-applicable", code = "")]
+    #[label]
+    pub lifetime_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::field_expression_with_generic)]
+pub(crate) struct FieldExpressionWithGeneric(#[primary_span] pub Span);
+
+#[derive(Diagnostic)]
+#[diag(parser::macro_invocation_with_qualified_path)]
+pub(crate) struct MacroInvocationWithQualifiedPath(#[primary_span] pub Span);
+
+#[derive(Diagnostic)]
+#[diag(parser::unexpected_token_after_label)]
+pub(crate) struct UnexpectedTokenAfterLabel {
+    #[primary_span]
+    #[label(parser::unexpected_token_after_label)]
+    pub span: Span,
+    #[suggestion_verbose(parser::suggestion_remove_label, 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")]
+pub(crate) struct UnexpectedTokenAfterLabelSugg {
+    #[suggestion_part(code = "{{ ")]
+    pub left: Span,
+    #[suggestion_part(code = " }}")]
+    pub right: Span,
+}
+
+#[derive(Diagnostic)]
+#[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 = ": ")]
+    pub label_end: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::do_catch_syntax_removed)]
+#[note]
+pub(crate) struct DoCatchSyntaxRemoved {
+    #[primary_span]
+    #[suggestion(applicability = "machine-applicable", code = "try")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::float_literal_requires_integer_part)]
+pub(crate) struct FloatLiteralRequiresIntegerPart {
+    #[primary_span]
+    #[suggestion(applicability = "machine-applicable", code = "{correct}")]
+    pub span: Span,
+    pub correct: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::invalid_int_literal_width)]
+#[help]
+pub(crate) struct InvalidIntLiteralWidth {
+    #[primary_span]
+    pub span: Span,
+    pub width: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::invalid_num_literal_base_prefix)]
+#[note]
+pub(crate) struct InvalidNumLiteralBasePrefix {
+    #[primary_span]
+    #[suggestion(applicability = "maybe-incorrect", code = "{fixed}")]
+    pub span: Span,
+    pub fixed: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::invalid_num_literal_suffix)]
+#[help]
+pub(crate) struct InvalidNumLiteralSuffix {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub suffix: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::invalid_float_literal_width)]
+#[help]
+pub(crate) struct InvalidFloatLiteralWidth {
+    #[primary_span]
+    pub span: Span,
+    pub width: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::invalid_float_literal_suffix)]
+#[help]
+pub(crate) struct InvalidFloatLiteralSuffix {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub suffix: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::int_literal_too_large)]
+pub(crate) struct IntLiteralTooLarge {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::missing_semicolon_before_array)]
+pub(crate) struct MissingSemicolonBeforeArray {
+    #[primary_span]
+    pub open_delim: Span,
+    #[suggestion_verbose(applicability = "maybe-incorrect", code = ";")]
+    pub semicolon: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::invalid_block_macro_segment)]
+pub(crate) struct InvalidBlockMacroSegment {
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    pub context: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::if_expression_missing_then_block)]
+pub(crate) struct IfExpressionMissingThenBlock {
+    #[primary_span]
+    pub if_span: Span,
+    #[subdiagnostic]
+    pub sub: IfExpressionMissingThenBlockSub,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum IfExpressionMissingThenBlockSub {
+    #[help(parser::condition_possibly_unfinished)]
+    UnfinishedCondition(#[primary_span] Span),
+    #[help(parser::add_then_block)]
+    AddThenBlock(#[primary_span] Span),
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::if_expression_missing_condition)]
+pub(crate) struct IfExpressionMissingCondition {
+    #[primary_span]
+    #[label(parser::condition_label)]
+    pub if_span: Span,
+    #[label(parser::block_label)]
+    pub block_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::expected_expression_found_let)]
+pub(crate) struct ExpectedExpressionFoundLet {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::expected_else_block)]
+pub(crate) struct ExpectedElseBlock {
+    #[primary_span]
+    pub first_tok_span: Span,
+    pub first_tok: String,
+    #[label]
+    pub else_span: Span,
+    #[suggestion(applicability = "maybe-incorrect", code = "if ")]
+    pub condition_start: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::outer_attribute_not_allowed_on_if_else)]
+pub(crate) struct OuterAttributeNotAllowedOnIfElse {
+    #[primary_span]
+    pub last: Span,
+
+    #[label(parser::branch_label)]
+    pub branch_span: Span,
+
+    #[label(parser::ctx_label)]
+    pub ctx_span: Span,
+    pub ctx: String,
+
+    #[suggestion(applicability = "machine-applicable", code = "")]
+    pub attributes: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::missing_in_in_for_loop)]
+pub(crate) struct MissingInInForLoop {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub sub: MissingInInForLoopSub,
+}
+
+#[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")]
+    InNotOf(#[primary_span] Span),
+    #[suggestion_short(parser::add_in, applicability = "maybe-incorrect", code = " in ")]
+    AddIn(#[primary_span] Span),
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::missing_comma_after_match_arm)]
+pub(crate) struct MissingCommaAfterMatchArm {
+    #[primary_span]
+    #[suggestion(applicability = "machine-applicable", code = ",")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::catch_after_try)]
+#[help]
+pub(crate) struct CatchAfterTry {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::comma_after_base_struct)]
+#[note]
+pub(crate) struct CommaAfterBaseStruct {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion_short(applicability = "machine-applicable", code = "")]
+    pub comma: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::eq_field_init)]
+pub(crate) struct EqFieldInit {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(applicability = "machine-applicable", code = ":")]
+    pub eq: Span,
+}
+
+#[derive(Diagnostic)]
+#[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 = "..=")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::left_arrow_operator)]
+pub(crate) struct LeftArrowOperator {
+    #[primary_span]
+    #[suggestion(applicability = "maybe-incorrect", code = "< -")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::remove_let)]
+pub(crate) struct RemoveLet {
+    #[primary_span]
+    #[suggestion(applicability = "machine-applicable", code = "")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::use_eq_instead)]
+pub(crate) struct UseEqInstead {
+    #[primary_span]
+    #[suggestion_short(applicability = "machine-applicable", code = "=")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::use_empty_block_not_semi)]
+pub(crate) struct UseEmptyBlockNotSemi {
+    #[primary_span]
+    #[suggestion_hidden(applicability = "machine-applicable", code = "{{}}")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::comparison_interpreted_as_generic)]
+pub(crate) struct ComparisonInterpretedAsGeneric {
+    #[primary_span]
+    #[label(parser::label_comparison)]
+    pub comparison: Span,
+    pub r#type: Path,
+    #[label(parser::label_args)]
+    pub args: Span,
+    #[subdiagnostic]
+    pub suggestion: ComparisonOrShiftInterpretedAsGenericSugg,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::shift_interpreted_as_generic)]
+pub(crate) struct ShiftInterpretedAsGeneric {
+    #[primary_span]
+    #[label(parser::label_comparison)]
+    pub shift: Span,
+    pub r#type: Path,
+    #[label(parser::label_args)]
+    pub args: Span,
+    #[subdiagnostic]
+    pub suggestion: ComparisonOrShiftInterpretedAsGenericSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")]
+pub(crate) struct ComparisonOrShiftInterpretedAsGenericSugg {
+    #[suggestion_part(code = "(")]
+    pub left: Span,
+    #[suggestion_part(code = ")")]
+    pub right: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::found_expr_would_be_stmt)]
+pub(crate) struct FoundExprWouldBeStmt {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub token: Token,
+    #[subdiagnostic]
+    pub suggestion: ExprParenthesesNeeded,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::leading_plus_not_supported)]
+pub(crate) struct LeadingPlusNotSupported {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[suggestion_verbose(
+        parser::suggestion_remove_plus,
+        code = "",
+        applicability = "machine-applicable"
+    )]
+    pub remove_plus: Option<Span>,
+    #[subdiagnostic]
+    pub add_parentheses: Option<ExprParenthesesNeeded>,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::parentheses_with_struct_fields)]
+pub(crate) struct ParenthesesWithStructFields {
+    #[primary_span]
+    pub span: Span,
+    pub r#type: Path,
+    #[subdiagnostic]
+    pub braces_for_struct: BracesForStructLiteral,
+    #[subdiagnostic]
+    pub no_fields_for_fn: NoFieldsForFnCall,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(parser::suggestion_braces_for_struct, applicability = "maybe-incorrect")]
+pub(crate) struct BracesForStructLiteral {
+    #[suggestion_part(code = " {{ ")]
+    pub first: Span,
+    #[suggestion_part(code = " }}")]
+    pub second: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(parser::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)]
+pub(crate) struct LabeledLoopInBreak {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub sub: WrapExpressionInParentheses,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+    parser::sugg_wrap_expression_in_parentheses,
+    applicability = "machine-applicable"
+)]
+pub(crate) struct WrapExpressionInParentheses {
+    #[suggestion_part(code = "(")]
+    pub left: Span,
+    #[suggestion_part(code = ")")]
+    pub right: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::array_brackets_instead_of_braces)]
+pub(crate) struct ArrayBracketsInsteadOfSpaces {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub sub: ArrayBracketsInsteadOfSpacesSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(parser::suggestion, applicability = "maybe-incorrect")]
+pub(crate) struct ArrayBracketsInsteadOfSpacesSugg {
+    #[suggestion_part(code = "[")]
+    pub left: Span,
+    #[suggestion_part(code = "]")]
+    pub right: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::match_arm_body_without_braces)]
+pub(crate) struct MatchArmBodyWithoutBraces {
+    #[primary_span]
+    #[label(parser::label_statements)]
+    pub statements: Span,
+    #[label(parser::label_arrow)]
+    pub arrow: Span,
+    pub num_statements: usize,
+    #[subdiagnostic]
+    pub sub: MatchArmBodyWithoutBracesSugg,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum MatchArmBodyWithoutBracesSugg {
+    #[multipart_suggestion(parser::suggestion_add_braces, applicability = "machine-applicable")]
+    AddBraces {
+        #[suggestion_part(code = "{{ ")]
+        left: Span,
+        #[suggestion_part(code = " }}")]
+        right: Span,
+    },
+    #[suggestion(
+        parser::suggestion_use_comma_not_semicolon,
+        code = ",",
+        applicability = "machine-applicable"
+    )]
+    UseComma {
+        #[primary_span]
+        semicolon: Span,
+    },
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::struct_literal_not_allowed_here)]
+pub(crate) struct StructLiteralNotAllowedHere {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub sub: StructLiteralNotAllowedHereSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")]
+pub(crate) struct StructLiteralNotAllowedHereSugg {
+    #[suggestion_part(code = "(")]
+    pub left: Span,
+    #[suggestion_part(code = ")")]
+    pub right: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::invalid_interpolated_expression)]
+pub(crate) struct InvalidInterpolatedExpression {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::hexadecimal_float_literal_not_supported)]
+pub(crate) struct HexadecimalFloatLiteralNotSupported {
+    #[primary_span]
+    #[label(parser::not_supported)]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::octal_float_literal_not_supported)]
+pub(crate) struct OctalFloatLiteralNotSupported {
+    #[primary_span]
+    #[label(parser::not_supported)]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::binary_float_literal_not_supported)]
+pub(crate) struct BinaryFloatLiteralNotSupported {
+    #[primary_span]
+    #[label(parser::not_supported)]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::invalid_literal_suffix)]
+pub(crate) struct InvalidLiteralSuffix {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    // FIXME(#100717)
+    pub kind: String,
+    pub suffix: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[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)]
+    pub exception: Option<()>,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::non_string_abi_literal)]
+pub(crate) struct NonStringAbiLiteral {
+    #[primary_span]
+    #[suggestion(code = "\"C\"", applicability = "maybe-incorrect")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::mismatched_closing_delimiter)]
+pub(crate) struct MismatchedClosingDelimiter {
+    #[primary_span]
+    pub spans: Vec<Span>,
+    pub delimiter: String,
+    #[label(parser::label_unmatched)]
+    pub unmatched: Span,
+    #[label(parser::label_opening_candidate)]
+    pub opening_candidate: Option<Span>,
+    #[label(parser::label_unclosed)]
+    pub unclosed: Option<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::incorrect_visibility_restriction, code = "E0704")]
+#[help]
+pub(crate) struct IncorrectVisibilityRestriction {
+    #[primary_span]
+    #[suggestion(code = "in {inner_str}", applicability = "machine-applicable")]
+    pub span: Span,
+    pub inner_str: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::assignment_else_not_allowed)]
+pub(crate) struct AssignmentElseNotAllowed {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[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")]
+#[help]
+pub(crate) struct DocCommentDoesNotDocumentAnything {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(code = ",", applicability = "machine-applicable")]
+    pub missing_comma: Option<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::const_let_mutually_exclusive)]
+pub(crate) struct ConstLetMutuallyExclusive {
+    #[primary_span]
+    #[suggestion(code = "const", applicability = "maybe-incorrect")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::invalid_expression_in_let_else)]
+pub(crate) struct InvalidExpressionInLetElse {
+    #[primary_span]
+    pub span: Span,
+    pub operator: &'static str,
+    #[subdiagnostic]
+    pub sugg: WrapExpressionInParentheses,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::invalid_curly_in_let_else)]
+pub(crate) struct InvalidCurlyInLetElse {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub sugg: WrapExpressionInParentheses,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::compound_assignment_expression_in_let)]
+#[help]
+pub(crate) struct CompoundAssignmentExpressionInLet {
+    #[primary_span]
+    #[suggestion_short(code = "=", applicability = "maybe-incorrect")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::suffixed_literal_in_attribute)]
+#[help]
+pub(crate) struct SuffixedLiteralInAttribute {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::invalid_meta_item)]
+pub(crate) struct InvalidMetaItem {
+    #[primary_span]
+    pub span: Span,
+    pub token: Token,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion_verbose(
+    parser::sugg_escape_to_use_as_identifier,
+    applicability = "maybe-incorrect",
+    code = "r#"
+)]
+pub(crate) struct SuggEscapeToUseAsIdentifier {
+    #[primary_span]
+    pub span: Span,
+    pub ident_name: String,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(parser::sugg_remove_comma, applicability = "machine-applicable", code = "")]
+pub(crate) struct SuggRemoveComma {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum ExpectedIdentifierFound {
+    #[label(parser::expected_identifier_found_reserved_identifier)]
+    ReservedIdentifier(#[primary_span] Span),
+    #[label(parser::expected_identifier_found_keyword)]
+    Keyword(#[primary_span] Span),
+    #[label(parser::expected_identifier_found_reserved_keyword)]
+    ReservedKeyword(#[primary_span] Span),
+    #[label(parser::expected_identifier_found_doc_comment)]
+    DocComment(#[primary_span] Span),
+    #[label(parser::expected_identifier)]
+    Other(#[primary_span] Span),
+}
+
+impl ExpectedIdentifierFound {
+    pub fn new(token_descr: Option<TokenDescription>, span: Span) -> Self {
+        (match token_descr {
+            Some(TokenDescription::ReservedIdentifier) => {
+                ExpectedIdentifierFound::ReservedIdentifier
+            }
+            Some(TokenDescription::Keyword) => ExpectedIdentifierFound::Keyword,
+            Some(TokenDescription::ReservedKeyword) => ExpectedIdentifierFound::ReservedKeyword,
+            Some(TokenDescription::DocComment) => ExpectedIdentifierFound::DocComment,
+            None => ExpectedIdentifierFound::Other,
+        })(span)
+    }
+}
+
+pub(crate) struct ExpectedIdentifier {
+    pub span: Span,
+    pub token: Token,
+    pub suggest_raw: Option<SuggEscapeToUseAsIdentifier>,
+    pub suggest_remove_comma: Option<SuggRemoveComma>,
+}
+
+impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier {
+    fn into_diagnostic(
+        self,
+        handler: &'a rustc_errors::Handler,
+    ) -> rustc_errors::DiagnosticBuilder<'a, G> {
+        let token_descr = super::parser::TokenDescription::from_token(&self.token);
+
+        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
+            }
+            Some(TokenDescription::ReservedKeyword) => {
+                fluent::parser::expected_identifier_found_reserved_keyword_str
+            }
+            Some(TokenDescription::DocComment) => {
+                fluent::parser::expected_identifier_found_doc_comment_str
+            }
+            None => fluent::parser::expected_identifier_found_str,
+        });
+        diag.set_span(self.span);
+        diag.set_arg("token", self.token);
+
+        if let Some(sugg) = self.suggest_raw {
+            sugg.add_to_diagnostic(&mut diag);
+        }
+
+        ExpectedIdentifierFound::new(token_descr, self.span).add_to_diagnostic(&mut diag);
+
+        if let Some(sugg) = self.suggest_remove_comma {
+            sugg.add_to_diagnostic(&mut diag);
+        }
+
+        diag
+    }
+}
+
+pub(crate) struct ExpectedSemi {
+    pub span: Span,
+    pub token: Token,
+
+    pub unexpected_token_label: Option<Span>,
+    pub sugg: ExpectedSemiSugg,
+}
+
+impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedSemi {
+    fn into_diagnostic(
+        self,
+        handler: &'a rustc_errors::Handler,
+    ) -> rustc_errors::DiagnosticBuilder<'a, G> {
+        let token_descr = super::parser::TokenDescription::from_token(&self.token);
+
+        let mut diag = handler.struct_diagnostic(match token_descr {
+            Some(TokenDescription::ReservedIdentifier) => {
+                fluent::parser::expected_semi_found_reserved_identifier_str
+            }
+            Some(TokenDescription::Keyword) => fluent::parser::expected_semi_found_keyword_str,
+            Some(TokenDescription::ReservedKeyword) => {
+                fluent::parser::expected_semi_found_reserved_keyword_str
+            }
+            Some(TokenDescription::DocComment) => {
+                fluent::parser::expected_semi_found_doc_comment_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);
+        }
+
+        self.sugg.add_to_diagnostic(&mut diag);
+
+        diag
+    }
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum ExpectedSemiSugg {
+    #[suggestion(
+        parser::sugg_change_this_to_semi,
+        code = ";",
+        applicability = "machine-applicable"
+    )]
+    ChangeToSemi(#[primary_span] Span),
+    #[suggestion_short(parser::sugg_add_semi, code = ";", applicability = "machine-applicable")]
+    AddSemi(#[primary_span] Span),
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::struct_literal_body_without_path)]
+pub(crate) struct StructLiteralBodyWithoutPath {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub sugg: StructLiteralBodyWithoutPathSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(parser::suggestion, applicability = "has-placeholders")]
+pub(crate) struct StructLiteralBodyWithoutPathSugg {
+    #[suggestion_part(code = "{{ SomeStruct ")]
+    pub before: Span,
+    #[suggestion_part(code = " }}")]
+    pub after: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::unmatched_angle_brackets)]
+pub(crate) struct UnmatchedAngleBrackets {
+    #[primary_span]
+    #[suggestion(code = "", applicability = "machine-applicable")]
+    pub span: Span,
+    pub num_extra_brackets: usize,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::generic_parameters_without_angle_brackets)]
+pub(crate) struct GenericParamsWithoutAngleBrackets {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub sugg: GenericParamsWithoutAngleBracketsSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")]
+pub(crate) struct GenericParamsWithoutAngleBracketsSugg {
+    #[suggestion_part(code = "<")]
+    pub left: Span,
+    #[suggestion_part(code = ">")]
+    pub right: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::comparison_operators_cannot_be_chained)]
+pub(crate) struct ComparisonOperatorsCannotBeChained {
+    #[primary_span]
+    pub span: Vec<Span>,
+    #[suggestion_verbose(
+        parser::sugg_turbofish_syntax,
+        code = "::",
+        applicability = "maybe-incorrect"
+    )]
+    pub suggest_turbofish: Option<Span>,
+    #[help(parser::sugg_turbofish_syntax)]
+    #[help(parser::sugg_parentheses_for_function_args)]
+    pub help_turbofish: Option<()>,
+    #[subdiagnostic]
+    pub chaining_sugg: Option<ComparisonOperatorsCannotBeChainedSugg>,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum ComparisonOperatorsCannotBeChainedSugg {
+    #[suggestion_verbose(
+        parser::sugg_split_comparison,
+        code = " && {middle_term}",
+        applicability = "maybe-incorrect"
+    )]
+    SplitComparison {
+        #[primary_span]
+        span: Span,
+        middle_term: String,
+    },
+    #[multipart_suggestion(parser::sugg_parenthesize, applicability = "maybe-incorrect")]
+    Parenthesize {
+        #[suggestion_part(code = "(")]
+        left: Span,
+        #[suggestion_part(code = ")")]
+        right: Span,
+    },
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::question_mark_in_type)]
+pub(crate) struct QuestionMarkInType {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[subdiagnostic]
+    pub sugg: QuestionMarkInTypeSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")]
+pub(crate) struct QuestionMarkInTypeSugg {
+    #[suggestion_part(code = "Option<")]
+    pub left: Span,
+    #[suggestion_part(code = ">")]
+    pub right: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::unexpected_parentheses_in_for_head)]
+pub(crate) struct ParenthesesInForHead {
+    #[primary_span]
+    pub span: Vec<Span>,
+    #[subdiagnostic]
+    pub sugg: ParenthesesInForHeadSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")]
+pub(crate) struct ParenthesesInForHeadSugg {
+    #[suggestion_part(code = "")]
+    pub left: Span,
+    #[suggestion_part(code = "")]
+    pub right: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::doc_comment_on_param_type)]
+pub(crate) struct DocCommentOnParamType {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::attribute_on_param_type)]
+pub(crate) struct AttributeOnParamType {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::pattern_method_param_without_body, code = "E0642")]
+pub(crate) struct PatternMethodParamWithoutBody {
+    #[primary_span]
+    #[suggestion(code = "_", applicability = "machine-applicable")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::self_param_not_first)]
+pub(crate) struct SelfParamNotFirst {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::const_generic_without_braces)]
+pub(crate) struct ConstGenericWithoutBraces {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub sugg: ConstGenericWithoutBracesSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")]
+pub(crate) struct ConstGenericWithoutBracesSugg {
+    #[suggestion_part(code = "{{ ")]
+    pub left: Span,
+    #[suggestion_part(code = " }}")]
+    pub right: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::unexpected_const_param_declaration)]
+pub(crate) struct UnexpectedConstParamDeclaration {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[subdiagnostic]
+    pub sugg: Option<UnexpectedConstParamDeclarationSugg>,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum UnexpectedConstParamDeclarationSugg {
+    #[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")]
+    AddParam {
+        #[suggestion_part(code = "<{snippet}>")]
+        impl_generics: Span,
+        #[suggestion_part(code = "{ident}")]
+        incorrect_decl: Span,
+        snippet: String,
+        ident: String,
+    },
+    #[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")]
+    AppendParam {
+        #[suggestion_part(code = ", {snippet}")]
+        impl_generics_end: Span,
+        #[suggestion_part(code = "{ident}")]
+        incorrect_decl: Span,
+        snippet: String,
+        ident: String,
+    },
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::unexpected_const_in_generic_param)]
+pub(crate) struct UnexpectedConstInGenericParam {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion_verbose(code = "", applicability = "maybe-incorrect")]
+    pub to_remove: Option<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::async_move_order_incorrect)]
+pub(crate) struct AsyncMoveOrderIncorrect {
+    #[primary_span]
+    #[suggestion_verbose(code = "async move", applicability = "maybe-incorrect")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser::double_colon_in_bound)]
+pub(crate) struct DoubleColonInBound {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(code = ": ", applicability = "machine-applicable")]
+    pub between: Span,
+}
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 63819a2f98d..bcd078a8967 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -1,10 +1,11 @@
 use crate::lexer::unicode_chars::UNICODE_ARRAY;
 use rustc_ast::ast::{self, AttrStyle};
 use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind};
-use rustc_ast::tokenstream::{Spacing, TokenStream};
+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_lexer::unescape::{self, Mode};
+use rustc_lexer::Cursor;
 use rustc_lexer::{Base, DocStyle, RawStrError};
 use rustc_session::lint::builtin::{
     RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
@@ -38,11 +39,20 @@ pub struct UnmatchedBrace {
 
 pub(crate) fn parse_token_trees<'a>(
     sess: &'a ParseSess,
-    src: &'a str,
-    start_pos: BytePos,
+    mut src: &'a str,
+    mut start_pos: BytePos,
     override_span: Option<Span>,
 ) -> (PResult<'a, TokenStream>, Vec<UnmatchedBrace>) {
-    StringReader { sess, start_pos, pos: start_pos, src, override_span }.into_token_trees()
+    // Skip `#!`, if present.
+    if let Some(shebang_len) = rustc_lexer::strip_shebang(src) {
+        src = &src[shebang_len..];
+        start_pos = start_pos + BytePos::from_usize(shebang_len);
+    }
+
+    let cursor = Cursor::new(src);
+    let string_reader =
+        StringReader { sess, start_pos, pos: start_pos, src, cursor, override_span };
+    tokentrees::TokenTreesReader::parse_token_trees(string_reader)
 }
 
 struct StringReader<'a> {
@@ -53,6 +63,8 @@ struct StringReader<'a> {
     pos: BytePos,
     /// Source text to tokenize.
     src: &'a str,
+    /// Cursor for getting lexer tokens.
+    cursor: Cursor<'a>,
     override_span: Option<Span>,
 }
 
@@ -61,42 +73,195 @@ impl<'a> StringReader<'a> {
         self.override_span.unwrap_or_else(|| Span::with_root_ctxt(lo, hi))
     }
 
-    /// Returns the next token, and info about preceding whitespace, if any.
-    fn next_token(&mut self) -> (Spacing, Token) {
-        let mut spacing = Spacing::Joint;
-
-        // Skip `#!` at the start of the file
-        if self.pos == self.start_pos
-            && let Some(shebang_len) = rustc_lexer::strip_shebang(self.src)
-        {
-            self.pos = self.pos + BytePos::from_usize(shebang_len);
-            spacing = Spacing::Alone;
-        }
+    /// Returns the next token, paired with a bool indicating if the token was
+    /// preceded by whitespace.
+    fn next_token(&mut self) -> (Token, bool) {
+        let mut preceded_by_whitespace = false;
 
         // Skip trivial (whitespace & comments) tokens
         loop {
-            let start_src_index = self.src_index(self.pos);
-            let text: &str = &self.src[start_src_index..];
-
-            if text.is_empty() {
-                let span = self.mk_sp(self.pos, self.pos);
-                return (spacing, Token::new(token::Eof, span));
-            }
-
-            let token = rustc_lexer::first_token(text);
-
+            let token = self.cursor.advance_token();
             let start = self.pos;
             self.pos = self.pos + BytePos(token.len);
 
             debug!("next_token: {:?}({:?})", token.kind, self.str_from(start));
 
-            match self.cook_lexer_token(token.kind, start) {
-                Some(kind) => {
+            // Now "cook" the token, converting the simple `rustc_lexer::TokenKind` enum into a
+            // rich `rustc_ast::TokenKind`. This turns strings into interned symbols and runs
+            // additional validation.
+            let kind = match token.kind {
+                rustc_lexer::TokenKind::LineComment { doc_style } => {
+                    // Skip non-doc comments
+                    let Some(doc_style) = doc_style else {
+                        self.lint_unicode_text_flow(start);
+                        preceded_by_whitespace = true;
+                        continue;
+                    };
+
+                    // Opening delimiter of the length 3 is not included into the symbol.
+                    let content_start = start + BytePos(3);
+                    let content = self.str_from(content_start);
+                    self.cook_doc_comment(content_start, content, CommentKind::Line, doc_style)
+                }
+                rustc_lexer::TokenKind::BlockComment { doc_style, terminated } => {
+                    if !terminated {
+                        self.report_unterminated_block_comment(start, doc_style);
+                    }
+
+                    // Skip non-doc comments
+                    let Some(doc_style) = doc_style else {
+                        self.lint_unicode_text_flow(start);
+                        preceded_by_whitespace = true;
+                        continue;
+                    };
+
+                    // Opening delimiter of the length 3 and closing delimiter of the length 2
+                    // are not included into the symbol.
+                    let content_start = start + BytePos(3);
+                    let content_end = self.pos - BytePos(if terminated { 2 } else { 0 });
+                    let content = self.str_from_to(content_start, content_end);
+                    self.cook_doc_comment(content_start, content, CommentKind::Block, doc_style)
+                }
+                rustc_lexer::TokenKind::Whitespace => {
+                    preceded_by_whitespace = true;
+                    continue;
+                }
+                rustc_lexer::TokenKind::Ident => {
+                    let sym = nfc_normalize(self.str_from(start));
                     let span = self.mk_sp(start, self.pos);
-                    return (spacing, Token::new(kind, span));
+                    self.sess.symbol_gallery.insert(sym, span);
+                    token::Ident(sym, false)
                 }
-                None => spacing = Spacing::Alone,
-            }
+                rustc_lexer::TokenKind::RawIdent => {
+                    let sym = nfc_normalize(self.str_from(start + BytePos(2)));
+                    let span = self.mk_sp(start, self.pos);
+                    self.sess.symbol_gallery.insert(sym, span);
+                    if !sym.can_be_raw() {
+                        self.err_span(span, &format!("`{}` cannot be a raw identifier", sym));
+                    }
+                    self.sess.raw_identifier_spans.borrow_mut().push(span);
+                    token::Ident(sym, true)
+                }
+                rustc_lexer::TokenKind::UnknownPrefix => {
+                    self.report_unknown_prefix(start);
+                    let sym = nfc_normalize(self.str_from(start));
+                    let span = self.mk_sp(start, self.pos);
+                    self.sess.symbol_gallery.insert(sym, span);
+                    token::Ident(sym, false)
+                }
+                rustc_lexer::TokenKind::InvalidIdent
+                    // Do not recover an identifier with emoji if the codepoint is a confusable
+                    // with a recoverable substitution token, like `âž–`.
+                    if !UNICODE_ARRAY
+                        .iter()
+                        .any(|&(c, _, _)| {
+                            let sym = self.str_from(start);
+                            sym.chars().count() == 1 && c == sym.chars().next().unwrap()
+                        }) =>
+                {
+                    let sym = nfc_normalize(self.str_from(start));
+                    let span = self.mk_sp(start, self.pos);
+                    self.sess.bad_unicode_identifiers.borrow_mut().entry(sym).or_default()
+                        .push(span);
+                    token::Ident(sym, false)
+                }
+                rustc_lexer::TokenKind::Literal { kind, suffix_start } => {
+                    let suffix_start = start + BytePos(suffix_start);
+                    let (kind, symbol) = self.cook_lexer_literal(start, suffix_start, kind);
+                    let suffix = if suffix_start < self.pos {
+                        let string = self.str_from(suffix_start);
+                        if string == "_" {
+                            self.sess
+                                .span_diagnostic
+                                .struct_span_warn(
+                                    self.mk_sp(suffix_start, self.pos),
+                                    "underscore literal suffix is not allowed",
+                                )
+                                .warn(
+                                    "this was previously accepted by the compiler but is \
+                                       being phased out; it will become a hard error in \
+                                       a future release!",
+                                )
+                                .note(
+                                    "see issue #42326 \
+                                     <https://github.com/rust-lang/rust/issues/42326> \
+                                     for more information",
+                                )
+                                .emit();
+                            None
+                        } else {
+                            Some(Symbol::intern(string))
+                        }
+                    } else {
+                        None
+                    };
+                    token::Literal(token::Lit { kind, symbol, suffix })
+                }
+                rustc_lexer::TokenKind::Lifetime { starts_with_number } => {
+                    // Include the leading `'` in the real identifier, for macro
+                    // expansion purposes. See #12512 for the gory details of why
+                    // 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 ident = Symbol::intern(lifetime_name);
+                    token::Lifetime(ident)
+                }
+                rustc_lexer::TokenKind::Semi => token::Semi,
+                rustc_lexer::TokenKind::Comma => token::Comma,
+                rustc_lexer::TokenKind::Dot => token::Dot,
+                rustc_lexer::TokenKind::OpenParen => token::OpenDelim(Delimiter::Parenthesis),
+                rustc_lexer::TokenKind::CloseParen => token::CloseDelim(Delimiter::Parenthesis),
+                rustc_lexer::TokenKind::OpenBrace => token::OpenDelim(Delimiter::Brace),
+                rustc_lexer::TokenKind::CloseBrace => token::CloseDelim(Delimiter::Brace),
+                rustc_lexer::TokenKind::OpenBracket => token::OpenDelim(Delimiter::Bracket),
+                rustc_lexer::TokenKind::CloseBracket => token::CloseDelim(Delimiter::Bracket),
+                rustc_lexer::TokenKind::At => token::At,
+                rustc_lexer::TokenKind::Pound => token::Pound,
+                rustc_lexer::TokenKind::Tilde => token::Tilde,
+                rustc_lexer::TokenKind::Question => token::Question,
+                rustc_lexer::TokenKind::Colon => token::Colon,
+                rustc_lexer::TokenKind::Dollar => token::Dollar,
+                rustc_lexer::TokenKind::Eq => token::Eq,
+                rustc_lexer::TokenKind::Bang => token::Not,
+                rustc_lexer::TokenKind::Lt => token::Lt,
+                rustc_lexer::TokenKind::Gt => token::Gt,
+                rustc_lexer::TokenKind::Minus => token::BinOp(token::Minus),
+                rustc_lexer::TokenKind::And => token::BinOp(token::And),
+                rustc_lexer::TokenKind::Or => token::BinOp(token::Or),
+                rustc_lexer::TokenKind::Plus => token::BinOp(token::Plus),
+                rustc_lexer::TokenKind::Star => token::BinOp(token::Star),
+                rustc_lexer::TokenKind::Slash => token::BinOp(token::Slash),
+                rustc_lexer::TokenKind::Caret => token::BinOp(token::Caret),
+                rustc_lexer::TokenKind::Percent => token::BinOp(token::Percent),
+
+                rustc_lexer::TokenKind::Unknown | rustc_lexer::TokenKind::InvalidIdent => {
+                    let c = self.str_from(start).chars().next().unwrap();
+                    let mut err =
+                        self.struct_err_span_char(start, self.pos, "unknown start of token", c);
+                    // FIXME: the lexer could be used to turn the ASCII version of unicode
+                    // homoglyphs, instead of keeping a table in `check_for_substitution`into the
+                    // token. Ideally, this should be inside `rustc_lexer`. However, we should
+                    // first remove compound tokens like `<<` from `rustc_lexer`, and then add
+                    // fancier error recovery to it, as there will be less overall work to do this
+                    // way.
+                    let token = unicode_chars::check_for_substitution(self, start, c, &mut err);
+                    if c == '\x00' {
+                        err.help("source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used");
+                    }
+                    err.emit();
+                    if let Some(token) = token {
+                        token
+                    } else {
+                        preceded_by_whitespace = true;
+                        continue;
+                    }
+                }
+                rustc_lexer::TokenKind::Eof => token::Eof,
+            };
+            let span = self.mk_sp(start, self.pos);
+            return (Token::new(kind, span), preceded_by_whitespace);
         }
     }
 
@@ -162,171 +327,6 @@ impl<'a> StringReader<'a> {
         }
     }
 
-    /// Turns simple `rustc_lexer::TokenKind` enum into a rich
-    /// `rustc_ast::TokenKind`. This turns strings into interned
-    /// symbols and runs additional validation.
-    fn cook_lexer_token(&self, token: rustc_lexer::TokenKind, start: BytePos) -> Option<TokenKind> {
-        Some(match token {
-            rustc_lexer::TokenKind::LineComment { doc_style } => {
-                // Skip non-doc comments
-                let Some(doc_style) = doc_style else {
-                    self.lint_unicode_text_flow(start);
-                    return None;
-                };
-
-                // Opening delimiter of the length 3 is not included into the symbol.
-                let content_start = start + BytePos(3);
-                let content = self.str_from(content_start);
-                self.cook_doc_comment(content_start, content, CommentKind::Line, doc_style)
-            }
-            rustc_lexer::TokenKind::BlockComment { doc_style, terminated } => {
-                if !terminated {
-                    self.report_unterminated_block_comment(start, doc_style);
-                }
-
-                // Skip non-doc comments
-                let Some(doc_style) = doc_style else {
-                    self.lint_unicode_text_flow(start);
-                    return None;
-                };
-
-                // Opening delimiter of the length 3 and closing delimiter of the length 2
-                // are not included into the symbol.
-                let content_start = start + BytePos(3);
-                let content_end = self.pos - BytePos(if terminated { 2 } else { 0 });
-                let content = self.str_from_to(content_start, content_end);
-                self.cook_doc_comment(content_start, content, CommentKind::Block, doc_style)
-            }
-            rustc_lexer::TokenKind::Whitespace => return None,
-            rustc_lexer::TokenKind::Ident
-            | rustc_lexer::TokenKind::RawIdent
-            | rustc_lexer::TokenKind::UnknownPrefix => {
-                let is_raw_ident = token == rustc_lexer::TokenKind::RawIdent;
-                let is_unknown_prefix = token == rustc_lexer::TokenKind::UnknownPrefix;
-                let mut ident_start = start;
-                if is_raw_ident {
-                    ident_start = ident_start + BytePos(2);
-                }
-                if is_unknown_prefix {
-                    self.report_unknown_prefix(start);
-                }
-                let sym = nfc_normalize(self.str_from(ident_start));
-                let span = self.mk_sp(start, self.pos);
-                self.sess.symbol_gallery.insert(sym, span);
-                if is_raw_ident {
-                    if !sym.can_be_raw() {
-                        self.err_span(span, &format!("`{}` cannot be a raw identifier", sym));
-                    }
-                    self.sess.raw_identifier_spans.borrow_mut().push(span);
-                }
-                token::Ident(sym, is_raw_ident)
-            }
-            rustc_lexer::TokenKind::InvalidIdent
-                // Do not recover an identifier with emoji if the codepoint is a confusable
-                // with a recoverable substitution token, like `âž–`.
-                if !UNICODE_ARRAY
-                    .iter()
-                    .any(|&(c, _, _)| {
-                        let sym = self.str_from(start);
-                        sym.chars().count() == 1 && c == sym.chars().next().unwrap()
-                    })
-                     =>
-            {
-                let sym = nfc_normalize(self.str_from(start));
-                let span = self.mk_sp(start, self.pos);
-                self.sess.bad_unicode_identifiers.borrow_mut().entry(sym).or_default().push(span);
-                token::Ident(sym, false)
-            }
-            rustc_lexer::TokenKind::Literal { kind, suffix_start } => {
-                let suffix_start = start + BytePos(suffix_start);
-                let (kind, symbol) = self.cook_lexer_literal(start, suffix_start, kind);
-                let suffix = if suffix_start < self.pos {
-                    let string = self.str_from(suffix_start);
-                    if string == "_" {
-                        self.sess
-                            .span_diagnostic
-                            .struct_span_warn(
-                                self.mk_sp(suffix_start, self.pos),
-                                "underscore literal suffix is not allowed",
-                            )
-                            .warn(
-                                "this was previously accepted by the compiler but is \
-                                   being phased out; it will become a hard error in \
-                                   a future release!",
-                            )
-                            .note(
-                                "see issue #42326 \
-                                 <https://github.com/rust-lang/rust/issues/42326> \
-                                 for more information",
-                            )
-                            .emit();
-                        None
-                    } else {
-                        Some(Symbol::intern(string))
-                    }
-                } else {
-                    None
-                };
-                token::Literal(token::Lit { kind, symbol, suffix })
-            }
-            rustc_lexer::TokenKind::Lifetime { starts_with_number } => {
-                // Include the leading `'` in the real identifier, for macro
-                // expansion purposes. See #12512 for the gory details of why
-                // 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 ident = Symbol::intern(lifetime_name);
-                token::Lifetime(ident)
-            }
-            rustc_lexer::TokenKind::Semi => token::Semi,
-            rustc_lexer::TokenKind::Comma => token::Comma,
-            rustc_lexer::TokenKind::Dot => token::Dot,
-            rustc_lexer::TokenKind::OpenParen => token::OpenDelim(Delimiter::Parenthesis),
-            rustc_lexer::TokenKind::CloseParen => token::CloseDelim(Delimiter::Parenthesis),
-            rustc_lexer::TokenKind::OpenBrace => token::OpenDelim(Delimiter::Brace),
-            rustc_lexer::TokenKind::CloseBrace => token::CloseDelim(Delimiter::Brace),
-            rustc_lexer::TokenKind::OpenBracket => token::OpenDelim(Delimiter::Bracket),
-            rustc_lexer::TokenKind::CloseBracket => token::CloseDelim(Delimiter::Bracket),
-            rustc_lexer::TokenKind::At => token::At,
-            rustc_lexer::TokenKind::Pound => token::Pound,
-            rustc_lexer::TokenKind::Tilde => token::Tilde,
-            rustc_lexer::TokenKind::Question => token::Question,
-            rustc_lexer::TokenKind::Colon => token::Colon,
-            rustc_lexer::TokenKind::Dollar => token::Dollar,
-            rustc_lexer::TokenKind::Eq => token::Eq,
-            rustc_lexer::TokenKind::Bang => token::Not,
-            rustc_lexer::TokenKind::Lt => token::Lt,
-            rustc_lexer::TokenKind::Gt => token::Gt,
-            rustc_lexer::TokenKind::Minus => token::BinOp(token::Minus),
-            rustc_lexer::TokenKind::And => token::BinOp(token::And),
-            rustc_lexer::TokenKind::Or => token::BinOp(token::Or),
-            rustc_lexer::TokenKind::Plus => token::BinOp(token::Plus),
-            rustc_lexer::TokenKind::Star => token::BinOp(token::Star),
-            rustc_lexer::TokenKind::Slash => token::BinOp(token::Slash),
-            rustc_lexer::TokenKind::Caret => token::BinOp(token::Caret),
-            rustc_lexer::TokenKind::Percent => token::BinOp(token::Percent),
-
-            rustc_lexer::TokenKind::Unknown | rustc_lexer::TokenKind::InvalidIdent => {
-                let c = self.str_from(start).chars().next().unwrap();
-                let mut err =
-                    self.struct_err_span_char(start, self.pos, "unknown start of token", c);
-                // FIXME: the lexer could be used to turn the ASCII version of unicode homoglyphs,
-                // instead of keeping a table in `check_for_substitution`into the token. Ideally,
-                // this should be inside `rustc_lexer`. However, we should first remove compound
-                // tokens like `<<` from `rustc_lexer`, and then add fancier error recovery to it,
-                // as there will be less overall work to do this way.
-                let token = unicode_chars::check_for_substitution(self, start, c, &mut err);
-                if c == '\x00' {
-                    err.help("source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used");
-                }
-                err.emit();
-                token?
-            }
-        })
-    }
-
     fn cook_doc_comment(
         &self,
         content_start: BytePos,
diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs
index aa70912dcde..364753154db 100644
--- a/compiler/rustc_parse/src/lexer/tokentrees.rs
+++ b/compiler/rustc_parse/src/lexer/tokentrees.rs
@@ -1,31 +1,15 @@
 use super::{StringReader, UnmatchedBrace};
-
 use rustc_ast::token::{self, Delimiter, Token};
 use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenStream, TokenTree};
 use rustc_ast_pretty::pprust::token_to_string;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::PResult;
+use rustc_errors::{PErr, PResult};
 use rustc_span::Span;
 
-impl<'a> StringReader<'a> {
-    pub(super) fn into_token_trees(self) -> (PResult<'a, TokenStream>, Vec<UnmatchedBrace>) {
-        let mut tt_reader = TokenTreesReader {
-            string_reader: self,
-            token: Token::dummy(),
-            open_braces: Vec::new(),
-            unmatched_braces: Vec::new(),
-            matching_delim_spans: Vec::new(),
-            last_unclosed_found_span: None,
-            last_delim_empty_block_spans: FxHashMap::default(),
-            matching_block_spans: Vec::new(),
-        };
-        let res = tt_reader.parse_all_token_trees();
-        (res, tt_reader.unmatched_braces)
-    }
-}
-
-struct TokenTreesReader<'a> {
+pub(super) struct TokenTreesReader<'a> {
     string_reader: StringReader<'a>,
+    /// The "next" token, which has been obtained from the `StringReader` but
+    /// not yet handled by the `TokenTreesReader`.
     token: Token,
     /// Stack of open delimiters and their spans. Used for error message.
     open_braces: Vec<(Delimiter, Span)>,
@@ -43,231 +27,235 @@ struct TokenTreesReader<'a> {
 }
 
 impl<'a> TokenTreesReader<'a> {
+    pub(super) fn parse_token_trees(
+        string_reader: StringReader<'a>,
+    ) -> (PResult<'a, TokenStream>, Vec<UnmatchedBrace>) {
+        let mut tt_reader = TokenTreesReader {
+            string_reader,
+            token: Token::dummy(),
+            open_braces: Vec::new(),
+            unmatched_braces: Vec::new(),
+            matching_delim_spans: Vec::new(),
+            last_unclosed_found_span: None,
+            last_delim_empty_block_spans: FxHashMap::default(),
+            matching_block_spans: Vec::new(),
+        };
+        let res = tt_reader.parse_all_token_trees();
+        (res, tt_reader.unmatched_braces)
+    }
+
     // Parse a stream of tokens into a list of `TokenTree`s, up to an `Eof`.
     fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> {
+        self.token = self.string_reader.next_token().0;
         let mut buf = TokenStreamBuilder::default();
-
-        self.bump();
-        while self.token != token::Eof {
-            buf.push(self.parse_token_tree()?);
+        loop {
+            match self.token.kind {
+                token::OpenDelim(delim) => buf.push(self.parse_token_tree_open_delim(delim)),
+                token::CloseDelim(delim) => return Err(self.close_delim_err(delim)),
+                token::Eof => return Ok(buf.into_token_stream()),
+                _ => buf.push(self.parse_token_tree_non_delim_non_eof()),
+            }
         }
-
-        Ok(buf.into_token_stream())
     }
 
     // Parse a stream of tokens into a list of `TokenTree`s, up to a `CloseDelim`.
     fn parse_token_trees_until_close_delim(&mut self) -> TokenStream {
         let mut buf = TokenStreamBuilder::default();
         loop {
-            if let token::CloseDelim(..) = self.token.kind {
-                return buf.into_token_stream();
-            }
-
-            match self.parse_token_tree() {
-                Ok(tree) => buf.push(tree),
-                Err(mut e) => {
-                    e.emit();
+            match self.token.kind {
+                token::OpenDelim(delim) => buf.push(self.parse_token_tree_open_delim(delim)),
+                token::CloseDelim(..) => return buf.into_token_stream(),
+                token::Eof => {
+                    self.eof_err().emit();
                     return buf.into_token_stream();
                 }
+                _ => buf.push(self.parse_token_tree_non_delim_non_eof()),
             }
         }
     }
 
-    fn parse_token_tree(&mut self) -> PResult<'a, TokenTree> {
-        let sm = self.string_reader.sess.source_map();
-
-        match self.token.kind {
-            token::Eof => {
-                let msg = "this file contains an unclosed delimiter";
-                let mut err =
-                    self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, msg);
-                for &(_, sp) in &self.open_braces {
-                    err.span_label(sp, "unclosed delimiter");
-                    self.unmatched_braces.push(UnmatchedBrace {
-                        expected_delim: Delimiter::Brace,
-                        found_delim: None,
-                        found_span: self.token.span,
-                        unclosed_span: Some(sp),
-                        candidate_span: None,
-                    });
-                }
+    fn eof_err(&mut self) -> PErr<'a> {
+        let msg = "this file contains an unclosed delimiter";
+        let mut err = self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, msg);
+        for &(_, sp) in &self.open_braces {
+            err.span_label(sp, "unclosed delimiter");
+            self.unmatched_braces.push(UnmatchedBrace {
+                expected_delim: Delimiter::Brace,
+                found_delim: None,
+                found_span: self.token.span,
+                unclosed_span: Some(sp),
+                candidate_span: None,
+            });
+        }
 
-                if let Some((delim, _)) = self.open_braces.last() {
-                    if let Some((_, open_sp, close_sp)) =
-                        self.matching_delim_spans.iter().find(|(d, open_sp, close_sp)| {
-                            if let Some(close_padding) = sm.span_to_margin(*close_sp) {
-                                if let Some(open_padding) = sm.span_to_margin(*open_sp) {
-                                    return delim == d && close_padding != open_padding;
-                                }
-                            }
-                            false
-                        })
-                    // these are in reverse order as they get inserted on close, but
-                    {
-                        // we want the last open/first close
-                        err.span_label(*open_sp, "this delimiter might not be properly closed...");
-                        err.span_label(
-                            *close_sp,
-                            "...as it matches this but it has different indentation",
-                        );
+        if let Some((delim, _)) = self.open_braces.last() {
+            if let Some((_, open_sp, close_sp)) =
+                self.matching_delim_spans.iter().find(|(d, open_sp, close_sp)| {
+                    let sm = self.string_reader.sess.source_map();
+                    if let Some(close_padding) = sm.span_to_margin(*close_sp) {
+                        if let Some(open_padding) = sm.span_to_margin(*open_sp) {
+                            return delim == d && close_padding != open_padding;
+                        }
                     }
-                }
-                Err(err)
+                    false
+                })
+            // these are in reverse order as they get inserted on close, but
+            {
+                // we want the last open/first close
+                err.span_label(*open_sp, "this delimiter might not be properly closed...");
+                err.span_label(*close_sp, "...as it matches this but it has different indentation");
             }
-            token::OpenDelim(delim) => {
-                // The span for beginning of the delimited section
-                let pre_span = self.token.span;
-
-                // Parse the open delimiter.
-                self.open_braces.push((delim, self.token.span));
-                self.bump();
+        }
+        err
+    }
 
-                // Parse the token trees within the delimiters.
-                // We stop at any delimiter so we can try to recover if the user
-                // uses an incorrect delimiter.
-                let tts = self.parse_token_trees_until_close_delim();
+    fn parse_token_tree_open_delim(&mut self, open_delim: Delimiter) -> TokenTree {
+        // The span for beginning of the delimited section
+        let pre_span = self.token.span;
 
-                // Expand to cover the entire delimited token tree
-                let delim_span = DelimSpan::from_pair(pre_span, self.token.span);
+        // Move past the open delimiter.
+        self.open_braces.push((open_delim, self.token.span));
+        self.token = self.string_reader.next_token().0;
 
-                match self.token.kind {
-                    // Correct delimiter.
-                    token::CloseDelim(d) if d == delim => {
-                        let (open_brace, open_brace_span) = self.open_braces.pop().unwrap();
-                        let close_brace_span = self.token.span;
+        // Parse the token trees within the delimiters.
+        // We stop at any delimiter so we can try to recover if the user
+        // uses an incorrect delimiter.
+        let tts = self.parse_token_trees_until_close_delim();
 
-                        if tts.is_empty() {
-                            let empty_block_span = open_brace_span.to(close_brace_span);
-                            if !sm.is_multiline(empty_block_span) {
-                                // Only track if the block is in the form of `{}`, otherwise it is
-                                // likely that it was written on purpose.
-                                self.last_delim_empty_block_spans.insert(delim, empty_block_span);
-                            }
-                        }
+        // Expand to cover the entire delimited token tree
+        let delim_span = DelimSpan::from_pair(pre_span, self.token.span);
 
-                        //only add braces
-                        if let (Delimiter::Brace, Delimiter::Brace) = (open_brace, delim) {
-                            self.matching_block_spans.push((open_brace_span, close_brace_span));
-                        }
+        match self.token.kind {
+            // Correct delimiter.
+            token::CloseDelim(close_delim) if close_delim == open_delim => {
+                let (open_brace, open_brace_span) = self.open_braces.pop().unwrap();
+                let close_brace_span = self.token.span;
 
-                        if self.open_braces.is_empty() {
-                            // Clear up these spans to avoid suggesting them as we've found
-                            // properly matched delimiters so far for an entire block.
-                            self.matching_delim_spans.clear();
-                        } else {
-                            self.matching_delim_spans.push((
-                                open_brace,
-                                open_brace_span,
-                                close_brace_span,
-                            ));
-                        }
-                        // Parse the closing delimiter.
-                        self.bump();
+                if tts.is_empty() {
+                    let empty_block_span = open_brace_span.to(close_brace_span);
+                    let sm = self.string_reader.sess.source_map();
+                    if !sm.is_multiline(empty_block_span) {
+                        // Only track if the block is in the form of `{}`, otherwise it is
+                        // likely that it was written on purpose.
+                        self.last_delim_empty_block_spans.insert(open_delim, empty_block_span);
                     }
-                    // Incorrect delimiter.
-                    token::CloseDelim(other) => {
-                        let mut unclosed_delimiter = None;
-                        let mut candidate = None;
+                }
+
+                //only add braces
+                if let (Delimiter::Brace, Delimiter::Brace) = (open_brace, open_delim) {
+                    self.matching_block_spans.push((open_brace_span, close_brace_span));
+                }
+
+                if self.open_braces.is_empty() {
+                    // Clear up these spans to avoid suggesting them as we've found
+                    // properly matched delimiters so far for an entire block.
+                    self.matching_delim_spans.clear();
+                } else {
+                    self.matching_delim_spans.push((open_brace, open_brace_span, close_brace_span));
+                }
+                // Move past the closing delimiter.
+                self.token = self.string_reader.next_token().0;
+            }
+            // Incorrect delimiter.
+            token::CloseDelim(close_delim) => {
+                let mut unclosed_delimiter = None;
+                let mut candidate = None;
 
-                        if self.last_unclosed_found_span != Some(self.token.span) {
-                            // do not complain about the same unclosed delimiter multiple times
-                            self.last_unclosed_found_span = Some(self.token.span);
-                            // This is a conservative error: only report the last unclosed
-                            // delimiter. The previous unclosed delimiters could actually be
-                            // closed! The parser just hasn't gotten to them yet.
-                            if let Some(&(_, sp)) = self.open_braces.last() {
-                                unclosed_delimiter = Some(sp);
-                            };
-                            if let Some(current_padding) = sm.span_to_margin(self.token.span) {
-                                for (brace, brace_span) in &self.open_braces {
-                                    if let Some(padding) = sm.span_to_margin(*brace_span) {
-                                        // high likelihood of these two corresponding
-                                        if current_padding == padding && brace == &other {
-                                            candidate = Some(*brace_span);
-                                        }
-                                    }
+                if self.last_unclosed_found_span != Some(self.token.span) {
+                    // do not complain about the same unclosed delimiter multiple times
+                    self.last_unclosed_found_span = Some(self.token.span);
+                    // This is a conservative error: only report the last unclosed
+                    // delimiter. The previous unclosed delimiters could actually be
+                    // closed! The parser just hasn't gotten to them yet.
+                    if let Some(&(_, sp)) = self.open_braces.last() {
+                        unclosed_delimiter = Some(sp);
+                    };
+                    let sm = self.string_reader.sess.source_map();
+                    if let Some(current_padding) = sm.span_to_margin(self.token.span) {
+                        for (brace, brace_span) in &self.open_braces {
+                            if let Some(padding) = sm.span_to_margin(*brace_span) {
+                                // high likelihood of these two corresponding
+                                if current_padding == padding && brace == &close_delim {
+                                    candidate = Some(*brace_span);
                                 }
                             }
-                            let (tok, _) = self.open_braces.pop().unwrap();
-                            self.unmatched_braces.push(UnmatchedBrace {
-                                expected_delim: tok,
-                                found_delim: Some(other),
-                                found_span: self.token.span,
-                                unclosed_span: unclosed_delimiter,
-                                candidate_span: candidate,
-                            });
-                        } else {
-                            self.open_braces.pop();
                         }
-
-                        // If the incorrect delimiter matches an earlier opening
-                        // delimiter, then don't consume it (it can be used to
-                        // close the earlier one). Otherwise, consume it.
-                        // E.g., we try to recover from:
-                        // fn foo() {
-                        //     bar(baz(
-                        // }  // Incorrect delimiter but matches the earlier `{`
-                        if !self.open_braces.iter().any(|&(b, _)| b == other) {
-                            self.bump();
-                        }
-                    }
-                    token::Eof => {
-                        // Silently recover, the EOF token will be seen again
-                        // and an error emitted then. Thus we don't pop from
-                        // self.open_braces here.
                     }
-                    _ => {}
+                    let (tok, _) = self.open_braces.pop().unwrap();
+                    self.unmatched_braces.push(UnmatchedBrace {
+                        expected_delim: tok,
+                        found_delim: Some(close_delim),
+                        found_span: self.token.span,
+                        unclosed_span: unclosed_delimiter,
+                        candidate_span: candidate,
+                    });
+                } else {
+                    self.open_braces.pop();
                 }
 
-                Ok(TokenTree::Delimited(delim_span, delim, tts))
+                // If the incorrect delimiter matches an earlier opening
+                // delimiter, then don't consume it (it can be used to
+                // close the earlier one). Otherwise, consume it.
+                // E.g., we try to recover from:
+                // fn foo() {
+                //     bar(baz(
+                // }  // Incorrect delimiter but matches the earlier `{`
+                if !self.open_braces.iter().any(|&(b, _)| b == close_delim) {
+                    self.token = self.string_reader.next_token().0;
+                }
             }
-            token::CloseDelim(delim) => {
-                // An unexpected closing delimiter (i.e., there is no
-                // matching opening delimiter).
-                let token_str = token_to_string(&self.token);
-                let msg = format!("unexpected closing delimiter: `{}`", token_str);
-                let mut err =
-                    self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, &msg);
-
-                // Braces are added at the end, so the last element is the biggest block
-                if let Some(parent) = self.matching_block_spans.last() {
-                    if let Some(span) = self.last_delim_empty_block_spans.remove(&delim) {
-                        // Check if the (empty block) is in the last properly closed block
-                        if (parent.0.to(parent.1)).contains(span) {
-                            err.span_label(
-                                span,
-                                "block is empty, you might have not meant to close it",
-                            );
-                        } else {
-                            err.span_label(parent.0, "this opening brace...");
+            token::Eof => {
+                // Silently recover, the EOF token will be seen again
+                // and an error emitted then. Thus we don't pop from
+                // self.open_braces here.
+            }
+            _ => unreachable!(),
+        }
 
-                            err.span_label(parent.1, "...matches this closing brace");
-                        }
-                    } else {
-                        err.span_label(parent.0, "this opening brace...");
+        TokenTree::Delimited(delim_span, open_delim, tts)
+    }
 
-                        err.span_label(parent.1, "...matches this closing brace");
-                    }
-                }
+    fn close_delim_err(&mut self, delim: Delimiter) -> PErr<'a> {
+        // An unexpected closing delimiter (i.e., there is no
+        // matching opening delimiter).
+        let token_str = token_to_string(&self.token);
+        let msg = format!("unexpected closing delimiter: `{}`", token_str);
+        let mut err =
+            self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, &msg);
 
-                err.span_label(self.token.span, "unexpected closing delimiter");
-                Err(err)
-            }
-            _ => {
-                let tok = self.token.take();
-                let mut spacing = self.bump();
-                if !self.token.is_op() {
-                    spacing = Spacing::Alone;
+        // Braces are added at the end, so the last element is the biggest block
+        if let Some(parent) = self.matching_block_spans.last() {
+            if let Some(span) = self.last_delim_empty_block_spans.remove(&delim) {
+                // Check if the (empty block) is in the last properly closed block
+                if (parent.0.to(parent.1)).contains(span) {
+                    err.span_label(span, "block is empty, you might have not meant to close it");
+                } else {
+                    err.span_label(parent.0, "this opening brace...");
+                    err.span_label(parent.1, "...matches this closing brace");
                 }
-                Ok(TokenTree::Token(tok, spacing))
+            } else {
+                err.span_label(parent.0, "this opening brace...");
+                err.span_label(parent.1, "...matches this closing brace");
             }
         }
+
+        err.span_label(self.token.span, "unexpected closing delimiter");
+        err
     }
 
-    fn bump(&mut self) -> Spacing {
-        let (spacing, token) = self.string_reader.next_token();
-        self.token = token;
-        spacing
+    #[inline]
+    fn parse_token_tree_non_delim_non_eof(&mut self) -> TokenTree {
+        // `this_spacing` for the returned token refers to whether the token is
+        // immediately followed by another op token. It is determined by the
+        // next token: its kind and its `preceded_by_whitespace` status.
+        let (next_tok, is_next_tok_preceded_by_whitespace) = self.string_reader.next_token();
+        let this_spacing = if is_next_tok_preceded_by_whitespace || !next_tok.is_op() {
+            Spacing::Alone
+        } else {
+            Spacing::Joint
+        };
+        let this_tok = std::mem::replace(&mut self.token, next_tok);
+        TokenTree::Token(this_tok, this_spacing)
     }
 }
 
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index a37327f4294..0bdfe10359c 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -4,7 +4,6 @@
 #![feature(box_patterns)]
 #![feature(if_let_guard)]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(never_type)]
 #![feature(rustc_attrs)]
 #![recursion_limit = "256"]
@@ -33,6 +32,8 @@ use parser::{emit_unclosed_delims, make_unclosed_delims_error, Parser};
 pub mod lexer;
 pub mod validate_attr;
 
+mod errors;
+
 // A bunch of utility functions of the form `parse_<thing>_from_<source>`
 // where <thing> includes crate, expr, item, stmt, tts, and one that
 // uses a HOF to parse anything, and <source> includes file and
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index 5fd69b15ecc..58be348883c 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -1,27 +1,26 @@
+use crate::errors::{InvalidMetaItem, SuffixedLiteralInAttribute};
+
 use super::{AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, PathStyle};
 use rustc_ast as ast;
 use rustc_ast::attr;
 use rustc_ast::token::{self, Delimiter, Nonterminal};
-use rustc_ast_pretty::pprust;
-use rustc_errors::{error_code, Diagnostic, PResult};
+use rustc_errors::{error_code, fluent, Diagnostic, IntoDiagnostic, PResult};
 use rustc_span::{sym, BytePos, Span};
 use std::convert::TryInto;
 
 // Public for rustfmt usage
 #[derive(Debug)]
-pub enum InnerAttrPolicy<'a> {
+pub enum InnerAttrPolicy {
     Permitted,
-    Forbidden { reason: &'a str, saw_doc_comment: bool, prev_outer_attr_sp: Option<Span> },
+    Forbidden(Option<InnerAttrForbiddenReason>),
 }
 
-const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \
-                                                     permitted in this context";
-
-pub(super) const DEFAULT_INNER_ATTR_FORBIDDEN: InnerAttrPolicy<'_> = InnerAttrPolicy::Forbidden {
-    reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG,
-    saw_doc_comment: false,
-    prev_outer_attr_sp: None,
-};
+#[derive(Clone, Copy, Debug)]
+pub enum InnerAttrForbiddenReason {
+    InCodeBlock,
+    AfterOuterDocComment { prev_doc_comment_span: Span },
+    AfterOuterAttribute { prev_outer_attr_sp: Span },
+}
 
 enum OuterAttributeType {
     DocComment,
@@ -40,17 +39,15 @@ impl<'a> Parser<'a> {
                 let prev_outer_attr_sp = outer_attrs.last().map(|attr| attr.span);
 
                 let inner_error_reason = if just_parsed_doc_comment {
-                    "an inner attribute is not permitted following an outer doc comment"
-                } else if prev_outer_attr_sp.is_some() {
-                    "an inner attribute is not permitted following an outer attribute"
+                    Some(InnerAttrForbiddenReason::AfterOuterDocComment {
+                        prev_doc_comment_span: prev_outer_attr_sp.unwrap(),
+                    })
+                } else if let Some(prev_outer_attr_sp) = prev_outer_attr_sp {
+                    Some(InnerAttrForbiddenReason::AfterOuterAttribute { prev_outer_attr_sp })
                 } else {
-                    DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
-                };
-                let inner_parse_policy = InnerAttrPolicy::Forbidden {
-                    reason: inner_error_reason,
-                    saw_doc_comment: just_parsed_doc_comment,
-                    prev_outer_attr_sp,
+                    None
                 };
+                let inner_parse_policy = InnerAttrPolicy::Forbidden(inner_error_reason);
                 just_parsed_doc_comment = false;
                 Some(self.parse_attribute(inner_parse_policy)?)
             } else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind {
@@ -58,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,
-                        "expected outer doc comment",
+                        fluent::parser::inner_doc_comment_not_permitted,
                         error_code!(E0753),
                     );
                     if let Some(replacement_span) = self.annotate_following_item_if_applicable(
@@ -69,13 +66,10 @@ impl<'a> Parser<'a> {
                             token::CommentKind::Block => OuterAttributeType::DocBlockComment,
                         },
                     ) {
-                        err.note(
-                            "inner doc comments like this (starting with `//!` or `/*!`) can \
-                            only appear before items",
-                        );
+                        err.note(fluent::parser::note);
                         err.span_suggestion_verbose(
                             replacement_span,
-                            "you might have meant to write a regular comment",
+                            fluent::parser::suggestion,
                             "",
                             rustc_errors::Applicability::MachineApplicable,
                         );
@@ -113,7 +107,7 @@ impl<'a> Parser<'a> {
     // Public for rustfmt usage.
     pub fn parse_attribute(
         &mut self,
-        inner_parse_policy: InnerAttrPolicy<'_>,
+        inner_parse_policy: InnerAttrPolicy,
     ) -> PResult<'a, ast::Attribute> {
         debug!(
             "parse_attribute: inner_parse_policy={:?} self.token={:?}",
@@ -122,35 +116,22 @@ impl<'a> Parser<'a> {
         let lo = self.token.span;
         // Attributes can't have attributes of their own [Editor's note: not with that attitude]
         self.collect_tokens_no_attrs(|this| {
-            if this.eat(&token::Pound) {
-                let style = if this.eat(&token::Not) {
-                    ast::AttrStyle::Inner
-                } else {
-                    ast::AttrStyle::Outer
-                };
+            assert!(this.eat(&token::Pound), "parse_attribute called in non-attribute position");
 
-                this.expect(&token::OpenDelim(Delimiter::Bracket))?;
-                let item = this.parse_attr_item(false)?;
-                this.expect(&token::CloseDelim(Delimiter::Bracket))?;
-                let attr_sp = lo.to(this.prev_token.span);
+            let style =
+                if this.eat(&token::Not) { ast::AttrStyle::Inner } else { ast::AttrStyle::Outer };
 
-                // Emit error if inner attribute is encountered and forbidden.
-                if style == ast::AttrStyle::Inner {
-                    this.error_on_forbidden_inner_attr(attr_sp, inner_parse_policy);
-                }
+            this.expect(&token::OpenDelim(Delimiter::Bracket))?;
+            let item = this.parse_attr_item(false)?;
+            this.expect(&token::CloseDelim(Delimiter::Bracket))?;
+            let attr_sp = lo.to(this.prev_token.span);
 
-                Ok(attr::mk_attr_from_item(
-                    &self.sess.attr_id_generator,
-                    item,
-                    None,
-                    style,
-                    attr_sp,
-                ))
-            } else {
-                let token_str = pprust::token_to_string(&this.token);
-                let msg = &format!("expected `#`, found `{token_str}`");
-                Err(this.struct_span_err(this.token.span, msg))
+            // Emit error if inner attribute is encountered and forbidden.
+            if style == ast::AttrStyle::Inner {
+                this.error_on_forbidden_inner_attr(attr_sp, inner_parse_policy);
             }
+
+            Ok(attr::mk_attr_from_item(&self.sess.attr_id_generator, item, None, style, attr_sp))
         })
     }
 
@@ -190,21 +171,12 @@ impl<'a> Parser<'a> {
             ForceCollect::No,
         ) {
             Ok(Some(item)) => {
-                let attr_name = match attr_type {
-                    OuterAttributeType::Attribute => "attribute",
-                    _ => "doc comment",
-                };
-                err.span_label(
-                    item.span,
-                    &format!("the inner {} doesn't annotate this {}", attr_name, item.kind.descr()),
-                );
+                // FIXME(#100717)
+                err.set_arg("item", item.kind.descr());
+                err.span_label(item.span, fluent::parser::label_does_not_annotate_this);
                 err.span_suggestion_verbose(
                     replacement_span,
-                    &format!(
-                        "to annotate the {}, change the {} from inner to outer style",
-                        item.kind.descr(),
-                        attr_name
-                    ),
+                    fluent::parser::sugg_change_inner_to_outer,
                     match attr_type {
                         OuterAttributeType::Attribute => "",
                         OuterAttributeType::DocBlockComment => "*",
@@ -222,22 +194,33 @@ impl<'a> Parser<'a> {
         Some(replacement_span)
     }
 
-    pub(super) fn error_on_forbidden_inner_attr(&self, attr_sp: Span, policy: InnerAttrPolicy<'_>) {
-        if let InnerAttrPolicy::Forbidden { reason, saw_doc_comment, prev_outer_attr_sp } = policy {
-            let prev_outer_attr_note =
-                if saw_doc_comment { "previous doc comment" } else { "previous outer attribute" };
-
-            let mut diag = self.struct_span_err(attr_sp, reason);
-
-            if let Some(prev_outer_attr_sp) = prev_outer_attr_sp {
-                diag.span_label(attr_sp, "not permitted following an outer attribute")
-                    .span_label(prev_outer_attr_sp, prev_outer_attr_note);
-            }
+    pub(super) fn error_on_forbidden_inner_attr(&self, attr_sp: Span, policy: InnerAttrPolicy) {
+        if let InnerAttrPolicy::Forbidden(reason) = policy {
+            let mut diag = match reason.as_ref().copied() {
+                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,
+                    );
+                    diag.span_label(attr_sp, fluent::parser::label_attr)
+                        .span_label(prev_doc_comment_span, fluent::parser::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,
+                    );
+                    diag.span_label(attr_sp, fluent::parser::label_attr)
+                        .span_label(prev_outer_attr_sp, fluent::parser::label_prev_attr);
+                    diag
+                }
+                Some(InnerAttrForbiddenReason::InCodeBlock) | None => {
+                    self.struct_span_err(attr_sp, fluent::parser::inner_attr_not_permitted)
+                }
+            };
 
-            diag.note(
-                "inner attributes, like `#![no_std]`, annotate the item enclosing them, and \
-                are usually found at the beginning of source files",
-            );
+            diag.note(fluent::parser::inner_attr_explanation);
             if self
                 .annotate_following_item_if_applicable(
                     &mut diag,
@@ -246,7 +229,7 @@ impl<'a> Parser<'a> {
                 )
                 .is_some()
             {
-                diag.note("outer attributes, like `#[test]`, annotate the item following them");
+                diag.note(fluent::parser::outer_attr_explanation);
             };
             diag.emit();
         }
@@ -337,12 +320,7 @@ impl<'a> Parser<'a> {
         debug!("checking if {:?} is unusuffixed", lit);
 
         if !lit.kind.is_unsuffixed() {
-            self.struct_span_err(lit.span, "suffixed literals are not allowed in attributes")
-                .help(
-                    "instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), \
-                    use an unsuffixed version (`1`, `1.0`, etc.)",
-                )
-                .emit();
+            self.sess.emit_err(SuffixedLiteralInAttribute { span: lit.span });
         }
 
         Ok(lit)
@@ -435,9 +413,8 @@ impl<'a> Parser<'a> {
             Err(err) => err.cancel(),
         }
 
-        let found = pprust::token_to_string(&self.token);
-        let msg = format!("expected unsuffixed literal or identifier, found `{found}`");
-        Err(self.struct_span_err(self.token.span, &msg))
+        Err(InvalidMetaItem { span: self.token.span, token: self.token.clone() }
+            .into_diagnostic(&self.sess.span_diagnostic))
     }
 }
 
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index dcea11eadcb..b512f26335f 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -3,6 +3,19 @@ use super::{
     BlockMode, CommaRecoveryMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep,
     TokenExpectType, TokenType,
 };
+use crate::errors::{
+    AmbiguousPlus, AttributeOnParamType, BadQPathStage2, BadTypePlus, BadTypePlusSub,
+    ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg,
+    ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentOnParamType,
+    DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
+    GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg, InInTypo,
+    IncorrectAwait, IncorrectSemicolon, IncorrectUseOfAwait, ParenthesesInForHead,
+    ParenthesesInForHeadSugg, PatternMethodParamWithoutBody, QuestionMarkInType,
+    QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath,
+    StructLiteralBodyWithoutPathSugg, SuggEscapeToUseAsIdentifier, SuggRemoveComma,
+    UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
+    UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead,
+};
 
 use crate::lexer::UnmatchedBrace;
 use rustc_ast as ast;
@@ -19,8 +32,7 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{
     fluent, Applicability, DiagnosticBuilder, DiagnosticMessage, Handler, MultiSpan, PResult,
 };
-use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed};
-use rustc_macros::{Diagnostic, Subdiagnostic};
+use rustc_errors::{pluralize, Diagnostic, ErrorGuaranteed, IntoDiagnostic};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{Span, SpanSnippetError, DUMMY_SP};
@@ -30,9 +42,6 @@ use std::mem::take;
 
 use crate::parser;
 
-const TURBOFISH_SUGGESTION_STR: &str =
-    "use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments";
-
 /// Creates a placeholder argument.
 pub(super) fn dummy_arg(ident: Ident) -> Param {
     let pat = P(Pat {
@@ -52,34 +61,6 @@ pub(super) fn dummy_arg(ident: Ident) -> Param {
     }
 }
 
-pub enum Error {
-    UselessDocComment,
-}
-
-impl Error {
-    fn span_err(
-        self,
-        sp: impl Into<MultiSpan>,
-        handler: &Handler,
-    ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
-        match self {
-            Error::UselessDocComment => {
-                let mut err = struct_span_err!(
-                    handler,
-                    sp,
-                    E0585,
-                    "found a documentation comment that doesn't document anything",
-                );
-                err.help(
-                    "doc comments must come before what they document, maybe a comment was \
-                          intended with `//`?",
-                );
-                err
-            }
-        }
-    }
-}
-
 pub(super) trait RecoverQPath: Sized + 'static {
     const PATH_STYLE: PathStyle = PathStyle::Expr;
     fn to_ty(&self) -> Option<P<Ty>>;
@@ -242,509 +223,6 @@ impl MultiSugg {
     }
 }
 
-#[derive(Diagnostic)]
-#[diag(parser::maybe_report_ambiguous_plus)]
-struct AmbiguousPlus {
-    pub sum_ty: String,
-    #[primary_span]
-    #[suggestion(code = "({sum_ty})")]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::maybe_recover_from_bad_type_plus, code = "E0178")]
-struct BadTypePlus {
-    pub ty: String,
-    #[primary_span]
-    pub span: Span,
-    #[subdiagnostic]
-    pub sub: BadTypePlusSub,
-}
-
-#[derive(Subdiagnostic)]
-pub enum BadTypePlusSub {
-    #[suggestion(
-        parser::add_paren,
-        code = "{sum_with_parens}",
-        applicability = "machine-applicable"
-    )]
-    AddParen {
-        sum_with_parens: String,
-        #[primary_span]
-        span: Span,
-    },
-    #[label(parser::forgot_paren)]
-    ForgotParen {
-        #[primary_span]
-        span: Span,
-    },
-    #[label(parser::expect_path)]
-    ExpectPath {
-        #[primary_span]
-        span: Span,
-    },
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::maybe_recover_from_bad_qpath_stage_2)]
-struct BadQPathStage2 {
-    #[primary_span]
-    #[suggestion(applicability = "maybe-incorrect")]
-    span: Span,
-    ty: String,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::incorrect_semicolon)]
-struct IncorrectSemicolon<'a> {
-    #[primary_span]
-    #[suggestion_short(applicability = "machine-applicable")]
-    span: Span,
-    #[help]
-    opt_help: Option<()>,
-    name: &'a str,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::incorrect_use_of_await)]
-struct IncorrectUseOfAwait {
-    #[primary_span]
-    #[suggestion(parser::parentheses_suggestion, applicability = "machine-applicable")]
-    span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::incorrect_use_of_await)]
-struct IncorrectAwait {
-    #[primary_span]
-    span: Span,
-    #[suggestion(parser::postfix_suggestion, code = "{expr}.await{question_mark}")]
-    sugg_span: (Span, Applicability),
-    expr: String,
-    question_mark: &'static str,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::in_in_typo)]
-struct InInTypo {
-    #[primary_span]
-    span: Span,
-    #[suggestion(applicability = "machine-applicable")]
-    sugg_span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::invalid_variable_declaration)]
-pub struct InvalidVariableDeclaration {
-    #[primary_span]
-    pub span: Span,
-    #[subdiagnostic]
-    pub sub: InvalidVariableDeclarationSub,
-}
-
-#[derive(Subdiagnostic)]
-pub enum InvalidVariableDeclarationSub {
-    #[suggestion(
-        parser::switch_mut_let_order,
-        applicability = "maybe-incorrect",
-        code = "let mut"
-    )]
-    SwitchMutLetOrder(#[primary_span] Span),
-    #[suggestion(
-        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")]
-    UseLetNotAuto(#[primary_span] Span),
-    #[suggestion(parser::use_let_not_var, applicability = "machine-applicable", code = "let")]
-    UseLetNotVar(#[primary_span] Span),
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::invalid_comparison_operator)]
-pub(crate) struct InvalidComparisonOperator {
-    #[primary_span]
-    pub span: Span,
-    pub invalid: String,
-    #[subdiagnostic]
-    pub sub: InvalidComparisonOperatorSub,
-}
-
-#[derive(Subdiagnostic)]
-pub(crate) enum InvalidComparisonOperatorSub {
-    #[suggestion_short(
-        parser::use_instead,
-        applicability = "machine-applicable",
-        code = "{correct}"
-    )]
-    Correctable {
-        #[primary_span]
-        span: Span,
-        invalid: String,
-        correct: String,
-    },
-    #[label(parser::spaceship_operator_invalid)]
-    Spaceship(#[primary_span] Span),
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::invalid_logical_operator)]
-#[note]
-pub(crate) struct InvalidLogicalOperator {
-    #[primary_span]
-    pub span: Span,
-    pub incorrect: String,
-    #[subdiagnostic]
-    pub sub: InvalidLogicalOperatorSub,
-}
-
-#[derive(Subdiagnostic)]
-pub(crate) enum InvalidLogicalOperatorSub {
-    #[suggestion_short(
-        parser::use_amp_amp_for_conjunction,
-        applicability = "machine-applicable",
-        code = "&&"
-    )]
-    Conjunction(#[primary_span] Span),
-    #[suggestion_short(
-        parser::use_pipe_pipe_for_disjunction,
-        applicability = "machine-applicable",
-        code = "||"
-    )]
-    Disjunction(#[primary_span] Span),
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::tilde_is_not_unary_operator)]
-pub(crate) struct TildeAsUnaryOperator(
-    #[primary_span]
-    #[suggestion_short(applicability = "machine-applicable", code = "!")]
-    pub Span,
-);
-
-#[derive(Diagnostic)]
-#[diag(parser::unexpected_token_after_not)]
-pub(crate) struct NotAsNegationOperator {
-    #[primary_span]
-    pub negated: Span,
-    pub negated_desc: String,
-    #[subdiagnostic]
-    pub sub: NotAsNegationOperatorSub,
-}
-
-#[derive(Subdiagnostic)]
-pub enum NotAsNegationOperatorSub {
-    #[suggestion_short(
-        parser::unexpected_token_after_not_default,
-        applicability = "machine-applicable",
-        code = "!"
-    )]
-    SuggestNotDefault(#[primary_span] Span),
-
-    #[suggestion_short(
-        parser::unexpected_token_after_not_bitwise,
-        applicability = "machine-applicable",
-        code = "!"
-    )]
-    SuggestNotBitwise(#[primary_span] Span),
-
-    #[suggestion_short(
-        parser::unexpected_token_after_not_logical,
-        applicability = "machine-applicable",
-        code = "!"
-    )]
-    SuggestNotLogical(#[primary_span] Span),
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::malformed_loop_label)]
-pub(crate) struct MalformedLoopLabel {
-    #[primary_span]
-    #[suggestion(applicability = "machine-applicable", code = "{correct_label}")]
-    pub span: Span,
-    pub correct_label: Ident,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::lifetime_in_borrow_expression)]
-pub(crate) struct LifetimeInBorrowExpression {
-    #[primary_span]
-    pub span: Span,
-    #[suggestion(applicability = "machine-applicable", code = "")]
-    #[label]
-    pub lifetime_span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::field_expression_with_generic)]
-pub(crate) struct FieldExpressionWithGeneric(#[primary_span] pub Span);
-
-#[derive(Diagnostic)]
-#[diag(parser::macro_invocation_with_qualified_path)]
-pub(crate) struct MacroInvocationWithQualifiedPath(#[primary_span] pub Span);
-
-#[derive(Diagnostic)]
-#[diag(parser::unexpected_token_after_label)]
-pub(crate) struct UnexpectedTokenAfterLabel(
-    #[primary_span]
-    #[label(parser::unexpected_token_after_label)]
-    pub Span,
-);
-
-#[derive(Diagnostic)]
-#[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 = ": ")]
-    pub label_end: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::do_catch_syntax_removed)]
-#[note]
-pub(crate) struct DoCatchSyntaxRemoved {
-    #[primary_span]
-    #[suggestion(applicability = "machine-applicable", code = "try")]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::float_literal_requires_integer_part)]
-pub(crate) struct FloatLiteralRequiresIntegerPart {
-    #[primary_span]
-    #[suggestion(applicability = "machine-applicable", code = "{correct}")]
-    pub span: Span,
-    pub correct: String,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::invalid_int_literal_width)]
-#[help]
-pub(crate) struct InvalidIntLiteralWidth {
-    #[primary_span]
-    pub span: Span,
-    pub width: String,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::invalid_num_literal_base_prefix)]
-#[note]
-pub(crate) struct InvalidNumLiteralBasePrefix {
-    #[primary_span]
-    #[suggestion(applicability = "maybe-incorrect", code = "{fixed}")]
-    pub span: Span,
-    pub fixed: String,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::invalid_num_literal_suffix)]
-#[help]
-pub(crate) struct InvalidNumLiteralSuffix {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-    pub suffix: String,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::invalid_float_literal_width)]
-#[help]
-pub(crate) struct InvalidFloatLiteralWidth {
-    #[primary_span]
-    pub span: Span,
-    pub width: String,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::invalid_float_literal_suffix)]
-#[help]
-pub(crate) struct InvalidFloatLiteralSuffix {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-    pub suffix: String,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::int_literal_too_large)]
-pub(crate) struct IntLiteralTooLarge {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::missing_semicolon_before_array)]
-pub(crate) struct MissingSemicolonBeforeArray {
-    #[primary_span]
-    pub open_delim: Span,
-    #[suggestion_verbose(applicability = "maybe-incorrect", code = ";")]
-    pub semicolon: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::invalid_block_macro_segment)]
-pub(crate) struct InvalidBlockMacroSegment {
-    #[primary_span]
-    pub span: Span,
-    #[label]
-    pub context: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::if_expression_missing_then_block)]
-pub(crate) struct IfExpressionMissingThenBlock {
-    #[primary_span]
-    pub if_span: Span,
-    #[subdiagnostic]
-    pub sub: IfExpressionMissingThenBlockSub,
-}
-
-#[derive(Subdiagnostic)]
-pub(crate) enum IfExpressionMissingThenBlockSub {
-    #[help(parser::condition_possibly_unfinished)]
-    UnfinishedCondition(#[primary_span] Span),
-    #[help(parser::add_then_block)]
-    AddThenBlock(#[primary_span] Span),
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::if_expression_missing_condition)]
-pub(crate) struct IfExpressionMissingCondition {
-    #[primary_span]
-    #[label(parser::condition_label)]
-    pub if_span: Span,
-    #[label(parser::block_label)]
-    pub block_span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::expected_expression_found_let)]
-pub(crate) struct ExpectedExpressionFoundLet {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::expected_else_block)]
-pub(crate) struct ExpectedElseBlock {
-    #[primary_span]
-    pub first_tok_span: Span,
-    pub first_tok: String,
-    #[label]
-    pub else_span: Span,
-    #[suggestion(applicability = "maybe-incorrect", code = "if ")]
-    pub condition_start: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::outer_attribute_not_allowed_on_if_else)]
-pub(crate) struct OuterAttributeNotAllowedOnIfElse {
-    #[primary_span]
-    pub last: Span,
-
-    #[label(parser::branch_label)]
-    pub branch_span: Span,
-
-    #[label(parser::ctx_label)]
-    pub ctx_span: Span,
-    pub ctx: String,
-
-    #[suggestion(applicability = "machine-applicable", code = "")]
-    pub attributes: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::missing_in_in_for_loop)]
-pub(crate) struct MissingInInForLoop {
-    #[primary_span]
-    pub span: Span,
-    #[subdiagnostic]
-    pub sub: MissingInInForLoopSub,
-}
-
-#[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")]
-    InNotOf(#[primary_span] Span),
-    #[suggestion_short(parser::add_in, applicability = "maybe-incorrect", code = " in ")]
-    AddIn(#[primary_span] Span),
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::missing_comma_after_match_arm)]
-pub(crate) struct MissingCommaAfterMatchArm {
-    #[primary_span]
-    #[suggestion(applicability = "machine-applicable", code = ",")]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::catch_after_try)]
-#[help]
-pub(crate) struct CatchAfterTry {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::comma_after_base_struct)]
-#[note]
-pub(crate) struct CommaAfterBaseStruct {
-    #[primary_span]
-    pub span: Span,
-    #[suggestion_short(applicability = "machine-applicable", code = "")]
-    pub comma: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::eq_field_init)]
-pub(crate) struct EqFieldInit {
-    #[primary_span]
-    pub span: Span,
-    #[suggestion(applicability = "machine-applicable", code = ":")]
-    pub eq: Span,
-}
-
-#[derive(Diagnostic)]
-#[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 = "..=")]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::left_arrow_operator)]
-pub(crate) struct LeftArrowOperator {
-    #[primary_span]
-    #[suggestion(applicability = "maybe-incorrect", code = "< -")]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::remove_let)]
-pub(crate) struct RemoveLet {
-    #[primary_span]
-    #[suggestion(applicability = "machine-applicable", code = "")]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(parser::use_eq_instead)]
-pub(crate) struct UseEqInstead {
-    #[primary_span]
-    #[suggestion_short(applicability = "machine-applicable", code = "=")]
-    pub span: Span,
-}
-
 // SnapshotParser is used to create a snapshot of the parser
 // without causing duplicate errors being emitted when the `Parser`
 // is dropped.
@@ -769,15 +247,6 @@ impl<'a> DerefMut for SnapshotParser<'a> {
 
 impl<'a> Parser<'a> {
     #[rustc_lint_diagnostics]
-    pub(super) fn span_err<S: Into<MultiSpan>>(
-        &self,
-        sp: S,
-        err: Error,
-    ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
-        err.span_err(sp, self.diagnostic())
-    }
-
-    #[rustc_lint_diagnostics]
     pub fn struct_span_err<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -822,10 +291,6 @@ impl<'a> Parser<'a> {
     }
 
     pub(super) fn expected_ident_found(&self) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
-        let mut err = self.struct_span_err(
-            self.token.span,
-            &format!("expected identifier, found {}", super::token_descr(&self.token)),
-        );
         let valid_follow = &[
             TokenKind::Eq,
             TokenKind::Colon,
@@ -837,34 +302,35 @@ impl<'a> Parser<'a> {
             TokenKind::CloseDelim(Delimiter::Brace),
             TokenKind::CloseDelim(Delimiter::Parenthesis),
         ];
-        match self.token.ident() {
+        let suggest_raw = match self.token.ident() {
             Some((ident, false))
                 if ident.is_raw_guess()
                     && self.look_ahead(1, |t| valid_follow.contains(&t.kind)) =>
             {
-                err.span_suggestion_verbose(
-                    ident.span.shrink_to_lo(),
-                    &format!("escape `{}` to use it as an identifier", ident.name),
-                    "r#",
-                    Applicability::MaybeIncorrect,
-                );
+                Some(SuggEscapeToUseAsIdentifier {
+                    span: ident.span.shrink_to_lo(),
+                    // `Symbol::to_string()` is different from `Symbol::into_diagnostic_arg()`,
+                    // which uses `Symbol::to_ident_string()` and "helpfully" adds an implicit `r#`
+                    ident_name: ident.name.to_string(),
+                })
             }
-            _ => {}
-        }
-        if let Some(token_descr) = super::token_descr_opt(&self.token) {
-            err.span_label(self.token.span, format!("expected identifier, found {}", token_descr));
-        } else {
-            err.span_label(self.token.span, "expected identifier");
+            _ => None,
+        };
+
+        let suggest_remove_comma =
             if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) {
-                err.span_suggestion(
-                    self.token.span,
-                    "remove this comma",
-                    "",
-                    Applicability::MachineApplicable,
-                );
-            }
-        }
-        err
+                Some(SuggRemoveComma { span: self.token.span })
+            } else {
+                None
+            };
+
+        let err = ExpectedIdentifier {
+            span: self.token.span,
+            token: self.token.clone(),
+            suggest_raw,
+            suggest_remove_comma,
+        };
+        err.into_diagnostic(&self.sess.span_diagnostic)
     }
 
     pub(super) fn expected_one_of_not_found(
@@ -929,8 +395,8 @@ impl<'a> Parser<'a> {
         expected.dedup();
 
         let sm = self.sess.source_map();
-        let msg = format!("expected `;`, found {}", super::token_descr(&self.token));
-        let appl = Applicability::MachineApplicable;
+
+        // Special-case "expected `;`" errors
         if expected.contains(&TokenType::Token(token::Semi)) {
             if self.token.span == DUMMY_SP || self.prev_token.span == DUMMY_SP {
                 // Likely inside a macro, can't provide meaningful suggestions.
@@ -958,11 +424,13 @@ impl<'a> Parser<'a> {
                 //
                 //   let x = 32:
                 //   let y = 42;
+                self.sess.emit_err(ExpectedSemi {
+                    span: self.token.span,
+                    token: self.token.clone(),
+                    unexpected_token_label: None,
+                    sugg: ExpectedSemiSugg::ChangeToSemi(self.token.span),
+                });
                 self.bump();
-                let sp = self.prev_token.span;
-                self.struct_span_err(sp, &msg)
-                    .span_suggestion_short(sp, "change this to `;`", ";", appl)
-                    .emit();
                 return Ok(true);
             } else if self.look_ahead(0, |t| {
                 t == &token::CloseDelim(Delimiter::Brace)
@@ -980,11 +448,13 @@ impl<'a> Parser<'a> {
                 //
                 //   let x = 32
                 //   let y = 42;
-                let sp = self.prev_token.span.shrink_to_hi();
-                self.struct_span_err(sp, &msg)
-                    .span_label(self.token.span, "unexpected token")
-                    .span_suggestion_short(sp, "add `;` here", ";", appl)
-                    .emit();
+                let span = self.prev_token.span.shrink_to_hi();
+                self.sess.emit_err(ExpectedSemi {
+                    span,
+                    token: self.token.clone(),
+                    unexpected_token_label: Some(self.token.span),
+                    sugg: ExpectedSemiSugg::AddSemi(span),
+                });
                 return Ok(true);
             }
         }
@@ -1021,6 +491,7 @@ impl<'a> Parser<'a> {
             )
         };
         self.last_unexpected_token_span = Some(self.token.span);
+        // FIXME: translation requires list formatting (for `expect`)
         let mut err = self.struct_span_err(self.token.span, &msg_exp);
 
         if let TokenKind::Ident(symbol, _) = &self.prev_token.kind {
@@ -1029,7 +500,7 @@ impl<'a> Parser<'a> {
                     self.prev_token.span,
                     &format!("write `fn` instead of `{symbol}` to declare a function"),
                     "fn",
-                    appl,
+                    Applicability::MachineApplicable,
                 );
             }
         }
@@ -1043,7 +514,7 @@ impl<'a> Parser<'a> {
                 self.prev_token.span,
                 "write `pub` instead of `public` to make the item public",
                 "pub",
-                appl,
+                Applicability::MachineApplicable,
             );
         }
 
@@ -1181,19 +652,13 @@ impl<'a> Parser<'a> {
                     //     field: value,
                     // } }
                     err.delay_as_bug();
-                    self.struct_span_err(
-                        expr.span,
-                        fluent::parser::struct_literal_body_without_path,
-                    )
-                    .multipart_suggestion(
-                        fluent::parser::suggestion,
-                        vec![
-                            (expr.span.shrink_to_lo(), "{ SomeStruct ".to_string()),
-                            (expr.span.shrink_to_hi(), " }".to_string()),
-                        ],
-                        Applicability::MaybeIncorrect,
-                    )
-                    .emit();
+                    self.sess.emit_err(StructLiteralBodyWithoutPath {
+                        span: expr.span,
+                        sugg: StructLiteralBodyWithoutPathSugg {
+                            before: expr.span.shrink_to_lo(),
+                            after: expr.span.shrink_to_hi(),
+                        },
+                    });
                     self.restore_snapshot(snapshot);
                     let mut tail = self.mk_block(
                         vec![self.mk_stmt_err(expr.span)],
@@ -1387,18 +852,8 @@ impl<'a> Parser<'a> {
             self.eat_to_tokens(end);
             let span = lo.until(self.token.span);
 
-            let total_num_of_gt = number_of_gt + number_of_shr * 2;
-            self.struct_span_err(
-                span,
-                &format!("unmatched angle bracket{}", pluralize!(total_num_of_gt)),
-            )
-            .span_suggestion(
-                span,
-                &format!("remove extra angle bracket{}", pluralize!(total_num_of_gt)),
-                "",
-                Applicability::MachineApplicable,
-            )
-            .emit();
+            let num_extra_brackets = number_of_gt + number_of_shr * 2;
+            self.sess.emit_err(UnmatchedAngleBrackets { span, num_extra_brackets });
             return true;
         }
         false
@@ -1427,19 +882,13 @@ impl<'a> Parser<'a> {
                         let args = AngleBracketedArgs { args, span }.into();
                         segment.args = args;
 
-                        self.struct_span_err(
+                        self.sess.emit_err(GenericParamsWithoutAngleBrackets {
                             span,
-                            "generic parameters without surrounding angle brackets",
-                        )
-                        .multipart_suggestion(
-                            "surround the type parameters with angle brackets",
-                            vec![
-                                (span.shrink_to_lo(), "<".to_string()),
-                                (trailing_span, ">".to_string()),
-                            ],
-                            Applicability::MachineApplicable,
-                        )
-                        .emit();
+                            sugg: GenericParamsWithoutAngleBracketsSugg {
+                                left: span.shrink_to_lo(),
+                                right: trailing_span,
+                            },
+                        });
                     } else {
                         // This doesn't look like an invalid turbofish, can't recover parse state.
                         self.restore_snapshot(snapshot);
@@ -1476,7 +925,7 @@ impl<'a> Parser<'a> {
                     if self.eat(&token::Gt) {
                         e.span_suggestion_verbose(
                             binop.span.shrink_to_lo(),
-                            TURBOFISH_SUGGESTION_STR,
+                            fluent::parser::sugg_turbofish_syntax,
                             "::",
                             Applicability::MaybeIncorrect,
                         )
@@ -1508,7 +957,7 @@ impl<'a> Parser<'a> {
     /// parenthesising the leftmost comparison.
     fn attempt_chained_comparison_suggestion(
         &mut self,
-        err: &mut Diagnostic,
+        err: &mut ComparisonOperatorsCannotBeChained,
         inner_op: &Expr,
         outer_op: &Spanned<AssocOp>,
     ) -> bool /* advanced the cursor */ {
@@ -1521,16 +970,6 @@ impl<'a> Parser<'a> {
                 // suggestion being the only one to apply is high.
                 return false;
             }
-            let mut enclose = |left: Span, right: Span| {
-                err.multipart_suggestion(
-                    "parenthesize the comparison",
-                    vec![
-                        (left.shrink_to_lo(), "(".to_string()),
-                        (right.shrink_to_hi(), ")".to_string()),
-                    ],
-                    Applicability::MaybeIncorrect,
-                );
-            };
             return match (op.node, &outer_op.node) {
                 // `x == y == z`
                 (BinOpKind::Eq, AssocOp::Equal) |
@@ -1544,12 +983,10 @@ impl<'a> Parser<'a> {
                         self.span_to_snippet(e.span)
                             .unwrap_or_else(|_| pprust::expr_to_string(&e))
                     };
-                    err.span_suggestion_verbose(
-                        inner_op.span.shrink_to_hi(),
-                        "split the comparison into two",
-                        format!(" && {}", expr_to_str(&r1)),
-                        Applicability::MaybeIncorrect,
-                    );
+                    err.chaining_sugg = Some(ComparisonOperatorsCannotBeChainedSugg::SplitComparison {
+                        span: inner_op.span.shrink_to_hi(),
+                        middle_term: expr_to_str(&r1),
+                    });
                     false // Keep the current parse behavior, where the AST is `(x < y) < z`.
                 }
                 // `x == y < z`
@@ -1560,7 +997,10 @@ impl<'a> Parser<'a> {
                         Ok(r2) => {
                             // We are sure that outer-op-rhs could be consumed, the suggestion is
                             // likely correct.
-                            enclose(r1.span, r2.span);
+                            err.chaining_sugg = Some(ComparisonOperatorsCannotBeChainedSugg::Parenthesize {
+                                left: r1.span.shrink_to_lo(),
+                                right: r2.span.shrink_to_hi(),
+                            });
                             true
                         }
                         Err(expr_err) => {
@@ -1577,7 +1017,10 @@ impl<'a> Parser<'a> {
                     // further checks are necessary.
                     match self.parse_expr() {
                         Ok(_) => {
-                            enclose(l1.span, r1.span);
+                            err.chaining_sugg = Some(ComparisonOperatorsCannotBeChainedSugg::Parenthesize {
+                                left: l1.span.shrink_to_lo(),
+                                right: r1.span.shrink_to_hi(),
+                            });
                             true
                         }
                         Err(expr_err) => {
@@ -1626,18 +1069,11 @@ impl<'a> Parser<'a> {
 
         match inner_op.kind {
             ExprKind::Binary(op, ref l1, ref r1) if op.node.is_comparison() => {
-                let mut err = self.struct_span_err(
-                    vec![op.span, self.prev_token.span],
-                    "comparison operators cannot be chained",
-                );
-
-                let suggest = |err: &mut Diagnostic| {
-                    err.span_suggestion_verbose(
-                        op.span.shrink_to_lo(),
-                        TURBOFISH_SUGGESTION_STR,
-                        "::",
-                        Applicability::MaybeIncorrect,
-                    );
+                let mut err = ComparisonOperatorsCannotBeChained {
+                    span: vec![op.span, self.prev_token.span],
+                    suggest_turbofish: None,
+                    help_turbofish: None,
+                    chaining_sugg: None,
                 };
 
                 // Include `<` to provide this recommendation even in a case like
@@ -1664,7 +1100,7 @@ impl<'a> Parser<'a> {
                     return if token::ModSep == self.token.kind {
                         // We have some certainty that this was a bad turbofish at this point.
                         // `foo< bar >::`
-                        suggest(&mut err);
+                        err.suggest_turbofish = Some(op.span.shrink_to_lo());
 
                         let snapshot = self.create_snapshot_for_diagnostic();
                         self.bump(); // `::`
@@ -1673,7 +1109,7 @@ impl<'a> Parser<'a> {
                         match self.parse_expr() {
                             Ok(_) => {
                                 // 99% certain that the suggestion is correct, continue parsing.
-                                err.emit();
+                                self.sess.emit_err(err);
                                 // FIXME: actually check that the two expressions in the binop are
                                 // paths and resynthesize new fn call expression instead of using
                                 // `ExprKind::Err` placeholder.
@@ -1684,18 +1120,18 @@ impl<'a> Parser<'a> {
                                 // Not entirely sure now, but we bubble the error up with the
                                 // suggestion.
                                 self.restore_snapshot(snapshot);
-                                Err(err)
+                                Err(err.into_diagnostic(&self.sess.span_diagnostic))
                             }
                         }
                     } else if token::OpenDelim(Delimiter::Parenthesis) == self.token.kind {
                         // We have high certainty that this was a bad turbofish at this point.
                         // `foo< bar >(`
-                        suggest(&mut err);
+                        err.suggest_turbofish = Some(op.span.shrink_to_lo());
                         // Consume the fn call arguments.
                         match self.consume_fn_args() {
-                            Err(()) => Err(err),
+                            Err(()) => Err(err.into_diagnostic(&self.sess.span_diagnostic)),
                             Ok(()) => {
-                                err.emit();
+                                self.sess.emit_err(err);
                                 // FIXME: actually check that the two expressions in the binop are
                                 // paths and resynthesize new fn call expression instead of using
                                 // `ExprKind::Err` placeholder.
@@ -1708,25 +1144,24 @@ impl<'a> Parser<'a> {
                         {
                             // All we know is that this is `foo < bar >` and *nothing* else. Try to
                             // be helpful, but don't attempt to recover.
-                            err.help(TURBOFISH_SUGGESTION_STR);
-                            err.help("or use `(...)` if you meant to specify fn arguments");
+                            err.help_turbofish = Some(());
                         }
 
                         // If it looks like a genuine attempt to chain operators (as opposed to a
                         // misformatted turbofish, for instance), suggest a correct form.
                         if self.attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op)
                         {
-                            err.emit();
+                            self.sess.emit_err(err);
                             mk_err_expr(self, inner_op.span.to(self.prev_token.span))
                         } else {
                             // These cases cause too many knock-down errors, bail out (#61329).
-                            Err(err)
+                            Err(err.into_diagnostic(&self.sess.span_diagnostic))
                         }
                     };
                 }
                 let recover =
                     self.attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op);
-                err.emit();
+                self.sess.emit_err(err);
                 if recover {
                     return mk_err_expr(self, inner_op.span.to(self.prev_token.span));
                 }
@@ -1767,17 +1202,13 @@ impl<'a> Parser<'a> {
     pub(super) fn maybe_recover_from_question_mark(&mut self, ty: P<Ty>) -> P<Ty> {
         if self.token == token::Question {
             self.bump();
-            self.struct_span_err(self.prev_token.span, "invalid `?` in type")
-                .span_label(self.prev_token.span, "`?` is only allowed on expressions, not types")
-                .multipart_suggestion(
-                    "if you meant to express that the type might not contain a value, use the `Option` wrapper type",
-                    vec![
-                        (ty.span.shrink_to_lo(), "Option<".to_string()),
-                        (self.prev_token.span, ">".to_string()),
-                    ],
-                    Applicability::MachineApplicable,
-                )
-                .emit();
+            self.sess.emit_err(QuestionMarkInType {
+                span: self.prev_token.span,
+                sugg: QuestionMarkInTypeSugg {
+                    left: ty.span.shrink_to_lo(),
+                    right: self.prev_token.span,
+                },
+            });
             self.mk_ty(ty.span.to(self.prev_token.span), TyKind::Err)
         } else {
             ty
@@ -2201,19 +1632,16 @@ impl<'a> Parser<'a> {
             (token::CloseDelim(Delimiter::Parenthesis), Some(begin_par_sp)) => {
                 self.bump();
 
-                self.struct_span_err(
-                    MultiSpan::from_spans(vec![begin_par_sp, self.prev_token.span]),
-                    "unexpected parentheses surrounding `for` loop head",
-                )
-                .multipart_suggestion(
-                    "remove parentheses in `for` loop",
-                    vec![(begin_par_sp, String::new()), (self.prev_token.span, String::new())],
+                self.sess.emit_err(ParenthesesInForHead {
+                    span: vec![begin_par_sp, self.prev_token.span],
                     // With e.g. `for (x) in y)` this would replace `(x) in y)`
                     // with `x) in y)` which is syntactically invalid.
                     // However, this is prevented before we get here.
-                    Applicability::MachineApplicable,
-                )
-                .emit();
+                    sugg: ParenthesesInForHeadSugg {
+                        left: begin_par_sp,
+                        right: self.prev_token.span,
+                    },
+                });
 
                 // Unwrap `(pat)` into `pat` to avoid the `unused_parens` lint.
                 pat.and_then(|pat| match pat.kind {
@@ -2432,12 +1860,7 @@ impl<'a> Parser<'a> {
 
     pub(super) fn eat_incorrect_doc_comment_for_param_type(&mut self) {
         if let token::DocComment(..) = self.token.kind {
-            self.struct_span_err(
-                self.token.span,
-                "documentation comments cannot be applied to a function parameter's type",
-            )
-            .span_label(self.token.span, "doc comments are not allowed here")
-            .emit();
+            self.sess.emit_err(DocCommentOnParamType { span: self.token.span });
             self.bump();
         } else if self.token == token::Pound
             && self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Bracket))
@@ -2449,9 +1872,7 @@ impl<'a> Parser<'a> {
             }
             let sp = lo.to(self.token.span);
             self.bump();
-            self.struct_span_err(sp, "attributes cannot be applied to a function parameter's type")
-                .span_label(sp, "attributes are not allowed here")
-                .emit();
+            self.sess.emit_err(AttributeOnParamType { span: sp });
         }
     }
 
@@ -2572,19 +1993,7 @@ impl<'a> Parser<'a> {
         self.expect(&token::Colon)?;
         let ty = self.parse_ty()?;
 
-        struct_span_err!(
-            self.diagnostic(),
-            pat.span,
-            E0642,
-            "patterns aren't allowed in methods without bodies",
-        )
-        .span_suggestion_short(
-            pat.span,
-            "give this argument a name or use an underscore to ignore it",
-            "_",
-            Applicability::MachineApplicable,
-        )
-        .emit();
+        self.sess.emit_err(PatternMethodParamWithoutBody { span: pat.span });
 
         // Pretend the pattern is `_`, to avoid duplicate errors from AST validation.
         let pat =
@@ -2593,11 +2002,9 @@ impl<'a> Parser<'a> {
     }
 
     pub(super) fn recover_bad_self_param(&mut self, mut param: Param) -> PResult<'a, Param> {
-        let sp = param.pat.span;
+        let span = param.pat.span;
         param.ty.kind = TyKind::Err;
-        self.struct_span_err(sp, "unexpected `self` parameter in function")
-            .span_label(sp, "must be the first parameter of an associated function")
-            .emit();
+        self.sess.emit_err(SelfParamNotFirst { span });
         Ok(param)
     }
 
@@ -2746,20 +2153,13 @@ impl<'a> Parser<'a> {
             err
         })?;
         if !self.expr_is_valid_const_arg(&expr) {
-            self.struct_span_err(
-                expr.span,
-                "expressions must be enclosed in braces to be used as const generic \
-                    arguments",
-            )
-            .multipart_suggestion(
-                "enclose the `const` expression in braces",
-                vec![
-                    (expr.span.shrink_to_lo(), "{ ".to_string()),
-                    (expr.span.shrink_to_hi(), " }".to_string()),
-                ],
-                Applicability::MachineApplicable,
-            )
-            .emit();
+            self.sess.emit_err(ConstGenericWithoutBraces {
+                span: expr.span,
+                sugg: ConstGenericWithoutBracesSugg {
+                    left: expr.span.shrink_to_lo(),
+                    right: expr.span.shrink_to_hi(),
+                },
+            });
         }
         Ok(expr)
     }
@@ -2774,24 +2174,30 @@ impl<'a> Parser<'a> {
                 return None;
             }
         };
-        let mut err =
-            self.struct_span_err(param.span(), "unexpected `const` parameter declaration");
-        err.span_label(param.span(), "expected a `const` expression, not a parameter declaration");
-        if let (Some(generics), Ok(snippet)) =
-            (ty_generics, self.sess.source_map().span_to_snippet(param.span()))
-        {
-            let (span, sugg) = match &generics.params[..] {
-                [] => (generics.span, format!("<{snippet}>")),
-                [.., generic] => (generic.span().shrink_to_hi(), format!(", {snippet}")),
-            };
-            err.multipart_suggestion(
-                "`const` parameters must be declared for the `impl`",
-                vec![(span, sugg), (param.span(), param.ident.to_string())],
-                Applicability::MachineApplicable,
-            );
-        }
+
+        let ident = param.ident.to_string();
+        let sugg = match (ty_generics, self.sess.source_map().span_to_snippet(param.span())) {
+            (Some(Generics { params, span: impl_generics, .. }), Ok(snippet)) => {
+                Some(match &params[..] {
+                    [] => UnexpectedConstParamDeclarationSugg::AddParam {
+                        impl_generics: *impl_generics,
+                        incorrect_decl: param.span(),
+                        snippet,
+                        ident,
+                    },
+                    [.., generic] => UnexpectedConstParamDeclarationSugg::AppendParam {
+                        impl_generics_end: generic.span().shrink_to_hi(),
+                        incorrect_decl: param.span(),
+                        snippet,
+                        ident,
+                    },
+                })
+            }
+            _ => None,
+        };
+        self.sess.emit_err(UnexpectedConstParamDeclaration { span: param.span(), sugg });
+
         let value = self.mk_expr_err(param.span());
-        err.emit();
         Some(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }))
     }
 
@@ -2809,20 +2215,15 @@ impl<'a> Parser<'a> {
         self.bump(); // `const`
 
         // Detect and recover from the old, pre-RFC2000 syntax for const generics.
-        let mut err = self
-            .struct_span_err(start, "expected lifetime, type, or constant, found keyword `const`");
+        let mut err = UnexpectedConstInGenericParam { span: start, to_remove: None };
         if self.check_const_arg() {
-            err.span_suggestion_verbose(
-                start.until(self.token.span),
-                "the `const` keyword is only needed in the definition of the type",
-                "",
-                Applicability::MaybeIncorrect,
-            );
-            err.emit();
+            err.to_remove = Some(start.until(self.token.span));
+            self.sess.emit_err(err);
             Ok(Some(GenericArg::Const(self.parse_const_arg()?)))
         } else {
             let after_kw_const = self.token.span;
-            self.recover_const_arg(after_kw_const, err).map(Some)
+            self.recover_const_arg(after_kw_const, err.into_diagnostic(&self.sess.span_diagnostic))
+                .map(Some)
         }
     }
 
@@ -2928,24 +2329,6 @@ impl<'a> Parser<'a> {
         GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })
     }
 
-    /// Get the diagnostics for the cases where `move async` is found.
-    ///
-    /// `move_async_span` starts at the 'm' of the move keyword and ends with the 'c' of the async keyword
-    pub(super) fn incorrect_move_async_order_found(
-        &self,
-        move_async_span: Span,
-    ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
-        let mut err =
-            self.struct_span_err(move_async_span, "the order of `move` and `async` is incorrect");
-        err.span_suggestion_verbose(
-            move_async_span,
-            "try switching the order",
-            "async move",
-            Applicability::MaybeIncorrect,
-        );
-        err
-    }
-
     /// Some special error handling for the "top-level" patterns in a match arm,
     /// `for` loop, `let`, &c. (in contrast to subpatterns within such).
     pub(crate) fn maybe_recover_colon_colon_in_pat_typo(
@@ -3141,17 +2524,11 @@ impl<'a> Parser<'a> {
                 let (a_span, b_span) = (a.span(), b.span());
                 let between_span = a_span.shrink_to_hi().to(b_span.shrink_to_lo());
                 if self.span_to_snippet(between_span).as_ref().map(|a| &a[..]) == Ok(":: ") {
-                    let mut err = self.struct_span_err(
-                        path.span.shrink_to_hi(),
-                        "expected `:` followed by trait or lifetime",
-                    );
-                    err.span_suggestion(
-                        between_span,
-                        "use single colon",
-                        ": ",
-                        Applicability::MachineApplicable,
-                    );
-                    return Err(err);
+                    return Err(DoubleColonInBound {
+                        span: path.span.shrink_to_hi(),
+                        between: between_span,
+                    }
+                    .into_diagnostic(&self.sess.span_diagnostic));
                 }
             }
         }
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index ae77961b7bc..8b328e593ae 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1,27 +1,33 @@
-use super::diagnostics::{
-    CatchAfterTry, CommaAfterBaseStruct, DoCatchSyntaxRemoved, DotDotDot, EqFieldInit,
-    ExpectedElseBlock, ExpectedExpressionFoundLet, FieldExpressionWithGeneric,
-    FloatLiteralRequiresIntegerPart, IfExpressionMissingCondition, IfExpressionMissingThenBlock,
-    IfExpressionMissingThenBlockSub, InvalidBlockMacroSegment, InvalidComparisonOperator,
-    InvalidComparisonOperatorSub, InvalidLogicalOperator, InvalidLogicalOperatorSub,
-    LeftArrowOperator, LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath,
-    MalformedLoopLabel, MissingInInForLoop, MissingInInForLoopSub, MissingSemicolonBeforeArray,
-    NotAsNegationOperator, NotAsNegationOperatorSub, OuterAttributeNotAllowedOnIfElse,
-    RequireColonAfterLabeledExpression, SnapshotParser, TildeAsUnaryOperator,
-    UnexpectedTokenAfterLabel,
-};
+use super::diagnostics::SnapshotParser;
 use super::pat::{CommaRecoveryMode, RecoverColon, RecoverComma, PARAM_EXPECTED};
 use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
 use super::{
     AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions,
     SemiColonMode, SeqSep, TokenExpectType, TokenType, TrailingToken,
 };
-use crate::maybe_recover_from_interpolated_ty_qpath;
-use crate::parser::diagnostics::{
-    IntLiteralTooLarge, InvalidFloatLiteralSuffix, InvalidFloatLiteralWidth,
-    InvalidIntLiteralWidth, InvalidNumLiteralBasePrefix, InvalidNumLiteralSuffix,
-    MissingCommaAfterMatchArm,
+use crate::errors::{
+    ArrayBracketsInsteadOfSpaces, ArrayBracketsInsteadOfSpacesSugg, AsyncMoveOrderIncorrect,
+    BinaryFloatLiteralNotSupported, BracesForStructLiteral, CatchAfterTry, CommaAfterBaseStruct,
+    ComparisonInterpretedAsGeneric, ComparisonOrShiftInterpretedAsGenericSugg,
+    DoCatchSyntaxRemoved, DotDotDot, EqFieldInit, ExpectedElseBlock, ExpectedExpressionFoundLet,
+    FieldExpressionWithGeneric, FloatLiteralRequiresIntegerPart, FoundExprWouldBeStmt,
+    HexadecimalFloatLiteralNotSupported, IfExpressionMissingCondition,
+    IfExpressionMissingThenBlock, IfExpressionMissingThenBlockSub, IntLiteralTooLarge,
+    InvalidBlockMacroSegment, InvalidComparisonOperator, InvalidComparisonOperatorSub,
+    InvalidFloatLiteralSuffix, InvalidFloatLiteralWidth, InvalidIntLiteralWidth,
+    InvalidInterpolatedExpression, InvalidLiteralSuffix, InvalidLiteralSuffixOnTupleIndex,
+    InvalidLogicalOperator, InvalidLogicalOperatorSub, InvalidNumLiteralBasePrefix,
+    InvalidNumLiteralSuffix, LabeledLoopInBreak, LeadingPlusNotSupported, LeftArrowOperator,
+    LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath, MalformedLoopLabel,
+    MatchArmBodyWithoutBraces, MatchArmBodyWithoutBracesSugg, MissingCommaAfterMatchArm,
+    MissingInInForLoop, MissingInInForLoopSub, MissingSemicolonBeforeArray, NoFieldsForFnCall,
+    NotAsNegationOperator, NotAsNegationOperatorSub, OctalFloatLiteralNotSupported,
+    OuterAttributeNotAllowedOnIfElse, ParenthesesWithStructFields,
+    RequireColonAfterLabeledExpression, ShiftInterpretedAsGeneric, StructLiteralNotAllowedHere,
+    StructLiteralNotAllowedHereSugg, TildeAsUnaryOperator, UnexpectedTokenAfterLabel,
+    UnexpectedTokenAfterLabelSugg, WrapExpressionInParentheses,
 };
+use crate::maybe_recover_from_interpolated_ty_qpath;
 
 use core::mem;
 use rustc_ast::ptr::P;
@@ -38,6 +44,7 @@ use rustc_ast::{ClosureBinder, StmtKind};
 use rustc_ast_pretty::pprust;
 use rustc_errors::IntoDiagnostic;
 use rustc_errors::{Applicability, Diagnostic, PResult};
+use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP;
 use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_span::source_map::{self, Span, Spanned};
@@ -421,13 +428,11 @@ impl<'a> Parser<'a> {
     /// but the next token implies this should be parsed as an expression.
     /// For example: `if let Some(x) = x { x } else { 0 } / 2`.
     fn error_found_expr_would_be_stmt(&self, lhs: &Expr) {
-        let mut err = self.struct_span_err(
-            self.token.span,
-            &format!("expected expression, found `{}`", pprust::token_to_string(&self.token),),
-        );
-        err.span_label(self.token.span, "expected expression");
-        self.sess.expr_parentheses_needed(&mut err, lhs.span);
-        err.emit();
+        self.sess.emit_err(FoundExprWouldBeStmt {
+            span: self.token.span,
+            token: self.token.clone(),
+            suggestion: ExprParenthesesNeeded::surrounding(lhs.span),
+        });
     }
 
     /// Possibly translate the current token to an associative operator.
@@ -578,21 +583,16 @@ impl<'a> Parser<'a> {
                 make_it!(this, attrs, |this, _| this.parse_borrow_expr(lo))
             }
             token::BinOp(token::Plus) if this.look_ahead(1, |tok| tok.is_numeric_lit()) => {
-                let mut err = this.struct_span_err(lo, "leading `+` is not supported");
-                err.span_label(lo, "unexpected `+`");
+                let mut err =
+                    LeadingPlusNotSupported { span: lo, remove_plus: None, add_parentheses: None };
 
                 // a block on the LHS might have been intended to be an expression instead
                 if let Some(sp) = this.sess.ambiguous_block_expr_parse.borrow().get(&lo) {
-                    this.sess.expr_parentheses_needed(&mut err, *sp);
+                    err.add_parentheses = Some(ExprParenthesesNeeded::surrounding(*sp));
                 } else {
-                    err.span_suggestion_verbose(
-                        lo,
-                        "try removing the `+`",
-                        "",
-                        Applicability::MachineApplicable,
-                    );
+                    err.remove_plus = Some(lo);
                 }
-                err.emit();
+                this.sess.emit_err(err);
 
                 this.bump();
                 this.parse_prefix_expr(None)
@@ -755,9 +755,34 @@ impl<'a> Parser<'a> {
 
                 match self.parse_path(PathStyle::Expr) {
                     Ok(path) => {
-                        let (op_noun, op_verb) = match self.token.kind {
-                            token::Lt => ("comparison", "comparing"),
-                            token::BinOp(token::Shl) => ("shift", "shifting"),
+                        let span_after_type = parser_snapshot_after_type.token.span;
+                        let expr = mk_expr(
+                            self,
+                            lhs,
+                            self.mk_ty(path.span, TyKind::Path(None, path.clone())),
+                        );
+
+                        let args_span = self.look_ahead(1, |t| t.span).to(span_after_type);
+                        let suggestion = ComparisonOrShiftInterpretedAsGenericSugg {
+                            left: expr.span.shrink_to_lo(),
+                            right: expr.span.shrink_to_hi(),
+                        };
+
+                        match self.token.kind {
+                            token::Lt => self.sess.emit_err(ComparisonInterpretedAsGeneric {
+                                comparison: self.token.span,
+                                r#type: path,
+                                args: args_span,
+                                suggestion,
+                            }),
+                            token::BinOp(token::Shl) => {
+                                self.sess.emit_err(ShiftInterpretedAsGeneric {
+                                    shift: self.token.span,
+                                    r#type: path,
+                                    args: args_span,
+                                    suggestion,
+                                })
+                            }
                             _ => {
                                 // We can end up here even without `<` being the next token, for
                                 // example because `parse_ty_no_plus` returns `Err` on keywords,
@@ -771,33 +796,7 @@ impl<'a> Parser<'a> {
                         // Successfully parsed the type path leaving a `<` yet to parse.
                         type_err.cancel();
 
-                        // Report non-fatal diagnostics, keep `x as usize` as an expression
-                        // in AST and continue parsing.
-                        let msg = format!(
-                            "`<` is interpreted as a start of generic arguments for `{}`, not a {}",
-                            pprust::path_to_string(&path),
-                            op_noun,
-                        );
-                        let span_after_type = parser_snapshot_after_type.token.span;
-                        let expr =
-                            mk_expr(self, lhs, self.mk_ty(path.span, TyKind::Path(None, path)));
-
-                        self.struct_span_err(self.token.span, &msg)
-                            .span_label(
-                                self.look_ahead(1, |t| t.span).to(span_after_type),
-                                "interpreted as generic arguments",
-                            )
-                            .span_label(self.token.span, format!("not interpreted as {op_noun}"))
-                            .multipart_suggestion(
-                                &format!("try {op_verb} the cast value"),
-                                vec![
-                                    (expr.span.shrink_to_lo(), "(".to_string()),
-                                    (expr.span.shrink_to_hi(), ")".to_string()),
-                                ],
-                                Applicability::MachineApplicable,
-                            )
-                            .emit();
-
+                        // Keep `x as usize` as an expression in AST and continue parsing.
                         expr
                     }
                     Err(path_err) => {
@@ -1158,7 +1157,9 @@ impl<'a> Parser<'a> {
         }
         let span = self.prev_token.span;
         let field = ExprKind::Field(base, Ident::new(field, span));
-        self.expect_no_suffix(span, "a tuple index", suffix);
+        if let Some(suffix) = suffix {
+            self.expect_no_tuple_index_suffix(span, suffix);
+        }
         self.mk_expr(lo.to(span), field)
     }
 
@@ -1196,9 +1197,8 @@ impl<'a> Parser<'a> {
     ) -> Option<P<Expr>> {
         match (seq.as_mut(), snapshot) {
             (Err(err), Some((mut snapshot, ExprKind::Path(None, path)))) => {
-                let name = pprust::path_to_string(&path);
                 snapshot.bump(); // `(`
-                match snapshot.parse_struct_fields(path, false, Delimiter::Parenthesis) {
+                match snapshot.parse_struct_fields(path.clone(), false, Delimiter::Parenthesis) {
                     Ok((fields, ..))
                         if snapshot.eat(&token::CloseDelim(Delimiter::Parenthesis)) =>
                     {
@@ -1208,29 +1208,25 @@ impl<'a> Parser<'a> {
                         let close_paren = self.prev_token.span;
                         let span = lo.to(self.prev_token.span);
                         if !fields.is_empty() {
-                            let replacement_err = self.struct_span_err(
+                            let mut replacement_err = ParenthesesWithStructFields {
                                 span,
-                                "invalid `struct` delimiters or `fn` call arguments",
-                            );
-                            mem::replace(err, replacement_err).cancel();
-
-                            err.multipart_suggestion(
-                                &format!("if `{name}` is a struct, use braces as delimiters"),
-                                vec![
-                                    (open_paren, " { ".to_string()),
-                                    (close_paren, " }".to_string()),
-                                ],
-                                Applicability::MaybeIncorrect,
-                            );
-                            err.multipart_suggestion(
-                                &format!("if `{name}` is a function, use the arguments directly"),
-                                fields
-                                    .into_iter()
-                                    .map(|field| (field.span.until(field.expr.span), String::new()))
-                                    .collect(),
-                                Applicability::MaybeIncorrect,
-                            );
-                            err.emit();
+                                r#type: path,
+                                braces_for_struct: BracesForStructLiteral {
+                                    first: open_paren,
+                                    second: close_paren,
+                                },
+                                no_fields_for_fn: NoFieldsForFnCall {
+                                    fields: fields
+                                        .into_iter()
+                                        .map(|field| field.span.until(field.expr.span))
+                                        .collect(),
+                                },
+                            }
+                            .into_diagnostic(&self.sess.span_diagnostic);
+                            replacement_err.emit();
+
+                            let old_err = mem::replace(err, replacement_err);
+                            old_err.cancel();
                         } else {
                             err.emit();
                         }
@@ -1537,15 +1533,19 @@ impl<'a> Parser<'a> {
             && (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt))
         {
             // We're probably inside of a `Path<'a>` that needs a turbofish
-            self.sess.emit_err(UnexpectedTokenAfterLabel(self.token.span));
+            self.sess.emit_err(UnexpectedTokenAfterLabel {
+                span: self.token.span,
+                remove_label: None,
+                enclose_in_block: None,
+            });
             consume_colon = false;
             Ok(self.mk_expr_err(lo))
         } else {
-            // FIXME: use UnexpectedTokenAfterLabel, needs multipart suggestions
-            let msg = "expected `while`, `for`, `loop` or `{` after a label";
-
-            let mut err = self.struct_span_err(self.token.span, msg);
-            err.span_label(self.token.span, msg);
+            let mut err = UnexpectedTokenAfterLabel {
+                span: self.token.span,
+                remove_label: None,
+                enclose_in_block: None,
+            };
 
             // Continue as an expression in an effort to recover on `'label: non_block_expr`.
             let expr = self.parse_expr().map(|expr| {
@@ -1572,28 +1572,15 @@ impl<'a> Parser<'a> {
                 // If there are no breaks that may use this label, suggest removing the label and
                 // recover to the unmodified expression.
                 if !found_labeled_breaks {
-                    let msg = "consider removing the label";
-                    err.span_suggestion_verbose(
-                        lo.until(span),
-                        msg,
-                        "",
-                        Applicability::MachineApplicable,
-                    );
+                    err.remove_label = Some(lo.until(span));
 
                     return expr;
                 }
 
-                let sugg_msg = "consider enclosing expression in a block";
-                let suggestions = vec![
-                    (span.shrink_to_lo(), "{ ".to_owned()),
-                    (span.shrink_to_hi(), " }".to_owned()),
-                ];
-
-                err.multipart_suggestion_verbose(
-                    sugg_msg,
-                    suggestions,
-                    Applicability::MachineApplicable,
-                );
+                err.enclose_in_block = Some(UnexpectedTokenAfterLabelSugg {
+                    left: span.shrink_to_lo(),
+                    right: span.shrink_to_hi(),
+                });
 
                 // Replace `'label: non_block_expr` with `'label: {non_block_expr}` in order to suppress future errors about `break 'label`.
                 let stmt = self.mk_stmt(span, StmtKind::Expr(expr));
@@ -1601,7 +1588,7 @@ impl<'a> Parser<'a> {
                 self.mk_expr(span, ExprKind::Block(blk, label))
             });
 
-            err.emit();
+            self.sess.emit_err(err);
             expr
         }?;
 
@@ -1672,19 +1659,13 @@ impl<'a> Parser<'a> {
             // The value expression can be a labeled loop, see issue #86948, e.g.:
             // `loop { break 'label: loop { break 'label 42; }; }`
             let lexpr = self.parse_labeled_expr(label.take().unwrap(), true)?;
-            self.struct_span_err(
-                lexpr.span,
-                "parentheses are required around this expression to avoid confusion with a labeled break expression",
-            )
-            .multipart_suggestion(
-                "wrap the expression in parentheses",
-                vec![
-                    (lexpr.span.shrink_to_lo(), "(".to_string()),
-                    (lexpr.span.shrink_to_hi(), ")".to_string()),
-                ],
-                Applicability::MachineApplicable,
-            )
-            .emit();
+            self.sess.emit_err(LabeledLoopInBreak {
+                span: lexpr.span,
+                sub: WrapExpressionInParentheses {
+                    left: lexpr.span.shrink_to_lo(),
+                    right: lexpr.span.shrink_to_hi(),
+                },
+            });
             Some(lexpr)
         } else if self.token != token::OpenDelim(Delimiter::Brace)
             || !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
@@ -1756,9 +1737,8 @@ impl<'a> Parser<'a> {
                 };
                 if let Some(expr) = expr {
                     if matches!(expr.kind, ExprKind::Err) {
-                        let mut err = self
-                            .diagnostic()
-                            .struct_span_err(self.token.span, "invalid interpolated expression");
+                        let mut err = InvalidInterpolatedExpression { span: self.token.span }
+                            .into_diagnostic(&self.sess.span_diagnostic);
                         err.downgrade_to_delayed_bug();
                         return err;
                     }
@@ -1790,7 +1770,10 @@ impl<'a> Parser<'a> {
             });
             if let Some(token) = &recovered {
                 self.bump();
-                self.error_float_lits_must_have_int_part(&token);
+                self.sess.emit_err(FloatLiteralRequiresIntegerPart {
+                    span: token.span,
+                    correct: pprust::token_to_string(token).into_owned(),
+                });
             }
         }
 
@@ -1818,13 +1801,6 @@ impl<'a> Parser<'a> {
         }
     }
 
-    fn error_float_lits_must_have_int_part(&self, token: &Token) {
-        self.sess.emit_err(FloatLiteralRequiresIntegerPart {
-            span: token.span,
-            correct: pprust::token_to_string(token).into_owned(),
-        });
-    }
-
     fn report_lit_error(&self, err: LitError, lit: token::Lit, span: Span) {
         // Checks if `s` looks like i32 or u1234 etc.
         fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool {
@@ -1853,11 +1829,13 @@ impl<'a> Parser<'a> {
             // by lexer, so here we don't report it the second time.
             LitError::LexerError => {}
             LitError::InvalidSuffix => {
-                self.expect_no_suffix(
-                    span,
-                    &format!("{} {} literal", kind.article(), kind.descr()),
-                    suffix,
-                );
+                if let Some(suffix) = suffix {
+                    self.sess.emit_err(InvalidLiteralSuffix {
+                        span,
+                        kind: format!("{}", kind.descr()),
+                        suffix,
+                    });
+                }
             }
             LitError::InvalidIntSuffix => {
                 let suf = suffix.expect("suffix error with no suffix");
@@ -1883,15 +1861,12 @@ impl<'a> Parser<'a> {
                 }
             }
             LitError::NonDecimalFloat(base) => {
-                let descr = match base {
-                    16 => "hexadecimal",
-                    8 => "octal",
-                    2 => "binary",
+                match base {
+                    16 => self.sess.emit_err(HexadecimalFloatLiteralNotSupported { span }),
+                    8 => self.sess.emit_err(OctalFloatLiteralNotSupported { span }),
+                    2 => self.sess.emit_err(BinaryFloatLiteralNotSupported { span }),
                     _ => unreachable!(),
                 };
-                self.struct_span_err(span, &format!("{descr} float literal is not supported"))
-                    .span_label(span, "not supported")
-                    .emit();
             }
             LitError::IntTooLarge => {
                 self.sess.emit_err(IntLiteralTooLarge { span });
@@ -1899,38 +1874,17 @@ impl<'a> Parser<'a> {
         }
     }
 
-    pub(super) fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option<Symbol>) {
-        if let Some(suf) = suffix {
-            let mut err = if kind == "a tuple index"
-                && [sym::i32, sym::u32, sym::isize, sym::usize].contains(&suf)
-            {
-                // #59553: warn instead of reject out of hand to allow the fix to percolate
-                // through the ecosystem when people fix their macros
-                let mut err = self
-                    .sess
-                    .span_diagnostic
-                    .struct_span_warn(sp, &format!("suffixes on {kind} are invalid"));
-                err.note(&format!(
-                    "`{}` is *temporarily* accepted on tuple index fields as it was \
-                        incorrectly accepted on stable for a few releases",
-                    suf,
-                ));
-                err.help(
-                    "on proc macros, you'll want to use `syn::Index::from` or \
-                        `proc_macro::Literal::*_unsuffixed` for code that will desugar \
-                        to tuple field access",
-                );
-                err.note(
-                    "see issue #60210 <https://github.com/rust-lang/rust/issues/60210> \
-                     for more information",
-                );
-                err
-            } else {
-                self.struct_span_err(sp, &format!("suffixes on {kind} are invalid"))
-                    .forget_guarantee()
-            };
-            err.span_label(sp, format!("invalid suffix `{suf}`"));
-            err.emit();
+    pub(super) fn expect_no_tuple_index_suffix(&self, span: Span, suffix: Symbol) {
+        if [sym::i32, sym::u32, sym::isize, sym::usize].contains(&suffix) {
+            // #59553: warn instead of reject out of hand to allow the fix to percolate
+            // through the ecosystem when people fix their macros
+            self.sess.emit_warning(InvalidLiteralSuffixOnTupleIndex {
+                span,
+                suffix,
+                exception: Some(()),
+            });
+        } else {
+            self.sess.emit_err(InvalidLiteralSuffixOnTupleIndex { span, suffix, exception: None });
         }
     }
 
@@ -1964,14 +1918,13 @@ impl<'a> Parser<'a> {
         let mut snapshot = self.create_snapshot_for_diagnostic();
         match snapshot.parse_array_or_repeat_expr(Delimiter::Brace) {
             Ok(arr) => {
-                let hi = snapshot.prev_token.span;
-                self.struct_span_err(arr.span, "this is a block expression, not an array")
-                    .multipart_suggestion(
-                        "to make an array, use square brackets instead of curly braces",
-                        vec![(lo, "[".to_owned()), (hi, "]".to_owned())],
-                        Applicability::MaybeIncorrect,
-                    )
-                    .emit();
+                self.sess.emit_err(ArrayBracketsInsteadOfSpaces {
+                    span: arr.span,
+                    sub: ArrayBracketsInsteadOfSpacesSugg {
+                        left: lo,
+                        right: snapshot.prev_token.span,
+                    },
+                });
 
                 self.restore_snapshot(snapshot);
                 Some(self.mk_expr_err(arr.span))
@@ -2134,7 +2087,8 @@ impl<'a> Parser<'a> {
             // Check for `move async` and recover
             if self.check_keyword(kw::Async) {
                 let move_async_span = self.token.span.with_lo(self.prev_token.span.data().lo);
-                Err(self.incorrect_move_async_order_found(move_async_span))
+                Err(AsyncMoveOrderIncorrect { span: move_async_span }
+                    .into_diagnostic(&self.sess.span_diagnostic))
             } else {
                 Ok(CaptureBy::Value)
             }
@@ -2515,39 +2469,22 @@ impl<'a> Parser<'a> {
         self.bump(); // `;`
         let mut stmts =
             vec![self.mk_stmt(first_expr.span, ast::StmtKind::Expr(first_expr.clone()))];
-        let err = |this: &mut Parser<'_>, stmts: Vec<ast::Stmt>| {
+        let err = |this: &Parser<'_>, stmts: Vec<ast::Stmt>| {
             let span = stmts[0].span.to(stmts[stmts.len() - 1].span);
-            let mut err = this.struct_span_err(span, "`match` arm body without braces");
-            let (these, s, are) =
-                if stmts.len() > 1 { ("these", "s", "are") } else { ("this", "", "is") };
-            err.span_label(
-                span,
-                &format!(
-                    "{these} statement{s} {are} not surrounded by a body",
-                    these = these,
-                    s = s,
-                    are = are
-                ),
-            );
-            err.span_label(arrow_span, "while parsing the `match` arm starting here");
-            if stmts.len() > 1 {
-                err.multipart_suggestion(
-                    &format!("surround the statement{s} with a body"),
-                    vec![
-                        (span.shrink_to_lo(), "{ ".to_string()),
-                        (span.shrink_to_hi(), " }".to_string()),
-                    ],
-                    Applicability::MachineApplicable,
-                );
-            } else {
-                err.span_suggestion(
-                    semi_sp,
-                    "use a comma to end a `match` arm expression",
-                    ",",
-                    Applicability::MachineApplicable,
-                );
-            }
-            err.emit();
+
+            this.sess.emit_err(MatchArmBodyWithoutBraces {
+                statements: span,
+                arrow: arrow_span,
+                num_statements: stmts.len(),
+                sub: if stmts.len() > 1 {
+                    MatchArmBodyWithoutBracesSugg::AddBraces {
+                        left: span.shrink_to_lo(),
+                        right: span.shrink_to_hi(),
+                    }
+                } else {
+                    MatchArmBodyWithoutBracesSugg::UseComma { semicolon: semi_sp }
+                },
+            });
             this.mk_expr_err(span)
         };
         // We might have either a `,` -> `;` typo, or a block without braces. We need
@@ -2836,23 +2773,19 @@ impl<'a> Parser<'a> {
             let expr = self.parse_struct_expr(qself.cloned(), path.clone(), true);
             if let (Ok(expr), false) = (&expr, struct_allowed) {
                 // This is a struct literal, but we don't can't accept them here.
-                self.error_struct_lit_not_allowed_here(path.span, expr.span);
+                self.sess.emit_err(StructLiteralNotAllowedHere {
+                    span: expr.span,
+                    sub: StructLiteralNotAllowedHereSugg {
+                        left: path.span.shrink_to_lo(),
+                        right: expr.span.shrink_to_hi(),
+                    },
+                });
             }
             return Some(expr);
         }
         None
     }
 
-    fn error_struct_lit_not_allowed_here(&self, lo: Span, sp: Span) {
-        self.struct_span_err(sp, "struct literals are not allowed here")
-            .multipart_suggestion(
-                "surround the struct literal with parentheses",
-                vec![(lo.shrink_to_lo(), "(".to_string()), (sp.shrink_to_hi(), ")".to_string())],
-                Applicability::MachineApplicable,
-            )
-            .emit();
-    }
-
     pub(super) fn parse_struct_fields(
         &mut self,
         pth: ast::Path,
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index e55b5ce71cd..c8a8e00b1fa 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1,4 +1,6 @@
-use super::diagnostics::{dummy_arg, ConsumeClosingDelim, Error};
+use crate::errors::{DocCommentDoesNotDocumentAnything, UseEmptyBlockNotSemi};
+
+use super::diagnostics::{dummy_arg, ConsumeClosingDelim};
 use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
 use super::{AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken};
 
@@ -13,7 +15,7 @@ use rustc_ast::{EnumDef, FieldDef, Generics, TraitRef, Ty, TyKind, Variant, Vari
 use rustc_ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, VisibilityKind};
 use rustc_ast::{MacArgs, MacCall, MacDelimiter};
 use rustc_ast_pretty::pprust;
-use rustc_errors::{struct_span_err, Applicability, PResult, StashKey};
+use rustc_errors::{struct_span_err, Applicability, IntoDiagnostic, PResult, StashKey};
 use rustc_span::edition::Edition;
 use rustc_span::lev_distance::lev_distance;
 use rustc_span::source_map::{self, Span};
@@ -664,6 +666,14 @@ impl<'a> Parser<'a> {
         mut parse_item: impl FnMut(&mut Parser<'a>) -> PResult<'a, Option<Option<T>>>,
     ) -> PResult<'a, Vec<T>> {
         let open_brace_span = self.token.span;
+
+        // Recover `impl Ty;` instead of `impl Ty {}`
+        if self.token == TokenKind::Semi {
+            self.sess.emit_err(UseEmptyBlockNotSemi { span: self.token.span });
+            self.bump();
+            return Ok(vec![]);
+        }
+
         self.expect(&token::OpenDelim(Delimiter::Brace))?;
         attrs.extend(self.parse_inner_attributes()?);
 
@@ -750,8 +760,8 @@ impl<'a> Parser<'a> {
                 )
                 .span_label(self.token.span, "this doc comment doesn't document anything")
                 .help(
-                    "doc comments must come before what they document, maybe a \
-                    comment was intended with `//`?",
+                    "doc comments must come before what they document, if a comment was \
+                    intended use `//`",
                 )
                 .emit();
                 self.bump();
@@ -1283,12 +1293,10 @@ impl<'a> Parser<'a> {
     /// Parses an enum declaration.
     fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> {
         if self.token.is_keyword(kw::Struct) {
-            let mut err = self.struct_span_err(
-                self.prev_token.span.to(self.token.span),
-                "`enum` and `struct` are mutually exclusive",
-            );
+            let span = self.prev_token.span.to(self.token.span);
+            let mut err = self.struct_span_err(span, "`enum` and `struct` are mutually exclusive");
             err.span_suggestion(
-                self.prev_token.span.to(self.token.span),
+                span,
                 "replace `enum struct` with",
                 "enum",
                 Applicability::MachineApplicable,
@@ -1305,12 +1313,20 @@ impl<'a> Parser<'a> {
         let mut generics = self.parse_generics()?;
         generics.where_clause = self.parse_where_clause()?;
 
-        let (variants, _) = self
-            .parse_delim_comma_seq(Delimiter::Brace, |p| p.parse_enum_variant())
-            .map_err(|e| {
-                self.recover_stmt();
-                e
-            })?;
+        // Possibly recover `enum Foo;` instead of `enum Foo {}`
+        let (variants, _) = if self.token == TokenKind::Semi {
+            self.sess.emit_err(UseEmptyBlockNotSemi { span: self.token.span });
+            self.bump();
+            (vec![], false)
+        } else {
+            self.parse_delim_comma_seq(Delimiter::Brace, |p| p.parse_enum_variant()).map_err(
+                |mut e| {
+                    e.span_label(id.span, "while parsing this enum");
+                    self.recover_stmt();
+                    e
+                },
+            )?
+        };
 
         let enum_definition = EnumDef { variants: variants.into_iter().flatten().collect() };
         Ok((id, ItemKind::Enum(enum_definition, generics)))
@@ -1332,7 +1348,8 @@ impl<'a> Parser<'a> {
 
                 let struct_def = if this.check(&token::OpenDelim(Delimiter::Brace)) {
                     // Parse a struct variant.
-                    let (fields, recovered) = this.parse_record_struct_body("struct", false)?;
+                    let (fields, recovered) =
+                        this.parse_record_struct_body("struct", ident.span, false)?;
                     VariantData::Struct(fields, recovered)
                 } else if this.check(&token::OpenDelim(Delimiter::Parenthesis)) {
                     VariantData::Tuple(this.parse_tuple_struct_body()?, DUMMY_NODE_ID)
@@ -1386,8 +1403,11 @@ impl<'a> Parser<'a> {
                 VariantData::Unit(DUMMY_NODE_ID)
             } else {
                 // If we see: `struct Foo<T> where T: Copy { ... }`
-                let (fields, recovered) =
-                    self.parse_record_struct_body("struct", generics.where_clause.has_where_token)?;
+                let (fields, recovered) = self.parse_record_struct_body(
+                    "struct",
+                    class_name.span,
+                    generics.where_clause.has_where_token,
+                )?;
                 VariantData::Struct(fields, recovered)
             }
         // No `where` so: `struct Foo<T>;`
@@ -1395,8 +1415,11 @@ impl<'a> Parser<'a> {
             VariantData::Unit(DUMMY_NODE_ID)
         // Record-style struct definition
         } else if self.token == token::OpenDelim(Delimiter::Brace) {
-            let (fields, recovered) =
-                self.parse_record_struct_body("struct", generics.where_clause.has_where_token)?;
+            let (fields, recovered) = self.parse_record_struct_body(
+                "struct",
+                class_name.span,
+                generics.where_clause.has_where_token,
+            )?;
             VariantData::Struct(fields, recovered)
         // Tuple-style struct definition with optional where-clause.
         } else if self.token == token::OpenDelim(Delimiter::Parenthesis) {
@@ -1425,12 +1448,18 @@ impl<'a> Parser<'a> {
 
         let vdata = if self.token.is_keyword(kw::Where) {
             generics.where_clause = self.parse_where_clause()?;
-            let (fields, recovered) =
-                self.parse_record_struct_body("union", generics.where_clause.has_where_token)?;
+            let (fields, recovered) = self.parse_record_struct_body(
+                "union",
+                class_name.span,
+                generics.where_clause.has_where_token,
+            )?;
             VariantData::Struct(fields, recovered)
         } else if self.token == token::OpenDelim(Delimiter::Brace) {
-            let (fields, recovered) =
-                self.parse_record_struct_body("union", generics.where_clause.has_where_token)?;
+            let (fields, recovered) = self.parse_record_struct_body(
+                "union",
+                class_name.span,
+                generics.where_clause.has_where_token,
+            )?;
             VariantData::Struct(fields, recovered)
         } else {
             let token_str = super::token_descr(&self.token);
@@ -1446,6 +1475,7 @@ impl<'a> Parser<'a> {
     fn parse_record_struct_body(
         &mut self,
         adt_ty: &str,
+        ident_span: Span,
         parsed_where: bool,
     ) -> PResult<'a, (Vec<FieldDef>, /* recovered */ bool)> {
         let mut fields = Vec::new();
@@ -1460,6 +1490,7 @@ impl<'a> Parser<'a> {
                 match field {
                     Ok(field) => fields.push(field),
                     Err(mut err) => {
+                        err.span_label(ident_span, format!("while parsing this {adt_ty}"));
                         err.emit();
                         break;
                     }
@@ -1555,7 +1586,10 @@ impl<'a> Parser<'a> {
             token::CloseDelim(Delimiter::Brace) => {}
             token::DocComment(..) => {
                 let previous_span = self.prev_token.span;
-                let mut err = self.span_err(self.token.span, Error::UselessDocComment);
+                let mut err = DocCommentDoesNotDocumentAnything {
+                    span: self.token.span,
+                    missing_comma: None,
+                };
                 self.bump(); // consume the doc comment
                 let comma_after_doc_seen = self.eat(&token::Comma);
                 // `seen_comma` is always false, because we are inside doc block
@@ -1564,18 +1598,13 @@ impl<'a> Parser<'a> {
                     seen_comma = true;
                 }
                 if comma_after_doc_seen || self.token == token::CloseDelim(Delimiter::Brace) {
-                    err.emit();
+                    self.sess.emit_err(err);
                 } else {
                     if !seen_comma {
                         let sp = self.sess.source_map().next_point(previous_span);
-                        err.span_suggestion(
-                            sp,
-                            "missing comma here",
-                            ",",
-                            Applicability::MachineApplicable,
-                        );
+                        err.missing_comma = Some(sp);
                     }
-                    return Err(err);
+                    return Err(err.into_diagnostic(&self.sess.span_diagnostic));
                 }
             }
             _ => {
@@ -1715,6 +1744,7 @@ impl<'a> Parser<'a> {
     fn parse_field_ident(&mut self, adt_ty: &str, lo: Span) -> PResult<'a, Ident> {
         let (ident, is_raw) = self.ident_or_err()?;
         if !is_raw && ident.is_reserved() {
+            let snapshot = self.create_snapshot_for_diagnostic();
             let err = if self.check_fn_front_matter(false) {
                 let inherited_vis = Visibility {
                     span: rustc_span::DUMMY_SP,
@@ -1735,6 +1765,22 @@ impl<'a> Parser<'a> {
                 err.help("unlike in C++, Java, and C#, functions are declared in `impl` blocks");
                 err.help("see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information");
                 err
+            } else if self.eat_keyword(kw::Struct) {
+                match self.parse_item_struct() {
+                    Ok((ident, _)) => {
+                        let mut err = self.struct_span_err(
+                            lo.with_hi(ident.span.hi()),
+                            &format!("structs are not allowed in {adt_ty} definitions"),
+                        );
+                        err.help("consider creating a new `struct` definition instead of nesting");
+                        err
+                    }
+                    Err(err) => {
+                        err.cancel();
+                        self.restore_snapshot(snapshot);
+                        self.expected_ident_found()
+                    }
+                }
             } else {
                 self.expected_ident_found()
             };
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 4cb198561e0..2aebaf7c3af 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -13,7 +13,6 @@ mod ty;
 use crate::lexer::UnmatchedBrace;
 pub use attr_wrapper::AttrWrapper;
 pub use diagnostics::AttemptLocalParseRecovery;
-use diagnostics::Error;
 pub(crate) use item::FnParseMode;
 pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma};
 pub use path::PathStyle;
@@ -32,7 +31,7 @@ use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::PResult;
 use rustc_errors::{
-    struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, MultiSpan,
+    Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, IntoDiagnostic, MultiSpan,
 };
 use rustc_session::parse::ParseSess;
 use rustc_span::source_map::{Span, DUMMY_SP};
@@ -41,6 +40,11 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use std::ops::Range;
 use std::{cmp, mem, slice};
 
+use crate::errors::{
+    DocCommentDoesNotDocumentAnything, IncorrectVisibilityRestriction, MismatchedClosingDelimiter,
+    NonStringAbiLiteral,
+};
+
 bitflags::bitflags! {
     struct Restrictions: u8 {
         const STMT_EXPR         = 1 << 0;
@@ -406,24 +410,39 @@ pub enum FollowedByType {
     No,
 }
 
-fn token_descr_opt(token: &Token) -> Option<&'static str> {
-    Some(match token.kind {
-        _ if token.is_special_ident() => "reserved identifier",
-        _ if token.is_used_keyword() => "keyword",
-        _ if token.is_unused_keyword() => "reserved keyword",
-        token::DocComment(..) => "doc comment",
-        _ => return None,
-    })
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub enum TokenDescription {
+    ReservedIdentifier,
+    Keyword,
+    ReservedKeyword,
+    DocComment,
 }
 
-pub(super) fn token_descr(token: &Token) -> String {
-    let token_str = pprust::token_to_string(token);
-    match token_descr_opt(token) {
-        Some(prefix) => format!("{} `{}`", prefix, token_str),
-        _ => format!("`{}`", token_str),
+impl TokenDescription {
+    pub fn from_token(token: &Token) -> Option<Self> {
+        match token.kind {
+            _ if token.is_special_ident() => Some(TokenDescription::ReservedIdentifier),
+            _ if token.is_used_keyword() => Some(TokenDescription::Keyword),
+            _ if token.is_unused_keyword() => Some(TokenDescription::ReservedKeyword),
+            token::DocComment(..) => Some(TokenDescription::DocComment),
+            _ => None,
+        }
     }
 }
 
+pub(super) fn token_descr(token: &Token) -> String {
+    let name = pprust::token_to_string(token).to_string();
+
+    let kind = TokenDescription::from_token(token).map(|kind| match kind {
+        TokenDescription::ReservedIdentifier => "reserved identifier",
+        TokenDescription::Keyword => "keyword",
+        TokenDescription::ReservedKeyword => "reserved keyword",
+        TokenDescription::DocComment => "doc comment",
+    });
+
+    if let Some(kind) = kind { format!("{} `{}`", kind, name) } else { format!("`{}`", name) }
+}
+
 impl<'a> Parser<'a> {
     pub fn new(
         sess: &'a ParseSess,
@@ -518,9 +537,11 @@ impl<'a> Parser<'a> {
 
     fn ident_or_err(&mut self) -> PResult<'a, (Ident, /* is_raw */ bool)> {
         self.token.ident().ok_or_else(|| match self.prev_token.kind {
-            TokenKind::DocComment(..) => {
-                self.span_err(self.prev_token.span, Error::UselessDocComment)
+            TokenKind::DocComment(..) => DocCommentDoesNotDocumentAnything {
+                span: self.prev_token.span,
+                missing_comma: None,
             }
+            .into_diagnostic(&self.sess.span_diagnostic),
             _ => self.expected_ident_found(),
         })
     }
@@ -1144,7 +1165,9 @@ impl<'a> Parser<'a> {
     fn parse_field_name(&mut self) -> PResult<'a, Ident> {
         if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) = self.token.kind
         {
-            self.expect_no_suffix(self.token.span, "a tuple index", suffix);
+            if let Some(suffix) = suffix {
+                self.expect_no_tuple_index_suffix(self.token.span, suffix);
+            }
             self.bump();
             Ok(Ident::new(symbol, self.prev_token.span))
         } else {
@@ -1342,23 +1365,8 @@ impl<'a> Parser<'a> {
         let path = self.parse_path(PathStyle::Mod)?;
         self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)`
 
-        let msg = "incorrect visibility restriction";
-        let suggestion = r##"some possible visibility restrictions are:
-`pub(crate)`: visible only on the current crate
-`pub(super)`: visible only in the current module's parent
-`pub(in path::to::module)`: visible only on the specified path"##;
-
         let path_str = pprust::path_to_string(&path);
-
-        struct_span_err!(self.sess.span_diagnostic, path.span, E0704, "{}", msg)
-            .help(suggestion)
-            .span_suggestion(
-                path.span,
-                &format!("make this visible only to module `{}` with `in`", path_str),
-                format!("in {}", path_str),
-                Applicability::MachineApplicable,
-            )
-            .emit();
+        self.sess.emit_err(IncorrectVisibilityRestriction { span: path.span, inner_str: path_str });
 
         Ok(())
     }
@@ -1384,14 +1392,7 @@ impl<'a> Parser<'a> {
             Err(Some(lit)) => match lit.kind {
                 ast::LitKind::Err => None,
                 _ => {
-                    self.struct_span_err(lit.span, "non-string ABI literal")
-                        .span_suggestion(
-                            lit.span,
-                            "specify the ABI with a string literal",
-                            "\"C\"",
-                            Applicability::MaybeIncorrect,
-                        )
-                        .emit();
+                    self.sess.emit_err(NonStringAbiLiteral { span: lit.span });
                     None
                 }
             },
@@ -1432,25 +1433,18 @@ pub(crate) fn make_unclosed_delims_error(
     // `None` here means an `Eof` was found. We already emit those errors elsewhere, we add them to
     // `unmatched_braces` only for error recovery in the `Parser`.
     let found_delim = unmatched.found_delim?;
-    let span: MultiSpan = if let Some(sp) = unmatched.unclosed_span {
-        vec![unmatched.found_span, sp].into()
-    } else {
-        unmatched.found_span.into()
-    };
-    let mut err = sess.span_diagnostic.struct_span_err(
-        span,
-        &format!(
-            "mismatched closing delimiter: `{}`",
-            pprust::token_kind_to_string(&token::CloseDelim(found_delim)),
-        ),
-    );
-    err.span_label(unmatched.found_span, "mismatched closing delimiter");
-    if let Some(sp) = unmatched.candidate_span {
-        err.span_label(sp, "closing delimiter possibly meant for this");
-    }
+    let mut spans = vec![unmatched.found_span];
     if let Some(sp) = unmatched.unclosed_span {
-        err.span_label(sp, "unclosed delimiter");
-    }
+        spans.push(sp);
+    };
+    let err = MismatchedClosingDelimiter {
+        spans,
+        delimiter: pprust::token_kind_to_string(&token::CloseDelim(found_delim)).to_string(),
+        unmatched: unmatched.found_span,
+        opening_candidate: unmatched.candidate_span,
+        unclosed: unmatched.unclosed_span,
+    }
+    .into_diagnostic(&sess.span_diagnostic);
     Some(err)
 }
 
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 120a3c267f1..542a1ac5dc6 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -1,5 +1,5 @@
 use super::{ForceCollect, Parser, PathStyle, TrailingToken};
-use crate::parser::diagnostics::RemoveLet;
+use crate::errors::RemoveLet;
 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
 use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
 use rustc_ast::ptr::P;
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index 3d957406b19..a61e77b7c3b 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -1,7 +1,5 @@
-use super::attr::DEFAULT_INNER_ATTR_FORBIDDEN;
-use super::diagnostics::{
-    AttemptLocalParseRecovery, Error, InvalidVariableDeclaration, InvalidVariableDeclarationSub,
-};
+use super::attr::InnerAttrForbiddenReason;
+use super::diagnostics::AttemptLocalParseRecovery;
 use super::expr::LhsExpr;
 use super::pat::RecoverComma;
 use super::path::PathStyle;
@@ -9,6 +7,12 @@ use super::TrailingToken;
 use super::{
     AttrWrapper, BlockMode, FnParseMode, ForceCollect, Parser, Restrictions, SemiColonMode,
 };
+use crate::errors::{
+    AssignmentElseNotAllowed, CompoundAssignmentExpressionInLet, ConstLetMutuallyExclusive,
+    DocCommentDoesNotDocumentAnything, ExpectedStatementAfterOuterAttr, InvalidCurlyInLetElse,
+    InvalidExpressionInLetElse, InvalidVariableDeclaration, InvalidVariableDeclarationSub,
+    WrapExpressionInParentheses,
+};
 use crate::maybe_whole;
 
 use rustc_ast as ast;
@@ -112,11 +116,7 @@ impl<'a> Parser<'a> {
                 let bl = self.parse_block()?;
                 // Destructuring assignment ... else.
                 // This is not allowed, but point it out in a nice way.
-                let mut err = self.struct_span_err(
-                    e.span.to(bl.span),
-                    "<assignment> ... else { ... } is not allowed",
-                );
-                err.emit();
+                self.sess.emit_err(AssignmentElseNotAllowed { span: e.span.to(bl.span) });
             }
             self.mk_stmt(lo.to(e.span), StmtKind::Expr(e))
         } else {
@@ -202,9 +202,12 @@ impl<'a> Parser<'a> {
     fn error_outer_attrs(&self, attrs: &[Attribute]) {
         if let [.., last] = attrs {
             if last.is_doc_comment() {
-                self.span_err(last.span, Error::UselessDocComment).emit();
+                self.sess.emit_err(DocCommentDoesNotDocumentAnything {
+                    span: last.span,
+                    missing_comma: None,
+                });
             } else if attrs.iter().any(|a| a.style == AttrStyle::Outer) {
-                self.struct_span_err(last.span, "expected statement after outer attribute").emit();
+                self.sess.emit_err(ExpectedStatementAfterOuterAttr { span: last.span });
             }
         }
     }
@@ -255,17 +258,7 @@ impl<'a> Parser<'a> {
         let lo = self.prev_token.span;
 
         if self.token.is_keyword(kw::Const) && self.look_ahead(1, |t| t.is_ident()) {
-            self.struct_span_err(
-                lo.to(self.token.span),
-                "`const` and `let` are mutually exclusive",
-            )
-            .span_suggestion(
-                lo.to(self.token.span),
-                "remove `let`",
-                "const",
-                Applicability::MaybeIncorrect,
-            )
-            .emit();
+            self.sess.emit_err(ConstLetMutuallyExclusive { span: lo.to(self.token.span) });
             self.bump();
         }
 
@@ -363,44 +356,27 @@ impl<'a> Parser<'a> {
     fn check_let_else_init_bool_expr(&self, init: &ast::Expr) {
         if let ast::ExprKind::Binary(op, ..) = init.kind {
             if op.node.lazy() {
-                let suggs = vec![
-                    (init.span.shrink_to_lo(), "(".to_string()),
-                    (init.span.shrink_to_hi(), ")".to_string()),
-                ];
-                self.struct_span_err(
-                    init.span,
-                    &format!(
-                        "a `{}` expression cannot be directly assigned in `let...else`",
-                        op.node.to_string()
-                    ),
-                )
-                .multipart_suggestion(
-                    "wrap the expression in parentheses",
-                    suggs,
-                    Applicability::MachineApplicable,
-                )
-                .emit();
+                self.sess.emit_err(InvalidExpressionInLetElse {
+                    span: init.span,
+                    operator: op.node.to_string(),
+                    sugg: WrapExpressionInParentheses {
+                        left: init.span.shrink_to_lo(),
+                        right: init.span.shrink_to_hi(),
+                    },
+                });
             }
         }
     }
 
     fn check_let_else_init_trailing_brace(&self, init: &ast::Expr) {
         if let Some(trailing) = classify::expr_trailing_brace(init) {
-            let err_span = trailing.span.with_lo(trailing.span.hi() - BytePos(1));
-            let suggs = vec![
-                (trailing.span.shrink_to_lo(), "(".to_string()),
-                (trailing.span.shrink_to_hi(), ")".to_string()),
-            ];
-            self.struct_span_err(
-                err_span,
-                "right curly brace `}` before `else` in a `let...else` statement not allowed",
-            )
-            .multipart_suggestion(
-                "try wrapping the expression in parentheses",
-                suggs,
-                Applicability::MachineApplicable,
-            )
-            .emit();
+            self.sess.emit_err(InvalidCurlyInLetElse {
+                span: trailing.span.with_lo(trailing.span.hi() - BytePos(1)),
+                sugg: WrapExpressionInParentheses {
+                    left: trailing.span.shrink_to_lo(),
+                    right: trailing.span.shrink_to_hi(),
+                },
+            });
         }
     }
 
@@ -409,18 +385,7 @@ impl<'a> Parser<'a> {
         let eq_consumed = match self.token.kind {
             token::BinOpEq(..) => {
                 // Recover `let x <op>= 1` as `let x = 1`
-                self.struct_span_err(
-                    self.token.span,
-                    "can't reassign to an uninitialized variable",
-                )
-                .span_suggestion_short(
-                    self.token.span,
-                    "initialize the variable",
-                    "=",
-                    Applicability::MaybeIncorrect,
-                )
-                .help("if you meant to overwrite, remove the `let` binding")
-                .emit();
+                self.sess.emit_err(CompoundAssignmentExpressionInLet { span: self.token.span });
                 self.bump();
                 true
             }
@@ -434,7 +399,12 @@ impl<'a> Parser<'a> {
     pub(super) fn parse_block(&mut self) -> PResult<'a, P<Block>> {
         let (attrs, block) = self.parse_inner_attrs_and_block()?;
         if let [.., last] = &*attrs {
-            self.error_on_forbidden_inner_attr(last.span, DEFAULT_INNER_ATTR_FORBIDDEN);
+            self.error_on_forbidden_inner_attr(
+                last.span,
+                super::attr::InnerAttrPolicy::Forbidden(Some(
+                    InnerAttrForbiddenReason::InCodeBlock,
+                )),
+            );
         }
         Ok(block)
     }
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index b47f0c09783..2a8512acf8c 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -397,10 +397,13 @@ impl<'a> Parser<'a> {
     fn parse_ty_ptr(&mut self) -> PResult<'a, TyKind> {
         let mutbl = self.parse_const_or_mut().unwrap_or_else(|| {
             let span = self.prev_token.span;
-            let msg = "expected mut or const in raw pointer type";
-            self.struct_span_err(span, msg)
-                .span_label(span, msg)
-                .help("use `*mut T` or `*const T` as appropriate")
+            self.struct_span_err(span, "expected `mut` or `const` keyword in raw pointer type")
+                .span_suggestions(
+                    span.shrink_to_hi(),
+                    "add `mut` or `const` here",
+                    ["mut ".to_string(), "const ".to_string()].into_iter(),
+                    Applicability::HasPlaceholders,
+                )
                 .emit();
             Mutability::Not
         });
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index a9e502016aa..df22d79f82e 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -224,7 +224,7 @@ impl<'a> Iterator for Parser<'a> {
                 '{' => {
                     let curr_last_brace = self.last_opening_brace;
                     let byte_pos = self.to_span_index(pos);
-                    let lbrace_end = InnerOffset(byte_pos.0 + 1);
+                    let lbrace_end = self.to_span_index(pos + 1);
                     self.last_opening_brace = Some(byte_pos.to(lbrace_end));
                     self.cur.next();
                     if self.consume('{') {
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index f112f1274b8..897a0db930c 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -11,9 +11,11 @@ use rustc_errors::{fluent, struct_span_err, Applicability, MultiSpan};
 use rustc_expand::base::resolve_path;
 use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
 use rustc_hir as hir;
-use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID};
+use rustc_hir::{
+    self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID, CRATE_OWNER_ID,
+};
 use rustc_hir::{MethodKind, Target};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault;
@@ -35,7 +37,7 @@ pub(crate) fn target_from_impl_item<'tcx>(
     match impl_item.kind {
         hir::ImplItemKind::Const(..) => Target::AssocConst,
         hir::ImplItemKind::Fn(..) => {
-            let parent_def_id = tcx.hir().get_parent_item(impl_item.hir_id());
+            let parent_def_id = tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
             let containing_item = tcx.hir().expect_item(parent_def_id);
             let containing_impl_is_for_trait = match &containing_item.kind {
                 hir::ItemKind::Impl(impl_) => impl_.of_trait.is_some(),
@@ -640,7 +642,7 @@ impl CheckAttrVisitor<'_> {
         let span = meta.span();
         if let Some(location) = match target {
             Target::AssocTy => {
-                let parent_def_id = self.tcx.hir().get_parent_item(hir_id);
+                let parent_def_id = self.tcx.hir().get_parent_item(hir_id).def_id;
                 let containing_item = self.tcx.hir().expect_item(parent_def_id);
                 if Target::from_item(containing_item) == Target::Impl {
                     Some("type alias in implementation block")
@@ -649,7 +651,7 @@ impl CheckAttrVisitor<'_> {
                 }
             }
             Target::AssocConst => {
-                let parent_def_id = self.tcx.hir().get_parent_item(hir_id);
+                let parent_def_id = self.tcx.hir().get_parent_item(hir_id).def_id;
                 let containing_item = self.tcx.hir().expect_item(parent_def_id);
                 // We can't link to trait impl's consts.
                 let err = "associated constant in trait implementation block";
@@ -878,7 +880,7 @@ impl CheckAttrVisitor<'_> {
             self.tcx.struct_span_lint_hir(INVALID_DOC_ATTRIBUTES, hir_id, meta.span(), |lint| {
                 let mut err = lint.build(fluent::passes::attr_crate_level);
                 if attr.style == AttrStyle::Outer
-                    && self.tcx.hir().get_parent_item(hir_id) == CRATE_DEF_ID
+                    && self.tcx.hir().get_parent_item(hir_id) == CRATE_OWNER_ID
                 {
                     if let Ok(mut src) = self.tcx.sess.source_map().span_to_snippet(attr.span) {
                         src.insert(1, '!');
@@ -1742,7 +1744,7 @@ impl CheckAttrVisitor<'_> {
                     }
                 }
                 Some(_) => {
-                    // This error case is handled in rustc_typeck::collect.
+                    // This error case is handled in rustc_hir_analysis::collect.
                 }
                 None => {
                     // Default case (compiler) when arg isn't defined.
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 57f7c379d04..3b1c1cd657f 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -102,14 +102,8 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
                 }
             }
             Res::Def(_, def_id) => self.check_def_id(def_id),
-            Res::SelfTy { trait_: t, alias_to: i } => {
-                if let Some(t) = t {
-                    self.check_def_id(t);
-                }
-                if let Some((i, _)) = i {
-                    self.check_def_id(i);
-                }
-            }
+            Res::SelfTyParam { trait_: t } => self.check_def_id(t),
+            Res::SelfTyAlias { alias_to: i, .. } => self.check_def_id(i),
             Res::ToolMod | Res::NonMacroAttr(..) | Res::Err => {}
         }
     }
@@ -317,7 +311,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);
+                let item = self.tcx.local_parent(impl_item.def_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
@@ -374,7 +368,7 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
             if has_repr_c || (f.is_positional() && has_repr_simd) {
                 return Some(def_id);
             }
-            if !tcx.visibility(f.hir_id.owner).is_public() {
+            if !tcx.visibility(f.hir_id.owner.def_id).is_public() {
                 return None;
             }
             if tcx.visibility(def_id).is_public() { Some(def_id) } else { None }
@@ -528,7 +522,7 @@ 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);
+        worklist.push(id.def_id.def_id);
     }
 
     match tcx.def_kind(id.def_id) {
@@ -554,7 +548,7 @@ fn check_item<'tcx>(
             let of_trait = tcx.impl_trait_ref(id.def_id);
 
             if of_trait.is_some() {
-                worklist.push(id.def_id);
+                worklist.push(id.def_id.def_id);
             }
 
             // get DefIds from another query
@@ -577,12 +571,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);
+                struct_constructors.insert(tcx.hir().local_def_id(ctor_hir_id), item.def_id.def_id);
             }
         }
         DefKind::GlobalAsm => {
             // global_asm! is always live.
-            worklist.push(id.def_id);
+            worklist.push(id.def_id.def_id);
         }
         _ => {}
     }
@@ -595,7 +589,7 @@ fn check_trait_item<'tcx>(tcx: TyCtxt<'tcx>, worklist: &mut Vec<LocalDefId>, 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);
+            worklist.push(trait_item.def_id.def_id);
         }
     }
 }
@@ -608,7 +602,7 @@ fn check_foreign_item<'tcx>(
     if matches!(tcx.def_kind(id.def_id), DefKind::Static(_) | DefKind::Fn)
         && has_allow_dead_code_or_lang_attr(tcx, id.hir_id())
     {
-        worklist.push(id.def_id);
+        worklist.push(id.def_id.def_id);
     }
 }
 
@@ -871,13 +865,13 @@ 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) {
-            let parent = tcx.local_parent(item.def_id);
+        if !live_symbols.contains(&item.def_id.def_id) {
+            let parent = tcx.local_parent(item.def_id.def_id);
             if parent != module && !live_symbols.contains(&parent) {
                 // We already have diagnosed something.
                 continue;
             }
-            visitor.check_definition(item.def_id);
+            visitor.check_definition(item.def_id.def_id);
             continue;
         }
 
@@ -926,16 +920,21 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) {
                 visitor.warn_dead_fields_and_variants(def_id, "read", dead_fields, is_positional)
             }
 
-            visitor.warn_dead_fields_and_variants(item.def_id, "constructed", dead_variants, false);
+            visitor.warn_dead_fields_and_variants(
+                item.def_id.def_id,
+                "constructed",
+                dead_variants,
+                false,
+            );
         }
     }
 
     for impl_item in module_items.impl_items() {
-        visitor.check_definition(impl_item.def_id);
+        visitor.check_definition(impl_item.def_id.def_id);
     }
 
     for foreign_item in module_items.foreign_items() {
-        visitor.check_definition(foreign_item.def_id);
+        visitor.check_definition(foreign_item.def_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 e6b69d8986c..e428d9293db 100644
--- a/compiler/rustc_passes/src/diagnostic_items.rs
+++ b/compiler/rustc_passes/src/diagnostic_items.rs
@@ -74,19 +74,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);
+        observe_item(tcx, &mut diagnostic_items, id.def_id.def_id);
     }
 
     for id in crate_items.trait_items() {
-        observe_item(tcx, &mut diagnostic_items, id.def_id);
+        observe_item(tcx, &mut diagnostic_items, id.def_id.def_id);
     }
 
     for id in crate_items.impl_items() {
-        observe_item(tcx, &mut diagnostic_items, id.def_id);
+        observe_item(tcx, &mut diagnostic_items, id.def_id.def_id);
     }
 
     for id in crate_items.foreign_items() {
-        observe_item(tcx, &mut diagnostic_items, id.def_id);
+        observe_item(tcx, &mut diagnostic_items, id.def_id.def_id);
     }
 
     diagnostic_items
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index cd10170d3ba..eec37d19a88 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -82,7 +82,7 @@ fn err_if_attr_found(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol, details:
 }
 
 fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
-    let at_root = ctxt.tcx.opt_local_parent(id.def_id) == Some(CRATE_DEF_ID);
+    let at_root = ctxt.tcx.opt_local_parent(id.def_id.def_id) == Some(CRATE_DEF_ID);
 
     match entry_point_type(ctxt, id, at_root) {
         EntryPointType::None => {
@@ -99,7 +99,7 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
         }
         EntryPointType::RustcMainAttr => {
             if ctxt.attr_main_fn.is_none() {
-                ctxt.attr_main_fn = Some((id.def_id, ctxt.tcx.def_span(id.def_id.to_def_id())));
+                ctxt.attr_main_fn = Some((id.def_id.def_id, ctxt.tcx.def_span(id.def_id)));
             } else {
                 struct_span_err!(
                     ctxt.tcx.sess,
@@ -118,11 +118,11 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
         EntryPointType::Start => {
             err_if_attr_found(ctxt, id, sym::unix_sigpipe, "can only be used on `fn main()`");
             if ctxt.start_fn.is_none() {
-                ctxt.start_fn = Some((id.def_id, ctxt.tcx.def_span(id.def_id.to_def_id())));
+                ctxt.start_fn = Some((id.def_id.def_id, ctxt.tcx.def_span(id.def_id)));
             } else {
                 struct_span_err!(
                     ctxt.tcx.sess,
-                    ctxt.tcx.def_span(id.def_id.to_def_id()),
+                    ctxt.tcx.def_span(id.def_id),
                     E0138,
                     "multiple `start` functions"
                 )
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index cdfa7cf7f93..cc231af71a2 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -462,7 +462,7 @@ pub struct LinkSection {
 pub struct NoMangleForeign {
     #[label]
     pub span: Span,
-    #[suggestion(applicability = "machine-applicable")]
+    #[suggestion(code = "", applicability = "machine-applicable")]
     pub attr_span: Span,
     pub foreign_item_kind: &'static str,
 }
@@ -596,7 +596,7 @@ pub enum UnusedNote {
 #[derive(LintDiagnostic)]
 #[diag(passes::unused)]
 pub struct Unused {
-    #[suggestion(applicability = "machine-applicable")]
+    #[suggestion(code = "", applicability = "machine-applicable")]
     pub attr_span: Span,
     #[subdiagnostic]
     pub note: UnusedNote,
diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs
index 3bb8c0bb48c..3ee8c8bcb1d 100644
--- a/compiler/rustc_passes/src/hir_id_validator.rs
+++ b/compiler/rustc_passes/src/hir_id_validator.rs
@@ -1,6 +1,5 @@
 use rustc_data_structures::sync::Lock;
 use rustc_hir as hir;
-use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
 use rustc_hir::intravisit;
 use rustc_hir::{HirId, ItemLocalId};
 use rustc_index::bit_set::GrowableBitSet;
@@ -42,7 +41,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
 
 struct HirIdValidator<'a, 'hir> {
     hir_map: Map<'hir>,
-    owner: Option<LocalDefId>,
+    owner: Option<hir::OwnerId>,
     hir_ids_seen: GrowableBitSet<ItemLocalId>,
     errors: &'a Lock<Vec<String>>,
 }
@@ -63,12 +62,12 @@ impl<'a, 'hir> HirIdValidator<'a, 'hir> {
         self.errors.lock().push(f());
     }
 
-    fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self, owner: LocalDefId, walk: F) {
+    fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self, owner: hir::OwnerId, walk: F) {
         assert!(self.owner.is_none());
         self.owner = Some(owner);
         walk(self);
 
-        if owner == CRATE_DEF_ID {
+        if owner == hir::CRATE_OWNER_ID {
             return;
         }
 
@@ -97,14 +96,14 @@ impl<'a, 'hir> HirIdValidator<'a, 'hir> {
                 missing_items.push(format!(
                     "[local_id: {}, owner: {}]",
                     local_id,
-                    self.hir_map.def_path(owner).to_string_no_crate_verbose()
+                    self.hir_map.def_path(owner.def_id).to_string_no_crate_verbose()
                 ));
             }
             self.error(|| {
                 format!(
                     "ItemLocalIds not assigned densely in {}. \
                 Max ItemLocalId = {}, missing IDs = {:#?}; seens IDs = {:#?}",
-                    self.hir_map.def_path(owner).to_string_no_crate_verbose(),
+                    self.hir_map.def_path(owner.def_id).to_string_no_crate_verbose(),
                     max,
                     missing_items,
                     self.hir_ids_seen
@@ -138,8 +137,8 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> {
                 format!(
                     "HirIdValidator: The recorded owner of {} is {} instead of {}",
                     self.hir_map.node_to_string(hir_id),
-                    self.hir_map.def_path(hir_id.owner).to_string_no_crate_verbose(),
-                    self.hir_map.def_path(owner).to_string_no_crate_verbose()
+                    self.hir_map.def_path(hir_id.owner.def_id).to_string_no_crate_verbose(),
+                    self.hir_map.def_path(owner.def_id).to_string_no_crate_verbose()
                 )
             });
         }
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index fd03f657111..46c4a702fde 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -16,7 +16,7 @@ pub fn test_layout(tcx: TyCtxt<'_>) {
                 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, attr);
+                    dump_layout_of(tcx, id.def_id.def_id, attr);
                 }
             }
         }
diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs
index 39ebb8db21c..6e621b7eb5e 100644
--- a/compiler/rustc_passes/src/lib.rs
+++ b/compiler/rustc_passes/src/lib.rs
@@ -8,7 +8,6 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(iter_intersperse)]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(map_try_insert)]
 #![feature(min_specialization)]
 #![feature(try_blocks)]
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index 75244124e20..16055641aca 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -153,7 +153,7 @@ impl<'tcx> ReachableContext<'tcx> {
                 hir::ImplItemKind::Fn(..) => {
                     let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
                     let impl_did = self.tcx.hir().get_parent_item(hir_id);
-                    method_might_be_inlined(self.tcx, impl_item, impl_did)
+                    method_might_be_inlined(self.tcx, impl_item, impl_did.def_id)
                 }
                 hir::ImplItemKind::TyAlias(_) => false,
             },
@@ -305,8 +305,8 @@ fn check_item<'tcx>(
     worklist: &mut Vec<LocalDefId>,
     access_levels: &privacy::AccessLevels,
 ) {
-    if has_custom_linkage(tcx, id.def_id) {
-        worklist.push(id.def_id);
+    if has_custom_linkage(tcx, id.def_id.def_id) {
+        worklist.push(id.def_id.def_id);
     }
 
     if !matches!(tcx.def_kind(id.def_id), DefKind::Impl) {
@@ -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) {
-            worklist.extend(items.iter().map(|ii_ref| ii_ref.id.def_id));
+        if !access_levels.is_reachable(item.def_id.def_id) {
+            worklist.extend(items.iter().map(|ii_ref| ii_ref.id.def_id.def_id));
 
             let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res else {
                 unreachable!();
@@ -403,8 +403,8 @@ fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashSet<LocalDefId> {
         }
 
         for id in crate_items.impl_items() {
-            if has_custom_linkage(tcx, id.def_id) {
-                reachable_context.worklist.push(id.def_id);
+            if has_custom_linkage(tcx, id.def_id.def_id) {
+                reachable_context.worklist.push(id.def_id.def_id);
             }
         }
     }
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 3f23b027aef..e50beb27d2a 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -385,7 +385,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
         }
 
         self.annotate(
-            i.def_id,
+            i.def_id.def_id,
             i.span,
             fn_sig,
             kind,
@@ -404,7 +404,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
         };
 
         self.annotate(
-            ti.def_id,
+            ti.def_id.def_id,
             ti.span,
             fn_sig,
             AnnotationKind::Required,
@@ -427,7 +427,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
         };
 
         self.annotate(
-            ii.def_id,
+            ii.def_id.def_id,
             ii.span,
             fn_sig,
             kind,
@@ -485,7 +485,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,
+            i.def_id.def_id,
             i.span,
             None,
             AnnotationKind::Required,
@@ -573,25 +573,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, i.span);
+            self.check_missing_stability(i.def_id.def_id, i.span);
         }
 
         // Ensure stable `const fn` have a const stability attribute.
-        self.check_missing_const_stability(i.def_id, i.span);
+        self.check_missing_const_stability(i.def_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, ti.span);
+        self.check_missing_stability(ti.def_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, ii.span);
-            self.check_missing_const_stability(ii.def_id, ii.span);
+            self.check_missing_stability(ii.def_id.def_id, ii.span);
+            self.check_missing_const_stability(ii.def_id.def_id, ii.span);
         }
         intravisit::walk_impl_item(self, ii);
     }
@@ -610,7 +610,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, i.span);
+        self.check_missing_stability(i.def_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,
@@ -716,7 +716,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
                     return;
                 }
 
-                let Some(cnum) = self.tcx.extern_mod_stmt_cnum(item.def_id) else {
+                let Some(cnum) = self.tcx.extern_mod_stmt_cnum(item.def_id.def_id) else {
                     return;
                 };
                 let def_id = cnum.as_def_id();
@@ -869,7 +869,7 @@ fn is_unstable_reexport<'tcx>(tcx: TyCtxt<'tcx>, id: hir::HirId) -> bool {
     }
 
     // If this is a path that isn't a use, we don't need to do anything special
-    if !matches!(tcx.hir().item(hir::ItemId { def_id }).kind, ItemKind::Use(..)) {
+    if !matches!(tcx.hir().expect_item(def_id).kind, ItemKind::Use(..)) {
         return false;
     }
 
diff --git a/compiler/rustc_privacy/Cargo.toml b/compiler/rustc_privacy/Cargo.toml
index 5785921fb1e..832fdc9f016 100644
--- a/compiler/rustc_privacy/Cargo.toml
+++ b/compiler/rustc_privacy/Cargo.toml
@@ -14,5 +14,5 @@ rustc_middle = { path = "../rustc_middle" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
-rustc_typeck = { path = "../rustc_typeck" }
+rustc_hir_analysis = { path = "../rustc_hir_analysis" }
 tracing = "0.1"
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 8f5ee51e6cf..841e3ebb2a1 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -1,7 +1,6 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(associated_type_defaults)]
 #![feature(control_flow_enum)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(rustc_private)]
 #![feature(try_blocks)]
 #![recursion_limit = "256"]
@@ -506,8 +505,8 @@ impl<'tcx> EmbargoVisitor<'tcx> {
         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);
-            self.update_macro_reachable_def(item_id.def_id, def_kind, vis, defining_mod);
+            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);
         }
         if let Some(exports) = self.tcx.module_reexports(module_def_id) {
             for export in exports {
@@ -627,11 +626,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, self.tcx, &self.access_levels);
-                self.update(item.def_id, impl_level)
+                let impl_level = Option::<AccessLevel>::of_impl(
+                    item.def_id.def_id,
+                    self.tcx,
+                    &self.access_levels,
+                );
+                self.update(item.def_id.def_id, impl_level)
             }
-            _ => self.get(item.def_id),
+            _ => self.get(item.def_id.def_id),
         };
 
         // Update levels of nested things.
@@ -652,13 +654,13 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
                     if impl_.of_trait.is_some()
                         || self.tcx.visibility(impl_item_ref.id.def_id).is_public()
                     {
-                        self.update(impl_item_ref.id.def_id, item_level);
+                        self.update(impl_item_ref.id.def_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, item_level);
+                    self.update(trait_item_ref.id.def_id.def_id, item_level);
                 }
             }
             hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
@@ -674,12 +676,12 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
                 }
             }
             hir::ItemKind::Macro(ref macro_def, _) => {
-                self.update_reachability_from_macro(item.def_id, macro_def);
+                self.update_reachability_from_macro(item.def_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, item_level);
+                        self.update(foreign_item.id.def_id.def_id, item_level);
                     }
                 }
             }
@@ -717,7 +719,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
                     // 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, exist_level).generics().predicates().ty();
+                    self.reach(item.def_id.def_id, exist_level).generics().predicates().ty();
                 }
             }
             // Visit everything.
@@ -726,16 +728,16 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             | hir::ItemKind::Fn(..)
             | hir::ItemKind::TyAlias(..) => {
                 if item_level.is_some() {
-                    self.reach(item.def_id, item_level).generics().predicates().ty();
+                    self.reach(item.def_id.def_id, item_level).generics().predicates().ty();
                 }
             }
             hir::ItemKind::Trait(.., trait_item_refs) => {
                 if item_level.is_some() {
-                    self.reach(item.def_id, item_level).generics().predicates();
+                    self.reach(item.def_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, item_level);
+                        let mut reach = self.reach(trait_item_ref.id.def_id.def_id, item_level);
                         reach.generics().predicates();
 
                         if trait_item_ref.kind == AssocItemKind::Type
@@ -750,18 +752,22 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             }
             hir::ItemKind::TraitAlias(..) => {
                 if item_level.is_some() {
-                    self.reach(item.def_id, item_level).generics().predicates();
+                    self.reach(item.def_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, item_level).generics().predicates().ty().trait_ref();
+                    self.reach(item.def_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);
+                        let impl_item_level = self.get(impl_item_ref.id.def_id.def_id);
                         if impl_item_level.is_some() {
-                            self.reach(impl_item_ref.id.def_id, impl_item_level)
+                            self.reach(impl_item_ref.id.def_id.def_id, impl_item_level)
                                 .generics()
                                 .predicates()
                                 .ty();
@@ -773,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, item_level).generics().predicates();
+                    self.reach(item.def_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));
@@ -784,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, variant_level).ty();
+                        self.reach(item.def_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, ctor_level).ty();
+                            self.reach(item.def_id.def_id, ctor_level).ty();
                         }
                     }
                 }
@@ -798,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);
+                    let foreign_item_level = self.get(foreign_item.id.def_id.def_id);
                     if foreign_item_level.is_some() {
-                        self.reach(foreign_item.id.def_id, foreign_item_level)
+                        self.reach(foreign_item.id.def_id.def_id, foreign_item_level)
                             .generics()
                             .predicates()
                             .ty();
@@ -810,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, item_level).generics().predicates();
+                    self.reach(item.def_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);
@@ -823,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, ctor_level).ty();
+                        self.reach(item.def_id.def_id, ctor_level).ty();
                     }
                 }
             }
@@ -945,7 +951,7 @@ 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);
+        self.access_level_diagnostic(item.def_id.def_id);
 
         match item.kind {
             hir::ItemKind::Enum(ref def, _) => {
@@ -969,13 +975,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);
+        self.access_level_diagnostic(item.def_id.def_id);
     }
     fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem<'tcx>) {
-        self.access_level_diagnostic(item.def_id);
+        self.access_level_diagnostic(item.def_id.def_id);
     }
     fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
-        self.access_level_diagnostic(item.def_id);
+        self.access_level_diagnostic(item.def_id.def_id);
     }
 }
 
@@ -1058,7 +1064,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);
+        let orig_current_item = mem::replace(&mut self.current_item, item.def_id.def_id);
         intravisit::walk_item(self, item);
         self.current_item = orig_current_item;
     }
@@ -1201,7 +1207,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
             // Types in signatures.
             // FIXME: This is very ineffective. Ideally each HIR type should be converted
             // into a semantic type only once and the result should be cached somehow.
-            if self.visit(rustc_typeck::hir_ty_to_ty(self.tcx, hir_ty)).is_break() {
+            if self.visit(rustc_hir_analysis::hir_ty_to_ty(self.tcx, hir_ty)).is_break() {
                 return;
             }
         }
@@ -1230,7 +1236,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
         if self.maybe_typeck_results.is_none() {
             // Avoid calling `hir_trait_to_predicates` in bodies, it will ICE.
             // The traits' privacy in bodies is already checked as a part of trait object types.
-            let bounds = rustc_typeck::hir_trait_to_predicates(
+            let bounds = rustc_hir_analysis::hir_trait_to_predicates(
                 self.tcx,
                 trait_ref,
                 // NOTE: This isn't really right, but the actual type doesn't matter here. It's
@@ -1361,7 +1367,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);
+        let orig_current_item = mem::replace(&mut self.current_item, item.def_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;
@@ -1416,7 +1422,9 @@ struct ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b, 'tcx> {
 impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
     fn path_is_private_type(&self, path: &hir::Path<'_>) -> bool {
         let did = match path.res {
-            Res::PrimTy(..) | Res::SelfTy { .. } | Res::Err => return false,
+            Res::PrimTy(..) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Err => {
+                return false;
+            }
             res => res.def_id(),
         };
 
@@ -1503,7 +1511,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) {
+                if !self.trait_is_public(item.def_id.def_id) {
                     return;
                 }
 
@@ -1564,7 +1572,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(..) => {
-                                self.access_levels.is_reachable(impl_item_ref.id.def_id)
+                                self.access_levels.is_reachable(impl_item_ref.id.def_id.def_id)
                             }
                             hir::ImplItemKind::TyAlias(_) => false,
                         }
@@ -1584,7 +1592,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) =>
+                                        if self.item_is_public(impl_item.def_id.def_id) =>
                                     {
                                         intravisit::walk_impl_item(self, impl_item)
                                     }
@@ -1625,7 +1633,7 @@ 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)
+                        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()
                         {
                             let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
@@ -1654,7 +1662,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) => {
+            _ if !self.item_is_public(item.def_id.def_id) => {
                 return;
             }
 
@@ -1685,7 +1693,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) {
+        if self.access_levels.is_reachable(item.def_id.def_id) {
             intravisit::walk_foreign_item(self, item)
         }
     }
@@ -1922,43 +1930,44 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
 
     pub fn check_item(&mut self, id: ItemId) {
         let tcx = self.tcx;
-        let item_visibility = tcx.local_visibility(id.def_id);
-        let def_kind = tcx.def_kind(id.def_id);
+        let def_id = id.def_id.def_id;
+        let item_visibility = tcx.local_visibility(def_id);
+        let def_kind = tcx.def_kind(def_id);
 
         match def_kind {
             DefKind::Const | DefKind::Static(_) | DefKind::Fn | DefKind::TyAlias => {
-                self.check(id.def_id, item_visibility).generics().predicates().ty();
+                self.check(def_id, item_visibility).generics().predicates().ty();
             }
             DefKind::OpaqueTy => {
                 // `ty()` for opaque types is the underlying type,
                 // it's not a part of interface, so we skip it.
-                self.check(id.def_id, item_visibility).generics().bounds();
+                self.check(def_id, item_visibility).generics().bounds();
             }
             DefKind::Trait => {
                 let item = tcx.hir().item(id);
                 if let hir::ItemKind::Trait(.., trait_item_refs) = item.kind {
-                    self.check(item.def_id, item_visibility).generics().predicates();
+                    self.check(item.def_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,
+                            trait_item_ref.id.def_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, item_visibility).bounds();
+                            self.check(trait_item_ref.id.def_id.def_id, item_visibility).bounds();
                         }
                     }
                 }
             }
             DefKind::TraitAlias => {
-                self.check(id.def_id, item_visibility).generics().predicates();
+                self.check(def_id, item_visibility).generics().predicates();
             }
             DefKind::Enum => {
                 let item = tcx.hir().item(id);
                 if let hir::ItemKind::Enum(ref def, _) = item.kind {
-                    self.check(item.def_id, item_visibility).generics().predicates();
+                    self.check(item.def_id.def_id, item_visibility).generics().predicates();
 
                     for variant in def.variants {
                         for field in variant.data.fields() {
@@ -1973,8 +1982,8 @@ 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);
-                        self.check(foreign_item.id.def_id, vis).generics().predicates().ty();
+                        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();
                     }
                 }
             }
@@ -1984,7 +1993,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, item_visibility).generics().predicates();
+                    self.check(item.def_id.def_id, item_visibility).generics().predicates();
 
                     for field in struct_def.fields() {
                         let def_id = tcx.hir().local_def_id(field.hir_id);
@@ -2000,20 +2009,21 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
             DefKind::Impl => {
                 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, tcx, &Default::default());
+                    let impl_vis =
+                        ty::Visibility::of_impl(item.def_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, impl_vis).generics().predicates();
+                        self.check(item.def_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), impl_vis, tcx)
+                            min(tcx.local_visibility(impl_item_ref.id.def_id.def_id), impl_vis, tcx)
                         } else {
                             impl_vis
                         };
                         self.check_assoc_item(
-                            impl_item_ref.id.def_id,
+                            impl_item_ref.id.def_id.def_id,
                             impl_item_ref.kind,
                             impl_item_vis,
                         );
@@ -2061,7 +2071,7 @@ fn local_visibility(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Visibility {
                 // Visibilities of trait impl items are inherited from their traits
                 // and are not filled in resolve.
                 Node::ImplItem(impl_item) => {
-                    match tcx.hir().get_by_def_id(tcx.hir().get_parent_item(hir_id)) {
+                    match tcx.hir().get_by_def_id(tcx.hir().get_parent_item(hir_id).def_id) {
                         Node::Item(hir::Item {
                             kind: hir::ItemKind::Impl(hir::Impl { of_trait: Some(tr), .. }),
                             ..
diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs
index 2bb7a240faa..47762440e29 100644
--- a/compiler/rustc_query_impl/src/keys.rs
+++ b/compiler/rustc_query_impl/src/keys.rs
@@ -1,6 +1,7 @@
 //! Defines the set of legal keys that can be used in queries.
 
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
+use rustc_hir::hir_id::OwnerId;
 use rustc_middle::infer::canonical::Canonical;
 use rustc_middle::mir;
 use rustc_middle::traits;
@@ -104,6 +105,19 @@ impl Key for CrateNum {
     }
 }
 
+impl Key for OwnerId {
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
+    }
+    fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
+        self.to_def_id().default_span(tcx)
+    }
+    fn key_as_def_id(&self) -> Option<DefId> {
+        Some(self.to_def_id())
+    }
+}
+
 impl Key for LocalDefId {
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index c87d26b3950..8e018d3e4a4 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -1,6 +1,8 @@
 //! Support for serializing the dep-graph and reloading it.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+// this shouldn't be necessary, but the check for `&mut _` is too naive and denies returning a function pointer that takes a mut ref
+#![feature(const_mut_refs)]
 #![feature(min_specialization)]
 #![feature(never_type)]
 #![feature(once_cell)]
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index d819f4774d5..2b3850bc0df 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -3,7 +3,8 @@
 //! manage the caches, and so forth.
 
 use crate::keys::Key;
-use crate::on_disk_cache::CacheDecoder;
+use crate::on_disk_cache::{CacheDecoder, CacheEncoder, EncodedDepNodeIndex};
+use crate::profiling_support::QueryKeyStringCache;
 use crate::{on_disk_cache, Queries};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::{AtomicU64, Lock};
@@ -173,34 +174,14 @@ impl<'tcx> QueryCtxt<'tcx> {
 
     pub(super) fn encode_query_results(
         self,
-        encoder: &mut on_disk_cache::CacheEncoder<'_, 'tcx>,
-        query_result_index: &mut on_disk_cache::EncodedDepNodeIndex,
+        encoder: &mut CacheEncoder<'_, 'tcx>,
+        query_result_index: &mut EncodedDepNodeIndex,
     ) {
-        macro_rules! expand_if_cached {
-            ([] $encode:expr) => {};
-            ([(cache) $($rest:tt)*] $encode:expr) => {
-                $encode
-            };
-            ([$other:tt $($modifiers:tt)*] $encode:expr) => {
-                expand_if_cached!([$($modifiers)*] $encode)
-            };
-        }
-
-        macro_rules! encode_queries {
-            (
-            $($(#[$attr:meta])*
-                [$($modifiers:tt)*] fn $query:ident($($K:tt)*) -> $V:ty,)*) => {
-                $(
-                    expand_if_cached!([$($modifiers)*] on_disk_cache::encode_query_results::<_, super::queries::$query<'_>>(
-                        self,
-                        encoder,
-                        query_result_index
-                    ));
-                )*
+        for query in &self.queries.query_structs {
+            if let Some(encode) = query.encode_query_results {
+                encode(self, encoder, query_result_index);
             }
         }
-
-        rustc_query_append!(encode_queries!);
     }
 
     pub fn try_print_query_stack(
@@ -213,6 +194,14 @@ impl<'tcx> QueryCtxt<'tcx> {
     }
 }
 
+#[derive(Clone, Copy)]
+pub(crate) struct QueryStruct<'tcx> {
+    pub try_collect_active_jobs: fn(QueryCtxt<'tcx>, &mut QueryMap) -> Option<()>,
+    pub alloc_self_profile_query_strings: fn(TyCtxt<'tcx>, &mut QueryKeyStringCache),
+    pub encode_query_results:
+        Option<fn(QueryCtxt<'tcx>, &mut CacheEncoder<'_, 'tcx>, &mut EncodedDepNodeIndex)>,
+}
+
 macro_rules! handle_cycle_error {
     ([]) => {{
         rustc_query_system::HandleCycleError::Error
@@ -380,6 +369,24 @@ where
     Q::Key: DepNodeParams<TyCtxt<'tcx>>,
     Q::Value: Value<TyCtxt<'tcx>>,
 {
+    // We must avoid ever having to call `force_from_dep_node()` for a
+    // `DepNode::codegen_unit`:
+    // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we
+    // would always end up having to evaluate the first caller of the
+    // `codegen_unit` query that *is* reconstructible. This might very well be
+    // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just
+    // to re-trigger calling the `codegen_unit` query with the right key. At
+    // that point we would already have re-done all the work we are trying to
+    // avoid doing in the first place.
+    // The solution is simple: Just explicitly call the `codegen_unit` query for
+    // each CGU, right after partitioning. This way `try_mark_green` will always
+    // hit the cache instead of having to go through `force_from_dep_node`.
+    // This assertion makes sure, we actually keep applying the solution above.
+    debug_assert!(
+        dep_node.kind != DepKind::codegen_unit,
+        "calling force_from_dep_node() on DepKind::codegen_unit"
+    );
+
     if let Some(key) = Q::Key::recover(tcx, &dep_node) {
         #[cfg(debug_assertions)]
         let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered();
@@ -420,6 +427,18 @@ where
     }
 }
 
+macro_rules! expand_if_cached {
+    ([], $tokens:expr) => {{
+        None
+    }};
+    ([(cache) $($rest:tt)*], $tokens:expr) => {{
+        Some($tokens)
+    }};
+    ([$other:tt $($modifiers:tt)*], $tokens:expr) => {
+        expand_if_cached!([$($modifiers)*], $tokens)
+    };
+}
+
 // NOTE: `$V` isn't used here, but we still need to match on it so it can be passed to other macros
 // invoked by `rustc_query_append`.
 macro_rules! define_queries {
@@ -553,6 +572,59 @@ macro_rules! define_queries {
             })*
         }
 
+        mod query_structs {
+            use rustc_middle::ty::TyCtxt;
+            use $crate::plumbing::{QueryStruct, QueryCtxt};
+            use $crate::profiling_support::QueryKeyStringCache;
+            use rustc_query_system::query::{QueryDescription, QueryMap};
+
+            pub(super) const fn dummy_query_struct<'tcx>() -> QueryStruct<'tcx> {
+                fn noop_try_collect_active_jobs(_: QueryCtxt<'_>, _: &mut QueryMap) -> Option<()> {
+                    None
+                }
+                fn noop_alloc_self_profile_query_strings(_: TyCtxt<'_>, _: &mut QueryKeyStringCache) {}
+
+                QueryStruct {
+                    try_collect_active_jobs: noop_try_collect_active_jobs,
+                    alloc_self_profile_query_strings: noop_alloc_self_profile_query_strings,
+                    encode_query_results: None,
+                }
+            }
+
+            pub(super) use dummy_query_struct as Null;
+            pub(super) use dummy_query_struct as Red;
+            pub(super) use dummy_query_struct as TraitSelect;
+            pub(super) use dummy_query_struct as CompileCodegenUnit;
+            pub(super) use dummy_query_struct as CompileMonoItem;
+
+            $(
+            pub(super) const fn $name<'tcx>() -> QueryStruct<'tcx> { QueryStruct {
+                try_collect_active_jobs: |tcx, qmap| {
+                    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)
+                    };
+                    tcx.queries.$name.try_collect_active_jobs(
+                        tcx,
+                        make_query,
+                        qmap,
+                    )
+                },
+                alloc_self_profile_query_strings: |tcx, string_cache| {
+                    $crate::profiling_support::alloc_self_profile_query_strings_for_query_cache(
+                        tcx,
+                        stringify!($name),
+                        &tcx.query_caches.$name,
+                        string_cache,
+                    )
+                },
+                encode_query_results: expand_if_cached!([$($modifiers)*], |tcx, encoder, query_result_index|
+                    $crate::on_disk_cache::encode_query_results::<_, super::queries::$name<'_>>(tcx, encoder, query_result_index)
+                ),
+            }})*
+        }
+
         pub fn query_callbacks<'tcx>(arena: &'tcx Arena<'tcx>) -> &'tcx [DepKindStruct<'tcx>] {
             arena.alloc_from_iter(make_dep_kind_array!(query_callbacks))
         }
@@ -567,9 +639,11 @@ impl<'tcx> Queries<'tcx> {
         extern_providers: ExternProviders,
         on_disk_cache: Option<OnDiskCache<'tcx>>,
     ) -> Self {
+        use crate::query_structs;
         Queries {
             local_providers: Box::new(local_providers),
             extern_providers: Box::new(extern_providers),
+            query_structs: make_dep_kind_array!(query_structs).to_vec(),
             on_disk_cache,
             jobs: AtomicU64::new(1),
             ..Queries::default()
@@ -584,6 +658,7 @@ macro_rules! define_queries_struct {
         pub struct Queries<'tcx> {
             local_providers: Box<Providers>,
             extern_providers: Box<ExternProviders>,
+            query_structs: Vec<$crate::plumbing::QueryStruct<'tcx>>,
 
             pub on_disk_cache: Option<OnDiskCache<'tcx>>,
 
@@ -600,18 +675,9 @@ macro_rules! define_queries_struct {
                 let tcx = QueryCtxt { tcx, queries: self };
                 let mut jobs = QueryMap::default();
 
-                $(
-                    let make_query = |tcx, key| {
-                        let kind = dep_graph::DepKind::$name;
-                        let name = stringify!($name);
-                        $crate::plumbing::create_query_frame(tcx, queries::$name::describe, key, kind, name)
-                    };
-                    self.$name.try_collect_active_jobs(
-                        tcx,
-                        make_query,
-                        &mut jobs,
-                    )?;
-                )*
+                for query in &self.query_structs {
+                    (query.try_collect_active_jobs)(tcx, &mut jobs);
+                }
 
                 Some(jobs)
             }
diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs
index 98ec3bc0977..2cc311d48c8 100644
--- a/compiler/rustc_query_impl/src/profiling_support.rs
+++ b/compiler/rustc_query_impl/src/profiling_support.rs
@@ -1,3 +1,4 @@
+use crate::QueryCtxt;
 use measureme::{StringComponent, StringId};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::profiling::SelfProfiler;
@@ -8,7 +9,7 @@ use rustc_query_system::query::QueryCache;
 use std::fmt::Debug;
 use std::io::Write;
 
-struct QueryKeyStringCache {
+pub(crate) struct QueryKeyStringCache {
     def_id_cache: FxHashMap<DefId, StringId>,
 }
 
@@ -226,7 +227,7 @@ where
 /// Allocate the self-profiling query strings for a single query cache. This
 /// method is called from `alloc_self_profile_query_strings` which knows all
 /// the queries via macro magic.
-fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
+pub(crate) fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
     tcx: TyCtxt<'tcx>,
     query_name: &'static str,
     query_cache: &C,
@@ -298,27 +299,15 @@ fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
 /// If we are recording only summary data, the ids will point to
 /// just the query names. If we are recording query keys too, we
 /// allocate the corresponding strings here.
-pub fn alloc_self_profile_query_strings(tcx: TyCtxt<'_>) {
+pub fn alloc_self_profile_query_strings<'tcx>(tcx: TyCtxt<'tcx>) {
     if !tcx.prof.enabled() {
         return;
     }
 
     let mut string_cache = QueryKeyStringCache::new();
+    let queries = QueryCtxt::from_tcx(tcx);
 
-    macro_rules! alloc_once {
-        (
-        $($(#[$attr:meta])*
-            [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => {
-            $(
-                alloc_self_profile_query_strings_for_query_cache(
-                    tcx,
-                    stringify!($name),
-                    &tcx.query_caches.$name,
-                    &mut string_cache,
-                );
-            )+
-        }
+    for query in &queries.queries.query_structs {
+        (query.alloc_self_profile_query_strings)(tcx, &mut string_cache);
     }
-
-    rustc_query_append! { alloc_once! }
 }
diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
index 162c274d8a2..5c6ce0556eb 100644
--- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
@@ -47,6 +47,7 @@ use crate::ich::StableHashingContext;
 
 use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_hir::definitions::DefPathHash;
 use std::fmt;
 use std::hash::Hash;
 
@@ -88,6 +89,17 @@ impl<K: DepKind> DepNode<K> {
 
         dep_node
     }
+
+    /// Construct a DepNode from the given DepKind and DefPathHash. This
+    /// method will assert that the given DepKind actually requires a
+    /// single DefId/DefPathHash parameter.
+    pub fn from_def_path_hash<Ctxt>(tcx: Ctxt, def_path_hash: DefPathHash, kind: K) -> Self
+    where
+        Ctxt: super::DepContext<DepKind = K>,
+    {
+        debug_assert!(tcx.fingerprint_style(kind) == FingerprintStyle::DefPathHash);
+        DepNode { kind, hash: def_path_hash.0.into() }
+    }
 }
 
 impl<K: DepKind> fmt::Debug for DepNode<K> {
@@ -149,6 +161,67 @@ where
     }
 }
 
+/// This struct stores metadata about each DepKind.
+///
+/// Information is retrieved by indexing the `DEP_KINDS` array using the integer value
+/// of the `DepKind`. Overall, this allows to implement `DepContext` using this manual
+/// jump table instead of large matches.
+pub struct DepKindStruct<CTX: DepContext> {
+    /// Anonymous queries cannot be replayed from one compiler invocation to the next.
+    /// When their result is needed, it is recomputed. They are useful for fine-grained
+    /// dependency tracking, and caching within one compiler invocation.
+    pub is_anon: bool,
+
+    /// Eval-always queries do not track their dependencies, and are always recomputed, even if
+    /// their inputs have not changed since the last compiler invocation. The result is still
+    /// cached within one compiler invocation.
+    pub is_eval_always: bool,
+
+    /// Whether the query key can be recovered from the hashed fingerprint.
+    /// See [DepNodeParams] trait for the behaviour of each key type.
+    pub fingerprint_style: FingerprintStyle,
+
+    /// The red/green evaluation system will try to mark a specific DepNode in the
+    /// dependency graph as green by recursively trying to mark the dependencies of
+    /// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode`
+    /// where we don't know if it is red or green and we therefore actually have
+    /// to recompute its value in order to find out. Since the only piece of
+    /// information that we have at that point is the `DepNode` we are trying to
+    /// re-evaluate, we need some way to re-run a query from just that. This is what
+    /// `force_from_dep_node()` implements.
+    ///
+    /// In the general case, a `DepNode` consists of a `DepKind` and an opaque
+    /// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint
+    /// is usually constructed by computing a stable hash of the query-key that the
+    /// `DepNode` corresponds to. Consequently, it is not in general possible to go
+    /// back from hash to query-key (since hash functions are not reversible). For
+    /// this reason `force_from_dep_node()` is expected to fail from time to time
+    /// because we just cannot find out, from the `DepNode` alone, what the
+    /// corresponding query-key is and therefore cannot re-run the query.
+    ///
+    /// The system deals with this case letting `try_mark_green` fail which forces
+    /// the root query to be re-evaluated.
+    ///
+    /// Now, if `force_from_dep_node()` would always fail, it would be pretty useless.
+    /// Fortunately, we can use some contextual information that will allow us to
+    /// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we
+    /// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a
+    /// valid `DefPathHash`. Since we also always build a huge table that maps every
+    /// `DefPathHash` in the current codebase to the corresponding `DefId`, we have
+    /// everything we need to re-run the query.
+    ///
+    /// Take the `mir_promoted` query as an example. Like many other queries, it
+    /// just has a single parameter: the `DefId` of the item it will compute the
+    /// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode`
+    /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode`
+    /// is actually a `DefPathHash`, and can therefore just look up the corresponding
+    /// `DefId` in `tcx.def_path_hash_to_def_id`.
+    pub force_from_dep_node: Option<fn(tcx: CTX, dep_node: DepNode<CTX::DepKind>) -> bool>,
+
+    /// Invoke a query to put the on-disk cached value in memory.
+    pub try_load_from_on_disk_cache: Option<fn(CTX, DepNode<CTX::DepKind>)>,
+}
+
 /// A "work product" corresponds to a `.o` (or other) file that we
 /// save in between runs. These IDs do not have a `DefId` but rather
 /// some independent path or string that persists between runs without
diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs
index 342d95ca490..5003a14b910 100644
--- a/compiler/rustc_query_system/src/dep_graph/mod.rs
+++ b/compiler/rustc_query_system/src/dep_graph/mod.rs
@@ -4,7 +4,7 @@ mod graph;
 mod query;
 mod serialized;
 
-pub use dep_node::{DepNode, DepNodeParams, WorkProductId};
+pub use dep_node::{DepKindStruct, DepNode, DepNodeParams, WorkProductId};
 pub use graph::{
     hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, TaskDepsRef, WorkProduct,
 };
@@ -34,16 +34,43 @@ pub trait DepContext: Copy {
     /// Access the compiler session.
     fn sess(&self) -> &Session;
 
-    /// Return whether this kind always require evaluation.
-    fn is_eval_always(&self, kind: Self::DepKind) -> bool;
+    fn dep_kind_info(&self, dep_node: Self::DepKind) -> &DepKindStruct<Self>;
 
-    fn fingerprint_style(&self, kind: Self::DepKind) -> FingerprintStyle;
+    #[inline(always)]
+    fn fingerprint_style(&self, kind: Self::DepKind) -> FingerprintStyle {
+        let data = self.dep_kind_info(kind);
+        if data.is_anon {
+            return FingerprintStyle::Opaque;
+        }
+        data.fingerprint_style
+    }
+
+    #[inline(always)]
+    /// Return whether this kind always require evaluation.
+    fn is_eval_always(&self, kind: Self::DepKind) -> bool {
+        self.dep_kind_info(kind).is_eval_always
+    }
 
     /// Try to force a dep node to execute and see if it's green.
-    fn try_force_from_dep_node(&self, dep_node: DepNode<Self::DepKind>) -> bool;
+    fn try_force_from_dep_node(self, dep_node: DepNode<Self::DepKind>) -> bool {
+        debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node);
+
+        let cb = self.dep_kind_info(dep_node.kind);
+        if let Some(f) = cb.force_from_dep_node {
+            f(self, dep_node);
+            true
+        } else {
+            false
+        }
+    }
 
     /// Load data from the on-disk cache.
-    fn try_load_from_on_disk_cache(&self, dep_node: DepNode<Self::DepKind>);
+    fn try_load_from_on_disk_cache(self, dep_node: DepNode<Self::DepKind>) {
+        let cb = self.dep_kind_info(dep_node.kind);
+        if let Some(f) = cb.try_load_from_on_disk_cache {
+            f(self, dep_node)
+        }
+    }
 }
 
 pub trait HasDepContext: Copy {
diff --git a/compiler/rustc_query_system/src/ich/hcx.rs b/compiler/rustc_query_system/src/ich/hcx.rs
index a09b8ca30e1..8140c243453 100644
--- a/compiler/rustc_query_system/src/ich/hcx.rs
+++ b/compiler/rustc_query_system/src/ich/hcx.rs
@@ -41,7 +41,10 @@ pub struct StableHashingContext<'a> {
 pub(super) enum BodyResolver<'tcx> {
     Forbidden,
     Ignore,
-    Traverse { owner: LocalDefId, bodies: &'tcx SortedMap<hir::ItemLocalId, &'tcx hir::Body<'tcx>> },
+    Traverse {
+        owner: hir::OwnerId,
+        bodies: &'tcx SortedMap<hir::ItemLocalId, &'tcx hir::Body<'tcx>>,
+    },
 }
 
 impl<'a> StableHashingContext<'a> {
@@ -103,7 +106,7 @@ impl<'a> StableHashingContext<'a> {
     #[inline]
     pub fn with_hir_bodies(
         &mut self,
-        owner: LocalDefId,
+        owner: hir::OwnerId,
         bodies: &SortedMap<hir::ItemLocalId, &hir::Body<'_>>,
         f: impl FnOnce(&mut StableHashingContext<'_>),
     ) {
diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs
index 5987651322a..8f6da73d1f2 100644
--- a/compiler/rustc_query_system/src/lib.rs
+++ b/compiler/rustc_query_system/src/lib.rs
@@ -1,7 +1,6 @@
 #![feature(assert_matches)]
 #![feature(core_intrinsics)]
 #![feature(hash_raw_entry)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(min_specialization)]
 #![feature(extern_types)]
 #![allow(rustc::potential_query_instability)]
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 81b67b758f7..29aab416ae9 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -1010,7 +1010,8 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                 _,
             )
             | Res::Local(..)
-            | Res::SelfTy { .. }
+            | Res::SelfTyParam { .. }
+            | Res::SelfTyAlias { .. }
             | Res::SelfCtor(..)
             | Res::Err => bug!("unexpected resolution: {:?}", res),
         }
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index 8b58b32b656..01c3801f223 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -6,7 +6,7 @@
 // `use` items.
 //
 // Unused trait imports can't be checked until the method resolution. We save
-// candidates here, and do the actual check in librustc_typeck/check_unused.rs.
+// candidates here, and do the actual check in rustc_hir_analysis/check_unused.rs.
 //
 // Checking for unused imports is split into three steps:
 //
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 3f88f44ff21..7e83f2a7221 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -1,6 +1,5 @@
 use crate::{ImplTraitContext, Resolver};
 use rustc_ast::visit::{self, FnKind};
-use rustc_ast::walk_list;
 use rustc_ast::*;
 use rustc_expand::expand::AstFragment;
 use rustc_hir::def_id::LocalDefId;
@@ -148,8 +147,13 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> {
                 self.with_parent(return_impl_trait_id, |this| {
                     this.visit_fn_ret_ty(&sig.decl.output)
                 });
-                let closure_def = self.create_def(closure_id, DefPathData::ClosureExpr, span);
-                self.with_parent(closure_def, |this| walk_list!(this, visit_block, body));
+                // If this async fn has no body (i.e. it's an async fn signature in a trait)
+                // then the closure_def will never be used, and we should avoid generating a
+                // def-id for it.
+                if let Some(body) = body {
+                    let closure_def = self.create_def(closure_id, DefPathData::ClosureExpr, span);
+                    self.with_parent(closure_def, |this| this.visit_block(body));
+                }
                 return;
             }
         }
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index ab71fa0bc1d..b6778804a99 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -511,24 +511,18 @@ impl<'a> Resolver<'a> {
 
                 let sm = self.session.source_map();
                 let def_id = match outer_res {
-                    Res::SelfTy { trait_: maybe_trait_defid, alias_to: maybe_impl_defid } => {
-                        if let Some(impl_span) =
-                            maybe_impl_defid.and_then(|(def_id, _)| self.opt_span(def_id))
-                        {
+                    Res::SelfTyParam { .. } => {
+                        err.span_label(span, "can't use `Self` here");
+                        return err;
+                    }
+                    Res::SelfTyAlias { alias_to: def_id, .. } => {
+                        if let Some(impl_span) = self.opt_span(def_id) {
                             err.span_label(
                                 reduce_impl_span_to_impl_keyword(sm, impl_span),
                                 "`Self` type implicitly declared here, by this `impl`",
                             );
                         }
-                        match (maybe_trait_defid, maybe_impl_defid) {
-                            (Some(_), None) => {
-                                err.span_label(span, "can't use `Self` here");
-                            }
-                            (_, Some(_)) => {
-                                err.span_label(span, "use a type here instead");
-                            }
-                            (None, None) => bug!("`impl` without trait nor type?"),
-                        }
+                        err.span_label(span, "use a type here instead");
                         return err;
                     }
                     Res::Def(DefKind::TyParam, def_id) => {
@@ -545,8 +539,9 @@ impl<'a> Resolver<'a> {
                     }
                     _ => {
                         bug!(
-                            "GenericParamsFromOuterFunction should only be used with Res::SelfTy, \
-                            DefKind::TyParam or DefKind::ConstParam"
+                            "GenericParamsFromOuterFunction should only be used with \
+                            Res::SelfTyParam, Res::SelfTyAlias, DefKind::TyParam or \
+                            DefKind::ConstParam"
                         );
                     }
                 };
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 2287aa1eb25..e0542d5479f 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -1162,7 +1162,7 @@ impl<'a> Resolver<'a> {
                     return Res::Err;
                 }
             }
-            Res::Def(DefKind::TyParam, _) | Res::SelfTy { .. } => {
+            Res::Def(DefKind::TyParam, _) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => {
                 for rib in ribs {
                     let has_generic_params: HasGenericParams = match rib.kind {
                         NormalRibKind
@@ -1182,11 +1182,21 @@ impl<'a> Resolver<'a> {
                             if !(trivial == ConstantHasGenerics::Yes
                                 || features.generic_const_exprs)
                             {
-                                // HACK(min_const_generics): If we encounter `Self` in an anonymous constant
-                                // we can't easily tell if it's generic at this stage, so we instead remember
-                                // this and then enforce the self type to be concrete later on.
-                                if let Res::SelfTy { trait_, alias_to: Some((def, _)) } = res {
-                                    res = Res::SelfTy { trait_, alias_to: Some((def, true)) }
+                                // HACK(min_const_generics): If we encounter `Self` in an anonymous
+                                // constant we can't easily tell if it's generic at this stage, so
+                                // we instead remember this and then enforce the self type to be
+                                // concrete later on.
+                                if let Res::SelfTyAlias {
+                                    alias_to: def,
+                                    forbid_generic: _,
+                                    is_trait_impl,
+                                } = res
+                                {
+                                    res = Res::SelfTyAlias {
+                                        alias_to: def,
+                                        forbid_generic: true,
+                                        is_trait_impl,
+                                    }
                                 } else {
                                     if let Some(span) = finalize {
                                         self.report_error(
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 0aea90bb5aa..72029488cb1 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -19,7 +19,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_errors::DiagnosticId;
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, PartialRes, PerNS};
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::{BindingAnnotation, PrimTy, TraitCandidate};
 use rustc_middle::middle::resolve_lifetime::Set1;
 use rustc_middle::ty::DefIdTree;
@@ -414,7 +414,8 @@ impl<'a> PathSource<'a> {
                         | DefKind::ForeignTy,
                     _,
                 ) | Res::PrimTy(..)
-                    | Res::SelfTy { .. }
+                    | Res::SelfTyParam { .. }
+                    | Res::SelfTyAlias { .. }
             ),
             PathSource::Trait(AliasPossibility::No) => matches!(res, Res::Def(DefKind::Trait, _)),
             PathSource::Trait(AliasPossibility::Maybe) => {
@@ -448,7 +449,8 @@ impl<'a> PathSource<'a> {
                         | DefKind::TyAlias
                         | DefKind::AssocTy,
                     _,
-                ) | Res::SelfTy { .. }
+                ) | Res::SelfTyParam { .. }
+                    | Res::SelfTyAlias { .. }
             ),
             PathSource::TraitItem(ns) => match res {
                 Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) if ns == ValueNS => true,
@@ -805,7 +807,12 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                             sig.decl.has_self(),
                             sig.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)),
                             &sig.decl.output,
-                        )
+                        );
+
+                        this.record_lifetime_params_for_async(
+                            fn_id,
+                            sig.header.asyncness.opt_return_id(),
+                        );
                     },
                 );
                 return;
@@ -847,41 +854,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                             },
                         );
 
-                        // Construct the list of in-scope lifetime parameters for async lowering.
-                        // We include all lifetime parameters, either named or "Fresh".
-                        // The order of those parameters does not matter, as long as it is
-                        // deterministic.
-                        if let Some((async_node_id, _)) = async_node_id {
-                            let mut extra_lifetime_params = this
-                                .r
-                                .extra_lifetime_params_map
-                                .get(&fn_id)
-                                .cloned()
-                                .unwrap_or_default();
-                            for rib in this.lifetime_ribs.iter().rev() {
-                                extra_lifetime_params.extend(
-                                    rib.bindings
-                                        .iter()
-                                        .map(|(&ident, &(node_id, res))| (ident, node_id, res)),
-                                );
-                                match rib.kind {
-                                    LifetimeRibKind::Item => break,
-                                    LifetimeRibKind::AnonymousCreateParameter {
-                                        binder, ..
-                                    } => {
-                                        if let Some(earlier_fresh) =
-                                            this.r.extra_lifetime_params_map.get(&binder)
-                                        {
-                                            extra_lifetime_params.extend(earlier_fresh);
-                                        }
-                                    }
-                                    _ => {}
-                                }
-                            }
-                            this.r
-                                .extra_lifetime_params_map
-                                .insert(async_node_id, extra_lifetime_params);
-                        }
+                        this.record_lifetime_params_for_async(fn_id, async_node_id);
 
                         if let Some(body) = body {
                             // Ignore errors in function bodies if this is rustdoc
@@ -1958,7 +1931,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                     TyKind::ImplicitSelf => true,
                     TyKind::Path(None, _) => {
                         let path_res = self.r.partial_res_map[&ty.id].base_res();
-                        if let Res::SelfTy { .. } = path_res {
+                        if let Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } = path_res {
                             return true;
                         }
                         Some(path_res) == self.impl_self
@@ -2079,7 +2052,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 |this| {
                     let item_def_id = this.r.local_def_id(item.id).to_def_id();
                     this.with_self_rib(
-                        Res::SelfTy { trait_: None, alias_to: Some((item_def_id, false)) },
+                        Res::SelfTyAlias {
+                            alias_to: item_def_id,
+                            forbid_generic: false,
+                            is_trait_impl: false,
+                        },
                         |this| {
                             visit::walk_item(this, item);
                         },
@@ -2193,14 +2170,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                     },
                     |this| {
                         let local_def_id = this.r.local_def_id(item.id).to_def_id();
-                        this.with_self_rib(
-                            Res::SelfTy { trait_: Some(local_def_id), alias_to: None },
-                            |this| {
-                                this.visit_generics(generics);
-                                walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits);
-                                this.resolve_trait_items(items);
-                            },
-                        );
+                        this.with_self_rib(Res::SelfTyParam { trait_: local_def_id }, |this| {
+                            this.visit_generics(generics);
+                            walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits);
+                            this.resolve_trait_items(items);
+                        });
                     },
                 );
             }
@@ -2217,13 +2191,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                     },
                     |this| {
                         let local_def_id = this.r.local_def_id(item.id).to_def_id();
-                        this.with_self_rib(
-                            Res::SelfTy { trait_: Some(local_def_id), alias_to: None },
-                            |this| {
-                                this.visit_generics(generics);
-                                walk_list!(this, visit_param_bound, bounds, BoundKind::Bound);
-                            },
-                        );
+                        this.with_self_rib(Res::SelfTyParam { trait_: local_def_id }, |this| {
+                            this.visit_generics(generics);
+                            walk_list!(this, visit_param_bound, bounds, BoundKind::Bound);
+                        });
                     },
                 );
             }
@@ -2605,7 +2576,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             },
             |this| {
                 // Dummy self type for better errors if `Self` is used in the trait path.
-                this.with_self_rib(Res::SelfTy { trait_: None, alias_to: None }, |this| {
+                this.with_self_rib(Res::SelfTyParam { trait_: LOCAL_CRATE.as_def_id() }, |this| {
                     this.with_lifetime_rib(
                         LifetimeRibKind::AnonymousCreateParameter {
                             binder: item_id,
@@ -2629,9 +2600,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                                     }
 
                                     let item_def_id = item_def_id.to_def_id();
-                                    let res = Res::SelfTy {
-                                        trait_: trait_id,
-                                        alias_to: Some((item_def_id, false)),
+                                    let res = Res::SelfTyAlias {
+                                        alias_to: item_def_id,
+                                        forbid_generic: false,
+                                        is_trait_impl: trait_id.is_some()
                                     };
                                     this.with_self_rib(res, |this| {
                                         if let Some(trait_ref) = opt_trait_reference.as_ref() {
@@ -3926,6 +3898,36 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             Some((ident.name, ns)),
         )
     }
+
+    /// Construct the list of in-scope lifetime parameters for async lowering.
+    /// We include all lifetime parameters, either named or "Fresh".
+    /// The order of those parameters does not matter, as long as it is
+    /// deterministic.
+    fn record_lifetime_params_for_async(
+        &mut self,
+        fn_id: NodeId,
+        async_node_id: Option<(NodeId, Span)>,
+    ) {
+        if let Some((async_node_id, _)) = 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() {
+                extra_lifetime_params.extend(
+                    rib.bindings.iter().map(|(&ident, &(node_id, res))| (ident, node_id, res)),
+                );
+                match rib.kind {
+                    LifetimeRibKind::Item => break,
+                    LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
+                        if let Some(earlier_fresh) = self.r.extra_lifetime_params_map.get(&binder) {
+                            extra_lifetime_params.extend(earlier_fresh);
+                        }
+                    }
+                    _ => {}
+                }
+            }
+            self.r.extra_lifetime_params_map.insert(async_node_id, extra_lifetime_params);
+        }
+    }
 }
 
 struct LifetimeCountVisitor<'a, 'b> {
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 3c276a9ada9..2d339a4d070 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -130,6 +130,16 @@ pub(super) enum LifetimeElisionCandidate {
     Missing(MissingLifetime),
 }
 
+/// Only used for diagnostics.
+struct BaseError {
+    msg: String,
+    fallback_label: String,
+    span: Span,
+    span_label: Option<(Span, &'static str)>,
+    could_be_expr: bool,
+    suggestion: Option<(Span, &'static str, String)>,
+}
+
 impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
     fn def_span(&self, def_id: DefId) -> Option<Span> {
         match def_id.krate {
@@ -138,35 +148,18 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
         }
     }
 
-    /// Handles error reporting for `smart_resolve_path_fragment` function.
-    /// Creates base error and amends it with one short label and possibly some longer helps/notes.
-    pub(crate) fn smart_resolve_report_errors(
+    fn make_base_error(
         &mut self,
         path: &[Segment],
         span: Span,
         source: PathSource<'_>,
         res: Option<Res>,
-    ) -> (DiagnosticBuilder<'a, ErrorGuaranteed>, Vec<ImportSuggestion>) {
-        let ident_span = path.last().map_or(span, |ident| ident.ident.span);
-        let ns = source.namespace();
-        let is_expected = &|res| source.is_expected(res);
-        let is_enum_variant = &|res| matches!(res, Res::Def(DefKind::Variant, _));
-
-        debug!(?res, ?source);
-
+    ) -> BaseError {
         // Make the base error.
-        struct BaseError<'a> {
-            msg: String,
-            fallback_label: String,
-            span: Span,
-            span_label: Option<(Span, &'a str)>,
-            could_be_expr: bool,
-            suggestion: Option<(Span, &'a str, String)>,
-        }
         let mut expected = source.descr_expected();
         let path_str = Segment::names_to_string(path);
         let item_str = path.last().unwrap().ident;
-        let base_error = if let Some(res) = res {
+        if let Some(res) = res {
             BaseError {
                 msg: format!("expected {}, found {} `{}`", expected, res.descr(), path_str),
                 fallback_label: format!("not a {expected}"),
@@ -277,8 +270,20 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                 could_be_expr: false,
                 suggestion,
             }
-        };
+        }
+    }
 
+    /// Handles error reporting for `smart_resolve_path_fragment` function.
+    /// Creates base error and amends it with one short label and possibly some longer helps/notes.
+    pub(crate) fn smart_resolve_report_errors(
+        &mut self,
+        path: &[Segment],
+        span: Span,
+        source: PathSource<'_>,
+        res: Option<Res>,
+    ) -> (DiagnosticBuilder<'a, ErrorGuaranteed>, Vec<ImportSuggestion>) {
+        debug!(?res, ?source);
+        let base_error = self.make_base_error(path, span, source, res);
         let code = source.error_code(res.is_some());
         let mut err =
             self.r.session.struct_span_err_with_code(base_error.span, &base_error.msg, code);
@@ -289,41 +294,79 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
             err.span_label(span, label);
         }
 
-        if let Some(sugg) = base_error.suggestion {
-            err.span_suggestion_verbose(sugg.0, sugg.1, sugg.2, Applicability::MaybeIncorrect);
+        if let Some(ref sugg) = base_error.suggestion {
+            err.span_suggestion_verbose(sugg.0, sugg.1, &sugg.2, Applicability::MaybeIncorrect);
         }
 
-        if let Some(span) = self.diagnostic_metadata.current_block_could_be_bare_struct_literal {
-            err.multipart_suggestion(
-                "you might have meant to write a `struct` literal",
-                vec![
-                    (span.shrink_to_lo(), "{ SomeStruct ".to_string()),
-                    (span.shrink_to_hi(), "}".to_string()),
-                ],
-                Applicability::HasPlaceholders,
-            );
+        self.suggest_bare_struct_literal(&mut err);
+        self.suggest_pattern_match_with_let(&mut err, source, span);
+
+        self.suggest_self_or_self_ref(&mut err, path, span);
+        self.detect_assoct_type_constraint_meant_as_path(&mut err, &base_error);
+        if self.suggest_self_ty(&mut err, source, path, span)
+            || self.suggest_self_value(&mut err, source, path, span)
+        {
+            return (err, Vec::new());
         }
-        match (source, self.diagnostic_metadata.in_if_condition) {
-            (
-                PathSource::Expr(_),
-                Some(Expr { span: expr_span, kind: ExprKind::Assign(lhs, _, _), .. }),
-            ) => {
-                // Icky heuristic so we don't suggest:
-                // `if (i + 2) = 2` => `if let (i + 2) = 2` (approximately pattern)
-                // `if 2 = i` => `if let 2 = i` (lhs needs to contain error span)
-                if lhs.is_approximately_pattern() && lhs.span.contains(span) {
-                    err.span_suggestion_verbose(
-                        expr_span.shrink_to_lo(),
-                        "you might have meant to use pattern matching",
-                        "let ",
-                        Applicability::MaybeIncorrect,
-                    );
+
+        let (found, candidates) =
+            self.try_lookup_name_relaxed(&mut err, source, path, span, res, &base_error);
+        if found {
+            return (err, candidates);
+        }
+
+        if !self.type_ascription_suggestion(&mut err, base_error.span) {
+            let mut fallback =
+                self.suggest_trait_and_bounds(&mut err, source, res, span, &base_error);
+            fallback |= self.suggest_typo(&mut err, source, path, span, &base_error);
+            if fallback {
+                // Fallback label.
+                err.span_label(base_error.span, &base_error.fallback_label);
+            }
+        }
+        self.err_code_special_cases(&mut err, source, path, span);
+
+        (err, candidates)
+    }
+
+    fn detect_assoct_type_constraint_meant_as_path(
+        &self,
+        err: &mut Diagnostic,
+        base_error: &BaseError,
+    ) {
+        let Some(ty) = self.diagnostic_metadata.current_type_path else { return; };
+        let TyKind::Path(_, path) = &ty.kind else { return; };
+        for segment in &path.segments {
+            let Some(params) = &segment.args else { continue; };
+            let ast::GenericArgs::AngleBracketed(ref params) = params.deref() else { continue; };
+            for param in &params.args {
+                let ast::AngleBracketedArg::Constraint(constraint) = param else { continue; };
+                let ast::AssocConstraintKind::Bound { bounds } = &constraint.kind else {
+                    continue;
+                };
+                for bound in bounds {
+                    let ast::GenericBound::Trait(trait_ref, ast::TraitBoundModifier::None)
+                        = bound else
+                    {
+                        continue;
+                    };
+                    if base_error.span == trait_ref.span {
+                        err.span_suggestion_verbose(
+                            constraint.ident.span.between(trait_ref.span),
+                            "you might have meant to write a path instead of an associated type bound",
+                            "::",
+                            Applicability::MachineApplicable,
+                        );
+                    }
                 }
             }
-            _ => {}
         }
+    }
 
+    fn suggest_self_or_self_ref(&mut self, err: &mut Diagnostic, path: &[Segment], span: Span) {
         let is_assoc_fn = self.self_type_is_available();
+        let Some(path_last_segment) = path.last() else { return };
+        let item_str = path_last_segment.ident;
         // Emit help message for fake-self from other languages (e.g., `this` in Javascript).
         if ["this", "my"].contains(&item_str.as_str()) && is_assoc_fn {
             err.span_suggestion_short(
@@ -358,96 +401,25 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                 }
             }
         }
+    }
 
-        self.detect_assoct_type_constraint_meant_as_path(base_error.span, &mut err);
-
-        // Emit special messages for unresolved `Self` and `self`.
-        if is_self_type(path, ns) {
-            err.code(rustc_errors::error_code!(E0411));
-            err.span_label(
-                span,
-                "`Self` is only available in impls, traits, and type definitions".to_string(),
-            );
-            if let Some(item_kind) = self.diagnostic_metadata.current_item {
-                err.span_label(
-                    item_kind.ident.span,
-                    format!(
-                        "`Self` not allowed in {} {}",
-                        item_kind.kind.article(),
-                        item_kind.kind.descr()
-                    ),
-                );
-            }
-            return (err, Vec::new());
-        }
-        if is_self_value(path, ns) {
-            debug!("smart_resolve_path_fragment: E0424, source={:?}", source);
-
-            err.code(rustc_errors::error_code!(E0424));
-            err.span_label(span, match source {
-                PathSource::Pat => "`self` value is a keyword and may not be bound to variables or shadowed",
-                _ => "`self` value is a keyword only available in methods with a `self` parameter",
-            });
-            if let Some((fn_kind, span)) = &self.diagnostic_metadata.current_function {
-                // The current function has a `self' parameter, but we were unable to resolve
-                // a reference to `self`. This can only happen if the `self` identifier we
-                // are resolving came from a different hygiene context.
-                if fn_kind.decl().inputs.get(0).map_or(false, |p| p.is_self()) {
-                    err.span_label(*span, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters");
-                } else {
-                    let doesnt = if is_assoc_fn {
-                        let (span, sugg) = fn_kind
-                            .decl()
-                            .inputs
-                            .get(0)
-                            .map(|p| (p.span.shrink_to_lo(), "&self, "))
-                            .unwrap_or_else(|| {
-                                // Try to look for the "(" after the function name, if possible.
-                                // This avoids placing the suggestion into the visibility specifier.
-                                let span = fn_kind
-                                    .ident()
-                                    .map_or(*span, |ident| span.with_lo(ident.span.hi()));
-                                (
-                                    self.r
-                                        .session
-                                        .source_map()
-                                        .span_through_char(span, '(')
-                                        .shrink_to_hi(),
-                                    "&self",
-                                )
-                            });
-                        err.span_suggestion_verbose(
-                            span,
-                            "add a `self` receiver parameter to make the associated `fn` a method",
-                            sugg,
-                            Applicability::MaybeIncorrect,
-                        );
-                        "doesn't"
-                    } else {
-                        "can't"
-                    };
-                    if let Some(ident) = fn_kind.ident() {
-                        err.span_label(
-                            ident.span,
-                            &format!("this function {} have a `self` parameter", doesnt),
-                        );
-                    }
-                }
-            } else if let Some(item_kind) = self.diagnostic_metadata.current_item {
-                err.span_label(
-                    item_kind.ident.span,
-                    format!(
-                        "`self` not allowed in {} {}",
-                        item_kind.kind.article(),
-                        item_kind.kind.descr()
-                    ),
-                );
-            }
-            return (err, Vec::new());
-        }
-
+    fn try_lookup_name_relaxed(
+        &mut self,
+        err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+        source: PathSource<'_>,
+        path: &[Segment],
+        span: Span,
+        res: Option<Res>,
+        base_error: &BaseError,
+    ) -> (bool, Vec<ImportSuggestion>) {
         // Try to lookup name in more relaxed fashion for better error reporting.
         let ident = path.last().unwrap().ident;
+        let is_expected = &|res| source.is_expected(res);
+        let ns = source.namespace();
+        let is_enum_variant = &|res| matches!(res, Res::Def(DefKind::Variant, _));
+        let path_str = Segment::names_to_string(path);
+        let ident_span = path.last().map_or(span, |ident| ident.ident.span);
+
         let mut candidates = self
             .r
             .lookup_import_candidates(ident, ns, &self.parent_scope, is_expected)
@@ -494,7 +466,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                     {
                         // Already reported this issue on the lhs of the type ascription.
                         err.delay_as_bug();
-                        return (err, candidates);
+                        return (true, candidates);
                     }
                 }
 
@@ -522,8 +494,9 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                 );
             }
         }
+
         // Try Levenshtein algorithm.
-        let typo_sugg = self.lookup_typo_candidate(path, ns, is_expected);
+        let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected);
         if path.len() == 1 && self.self_type_is_available() {
             if let Some(candidate) = self.lookup_assoc_candidate(ident, ns, is_expected) {
                 let self_is_available = self.self_value_is_available(path[0].ident.span);
@@ -560,8 +533,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                         );
                     }
                 }
-                self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span);
-                return (err, candidates);
+                self.r.add_typo_suggestion(err, typo_sugg, ident_span);
+                return (true, candidates);
             }
 
             // If the first argument in call is `self` suggest calling a method.
@@ -579,14 +552,14 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                     format!("self.{path_str}({args_snippet})"),
                     Applicability::MachineApplicable,
                 );
-                return (err, candidates);
+                return (true, candidates);
             }
         }
 
         // Try context-dependent help if relaxed lookup didn't work.
         if let Some(res) = res {
             if self.smart_resolve_context_dependent_help(
-                &mut err,
+                err,
                 span,
                 source,
                 res,
@@ -594,106 +567,135 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                 &base_error.fallback_label,
             ) {
                 // We do this to avoid losing a secondary span when we override the main error span.
-                self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span);
-                return (err, candidates);
+                self.r.add_typo_suggestion(err, typo_sugg, ident_span);
+                return (true, candidates);
             }
         }
+        return (false, candidates);
+    }
 
+    fn suggest_trait_and_bounds(
+        &mut self,
+        err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+        source: PathSource<'_>,
+        res: Option<Res>,
+        span: Span,
+        base_error: &BaseError,
+    ) -> bool {
         let is_macro =
             base_error.span.from_expansion() && base_error.span.desugaring_kind().is_none();
-        if !self.type_ascription_suggestion(&mut err, base_error.span) {
-            let mut fallback = false;
-            if let (
-                PathSource::Trait(AliasPossibility::Maybe),
-                Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)),
-                false,
-            ) = (source, res, is_macro)
-            {
-                if let Some(bounds @ [_, .., _]) = self.diagnostic_metadata.current_trait_object {
-                    fallback = true;
-                    let spans: Vec<Span> = bounds
-                        .iter()
-                        .map(|bound| bound.span())
-                        .filter(|&sp| sp != base_error.span)
-                        .collect();
+        let mut fallback = false;
 
-                    let start_span = bounds[0].span();
-                    // `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)
-                    let end_span = bounds.last().unwrap().span();
-                    // `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)
-                    let last_bound_span = spans.last().cloned().unwrap();
-                    let mut multi_span: MultiSpan = spans.clone().into();
-                    for sp in spans {
-                        let msg = if sp == last_bound_span {
-                            format!(
-                                "...because of {these} bound{s}",
-                                these = pluralize!("this", bounds.len() - 1),
-                                s = pluralize!(bounds.len() - 1),
-                            )
-                        } else {
-                            String::new()
-                        };
-                        multi_span.push_span_label(sp, msg);
-                    }
-                    multi_span
-                        .push_span_label(base_error.span, "expected this type to be a trait...");
-                    err.span_help(
-                        multi_span,
-                        "`+` is used to constrain a \"trait object\" type with lifetimes or \
-                         auto-traits; structs and enums can't be bound in that way",
-                    );
-                    if bounds.iter().all(|bound| match bound {
-                        ast::GenericBound::Outlives(_) => true,
-                        ast::GenericBound::Trait(tr, _) => tr.span == base_error.span,
-                    }) {
-                        let mut sugg = vec![];
-                        if base_error.span != start_span {
-                            sugg.push((start_span.until(base_error.span), String::new()));
-                        }
-                        if base_error.span != end_span {
-                            sugg.push((base_error.span.shrink_to_hi().to(end_span), String::new()));
-                        }
+        if let (
+            PathSource::Trait(AliasPossibility::Maybe),
+            Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)),
+            false,
+        ) = (source, res, is_macro)
+        {
+            if let Some(bounds @ [_, .., _]) = self.diagnostic_metadata.current_trait_object {
+                fallback = true;
+                let spans: Vec<Span> = bounds
+                    .iter()
+                    .map(|bound| bound.span())
+                    .filter(|&sp| sp != base_error.span)
+                    .collect();
 
-                        err.multipart_suggestion(
-                            "if you meant to use a type and not a trait here, remove the bounds",
-                            sugg,
-                            Applicability::MaybeIncorrect,
-                        );
+                let start_span = bounds[0].span();
+                // `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)
+                let end_span = bounds.last().unwrap().span();
+                // `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)
+                let last_bound_span = spans.last().cloned().unwrap();
+                let mut multi_span: MultiSpan = spans.clone().into();
+                for sp in spans {
+                    let msg = if sp == last_bound_span {
+                        format!(
+                            "...because of {these} bound{s}",
+                            these = pluralize!("this", bounds.len() - 1),
+                            s = pluralize!(bounds.len() - 1),
+                        )
+                    } else {
+                        String::new()
+                    };
+                    multi_span.push_span_label(sp, msg);
+                }
+                multi_span.push_span_label(base_error.span, "expected this type to be a trait...");
+                err.span_help(
+                    multi_span,
+                    "`+` is used to constrain a \"trait object\" type with lifetimes or \
+                        auto-traits; structs and enums can't be bound in that way",
+                );
+                if bounds.iter().all(|bound| match bound {
+                    ast::GenericBound::Outlives(_) => true,
+                    ast::GenericBound::Trait(tr, _) => tr.span == base_error.span,
+                }) {
+                    let mut sugg = vec![];
+                    if base_error.span != start_span {
+                        sugg.push((start_span.until(base_error.span), String::new()));
                     }
+                    if base_error.span != end_span {
+                        sugg.push((base_error.span.shrink_to_hi().to(end_span), String::new()));
+                    }
+
+                    err.multipart_suggestion(
+                        "if you meant to use a type and not a trait here, remove the bounds",
+                        sugg,
+                        Applicability::MaybeIncorrect,
+                    );
                 }
             }
+        }
 
-            fallback |= self.restrict_assoc_type_in_where_clause(span, &mut err);
+        fallback |= self.restrict_assoc_type_in_where_clause(span, err);
+        fallback
+    }
 
-            if !self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span) {
-                fallback = true;
-                match self.diagnostic_metadata.current_let_binding {
-                    Some((pat_sp, Some(ty_sp), None))
-                        if ty_sp.contains(base_error.span) && base_error.could_be_expr =>
-                    {
-                        err.span_suggestion_short(
-                            pat_sp.between(ty_sp),
-                            "use `=` if you meant to assign",
-                            " = ",
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                    _ => {}
+    fn suggest_typo(
+        &mut self,
+        err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+        source: PathSource<'_>,
+        path: &[Segment],
+        span: Span,
+        base_error: &BaseError,
+    ) -> bool {
+        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 mut fallback = false;
+        if !self.r.add_typo_suggestion(err, typo_sugg, ident_span) {
+            fallback = true;
+            match self.diagnostic_metadata.current_let_binding {
+                Some((pat_sp, Some(ty_sp), None))
+                    if ty_sp.contains(base_error.span) && base_error.could_be_expr =>
+                {
+                    err.span_suggestion_short(
+                        pat_sp.between(ty_sp),
+                        "use `=` if you meant to assign",
+                        " = ",
+                        Applicability::MaybeIncorrect,
+                    );
                 }
-
-                // 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(&mut err, suggestion, ident_span);
-            }
-            if fallback {
-                // Fallback label.
-                err.span_label(base_error.span, base_error.fallback_label);
+                _ => {}
             }
+
+            // 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);
         }
+        fallback
+    }
+
+    fn err_code_special_cases(
+        &mut self,
+        err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+        source: PathSource<'_>,
+        path: &[Segment],
+        span: Span,
+    ) {
         if let Some(err_code) = &err.code {
             if err_code == &rustc_errors::error_code!(E0425) {
                 for label_rib in &self.label_ribs {
                     for (label_ident, node_id) in &label_rib.bindings {
+                        let ident = path.last().unwrap().ident;
                         if format!("'{}", ident) == label_ident.to_string() {
                             err.span_label(label_ident.span, "a label with a similar name exists");
                             if let PathSource::Expr(Some(Expr {
@@ -724,38 +726,116 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                 }
             }
         }
+    }
 
-        (err, candidates)
+    /// Emit special messages for unresolved `Self` and `self`.
+    fn suggest_self_ty(
+        &mut self,
+        err: &mut Diagnostic,
+        source: PathSource<'_>,
+        path: &[Segment],
+        span: Span,
+    ) -> bool {
+        if !is_self_type(path, source.namespace()) {
+            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(),
+        );
+        if let Some(item_kind) = self.diagnostic_metadata.current_item {
+            err.span_label(
+                item_kind.ident.span,
+                format!(
+                    "`Self` not allowed in {} {}",
+                    item_kind.kind.article(),
+                    item_kind.kind.descr()
+                ),
+            );
+        }
+        true
     }
 
-    fn detect_assoct_type_constraint_meant_as_path(&self, base_span: Span, err: &mut Diagnostic) {
-        let Some(ty) = self.diagnostic_metadata.current_type_path else { return; };
-        let TyKind::Path(_, path) = &ty.kind else { return; };
-        for segment in &path.segments {
-            let Some(params) = &segment.args else { continue; };
-            let ast::GenericArgs::AngleBracketed(ref params) = params.deref() else { continue; };
-            for param in &params.args {
-                let ast::AngleBracketedArg::Constraint(constraint) = param else { continue; };
-                let ast::AssocConstraintKind::Bound { bounds } = &constraint.kind else {
-                    continue;
+    fn suggest_self_value(
+        &mut self,
+        err: &mut Diagnostic,
+        source: PathSource<'_>,
+        path: &[Segment],
+        span: Span,
+    ) -> bool {
+        if !is_self_value(path, source.namespace()) {
+            return false;
+        }
+
+        debug!("smart_resolve_path_fragment: E0424, source={:?}", source);
+        err.code(rustc_errors::error_code!(E0424));
+        err.span_label(
+            span,
+            match source {
+                PathSource::Pat => {
+                    "`self` value is a keyword and may not be bound to variables or shadowed"
+                }
+                _ => "`self` value is a keyword only available in methods with a `self` parameter",
+            },
+        );
+        let is_assoc_fn = self.self_type_is_available();
+        if let Some((fn_kind, span)) = &self.diagnostic_metadata.current_function {
+            // The current function has a `self' parameter, but we were unable to resolve
+            // a reference to `self`. This can only happen if the `self` identifier we
+            // are resolving came from a different hygiene context.
+            if fn_kind.decl().inputs.get(0).map_or(false, |p| p.is_self()) {
+                err.span_label(*span, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters");
+            } else {
+                let doesnt = if is_assoc_fn {
+                    let (span, sugg) = fn_kind
+                        .decl()
+                        .inputs
+                        .get(0)
+                        .map(|p| (p.span.shrink_to_lo(), "&self, "))
+                        .unwrap_or_else(|| {
+                            // Try to look for the "(" after the function name, if possible.
+                            // This avoids placing the suggestion into the visibility specifier.
+                            let span = fn_kind
+                                .ident()
+                                .map_or(*span, |ident| span.with_lo(ident.span.hi()));
+                            (
+                                self.r
+                                    .session
+                                    .source_map()
+                                    .span_through_char(span, '(')
+                                    .shrink_to_hi(),
+                                "&self",
+                            )
+                        });
+                    err.span_suggestion_verbose(
+                        span,
+                        "add a `self` receiver parameter to make the associated `fn` a method",
+                        sugg,
+                        Applicability::MaybeIncorrect,
+                    );
+                    "doesn't"
+                } else {
+                    "can't"
                 };
-                for bound in bounds {
-                    let ast::GenericBound::Trait(trait_ref, ast::TraitBoundModifier::None)
-                        = bound else
-                    {
-                        continue;
-                    };
-                    if base_span == trait_ref.span {
-                        err.span_suggestion_verbose(
-                            constraint.ident.span.between(trait_ref.span),
-                            "you might have meant to write a path instead of an associated type bound",
-                            "::",
-                            Applicability::MachineApplicable,
-                        );
-                    }
+                if let Some(ident) = fn_kind.ident() {
+                    err.span_label(
+                        ident.span,
+                        &format!("this function {} have a `self` parameter", doesnt),
+                    );
                 }
             }
+        } else if let Some(item_kind) = self.diagnostic_metadata.current_item {
+            err.span_label(
+                item_kind.ident.span,
+                format!(
+                    "`self` not allowed in {} {}",
+                    item_kind.kind.article(),
+                    item_kind.kind.descr()
+                ),
+            );
         }
+        true
     }
 
     fn suggest_swapping_misplaced_self_ty_and_trait(
@@ -787,6 +867,45 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
         }
     }
 
+    fn suggest_bare_struct_literal(&mut self, err: &mut Diagnostic) {
+        if let Some(span) = self.diagnostic_metadata.current_block_could_be_bare_struct_literal {
+            err.multipart_suggestion(
+                "you might have meant to write a `struct` literal",
+                vec![
+                    (span.shrink_to_lo(), "{ SomeStruct ".to_string()),
+                    (span.shrink_to_hi(), "}".to_string()),
+                ],
+                Applicability::HasPlaceholders,
+            );
+        }
+    }
+
+    fn suggest_pattern_match_with_let(
+        &mut self,
+        err: &mut Diagnostic,
+        source: PathSource<'_>,
+        span: Span,
+    ) {
+        if let PathSource::Expr(_) = source &&
+        let Some(Expr {
+                    span: expr_span,
+                    kind: ExprKind::Assign(lhs, _, _),
+                    ..
+                })  = self.diagnostic_metadata.in_if_condition {
+            // Icky heuristic so we don't suggest:
+            // `if (i + 2) = 2` => `if let (i + 2) = 2` (approximately pattern)
+            // `if 2 = i` => `if let 2 = i` (lhs needs to contain error span)
+            if lhs.is_approximately_pattern() && lhs.span.contains(span) {
+                err.span_suggestion_verbose(
+                    expr_span.shrink_to_lo(),
+                    "you might have meant to use pattern matching",
+                    "let ",
+                    Applicability::MaybeIncorrect,
+                );
+            }
+        }
+    }
+
     fn get_single_associated_item(
         &mut self,
         path: &[Segment],
@@ -1330,7 +1449,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                     Applicability::HasPlaceholders,
                 );
             }
-            (Res::SelfTy { .. }, _) if ns == ValueNS => {
+            (Res::SelfTyParam { .. } | Res::SelfTyAlias { .. }, _) if ns == ValueNS => {
                 err.span_label(span, fallback_label);
                 err.note("can't use `Self` as a constructor, you must use the implemented struct");
             }
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index 4d970461712..0c29ff364dc 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -326,6 +326,7 @@ fn convert_named_region_map(named_region_map: NamedRegionMap) -> ResolveLifetime
     }
 
     debug!(?rl.defs);
+    debug!(?rl.late_bound_vars);
     rl
 }
 
@@ -339,24 +340,25 @@ fn convert_named_region_map(named_region_map: NamedRegionMap) -> ResolveLifetime
 /// This allows us to avoid cycles. Importantly, if we ask for lifetimes for lifetimes that have an owner
 /// other than the trait itself (like the trait methods or associated types), then we just use the regular
 /// `resolve_lifetimes`.
-fn resolve_lifetimes_for<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx ResolveLifetimes {
-    let item_id = item_for(tcx, def_id);
-    if item_id == def_id {
-        let item = tcx.hir().item(hir::ItemId { def_id: item_id });
+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 item = tcx.hir().item(item_id);
         match item.kind {
-            hir::ItemKind::Trait(..) => tcx.resolve_lifetimes_trait_definition(item_id),
-            _ => tcx.resolve_lifetimes(item_id),
+            hir::ItemKind::Trait(..) => tcx.resolve_lifetimes_trait_definition(local_def_id),
+            _ => tcx.resolve_lifetimes(local_def_id),
         }
     } else {
-        tcx.resolve_lifetimes(item_id)
+        tcx.resolve_lifetimes(local_def_id)
     }
 }
 
 /// Finds the `Item` that contains the given `LocalDefId`
-fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> LocalDefId {
+fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> hir::ItemId {
     match tcx.hir().find_by_def_id(local_def_id) {
         Some(Node::Item(item)) => {
-            return item.def_id;
+            return item.item_id();
         }
         _ => {}
     }
@@ -366,7 +368,7 @@ fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> LocalDefId {
         loop {
             let node = parent_iter.next().map(|n| n.1);
             match node {
-                Some(hir::Node::Item(item)) => break item.def_id,
+                Some(hir::Node::Item(item)) => break item.item_id(),
                 Some(hir::Node::Crate(_)) | None => bug!("Called `item_for` on an Item."),
                 _ => {}
             }
@@ -506,7 +508,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     })
                     .unzip();
 
-            self.map.late_bound_vars.insert(e.hir_id, binders);
+            self.record_late_bound_vars(e.hir_id, binders);
             let scope = Scope::Binder {
                 hir_id: e.hir_id,
                 lifetimes,
@@ -530,7 +532,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
         match &item.kind {
             hir::ItemKind::Impl(hir::Impl { of_trait, .. }) => {
                 if let Some(of_trait) = of_trait {
-                    self.map.late_bound_vars.insert(of_trait.hir_ref_id, Vec::default());
+                    self.record_late_bound_vars(of_trait.hir_ref_id, Vec::default());
                 }
             }
             _ => {}
@@ -566,13 +568,12 @@ 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(self.tcx.hir().local_def_id_to_hir_id(item.def_id))
-                {
+                for (_hir_id, node) in self.tcx.hir().parent_iter(item.def_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));
+                            let resolved_lifetimes: &ResolveLifetimes = self.tcx.resolve_lifetimes(
+                                item_for(self.tcx, parent_item.def_id.def_id).def_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() {
                                 defs.iter().for_each(|(&local_id, region)| {
@@ -583,7 +584,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                                 resolved_lifetimes.late_bound_vars.iter()
                             {
                                 late_bound_vars.iter().for_each(|(&local_id, late_bound_vars)| {
-                                    self.map.late_bound_vars.insert(
+                                    self.record_late_bound_vars(
                                         hir::HirId { owner, local_id },
                                         late_bound_vars.clone(),
                                     );
@@ -614,7 +615,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                         GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None,
                     })
                     .collect();
-                self.map.late_bound_vars.insert(item.hir_id(), vec![]);
+                self.record_late_bound_vars(item.hir_id(), vec![]);
                 let scope = Scope::Binder {
                     hir_id: item.hir_id(),
                     lifetimes,
@@ -663,7 +664,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                         (pair, r)
                     })
                     .unzip();
-                self.map.late_bound_vars.insert(ty.hir_id, binders);
+                self.record_late_bound_vars(ty.hir_id, binders);
                 let scope = Scope::Binder {
                     hir_id: ty.hir_id,
                     lifetimes,
@@ -817,7 +818,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                         GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {}
                     }
                 }
-                self.map.late_bound_vars.insert(ty.hir_id, vec![]);
+                self.record_late_bound_vars(ty.hir_id, vec![]);
 
                 let scope = Scope::Binder {
                     hir_id: ty.hir_id,
@@ -861,7 +862,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                         GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None,
                     })
                     .collect();
-                self.map.late_bound_vars.insert(trait_item.hir_id(), vec![]);
+                self.record_late_bound_vars(trait_item.hir_id(), vec![]);
                 let scope = Scope::Binder {
                     hir_id: trait_item.hir_id(),
                     lifetimes,
@@ -909,9 +910,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                         GenericParamKind::Const { .. } | GenericParamKind::Type { .. } => None,
                     })
                     .collect();
-                self.map.late_bound_vars.insert(ty.hir_id, vec![]);
+                self.record_late_bound_vars(impl_item.hir_id(), vec![]);
                 let scope = Scope::Binder {
-                    hir_id: ty.hir_id,
+                    hir_id: impl_item.hir_id(),
                     lifetimes,
                     s: self.scope,
                     scope_type: BinderScopeType::Normal,
@@ -995,13 +996,14 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
             for predicate in generics.predicates {
                 match predicate {
                     &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
+                        hir_id,
                         ref bounded_ty,
                         bounds,
                         ref bound_generic_params,
                         origin,
                         ..
                     }) => {
-                        let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) =
+                        let lifetimes: FxIndexMap<LocalDefId, Region> =
                             bound_generic_params
                                 .iter()
                                 .filter(|param| {
@@ -1009,19 +1011,23 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                                 })
                                 .enumerate()
                                 .map(|(late_bound_idx, param)| {
-                                    let pair =
-                                        Region::late(late_bound_idx as u32, this.tcx.hir(), param);
-                                    let r = late_region_as_bound_region(this.tcx, &pair.1);
-                                    (pair, r)
+                                        Region::late(late_bound_idx as u32, this.tcx.hir(), param)
+                                })
+                                .collect();
+                        let binders: Vec<_> =
+                            lifetimes
+                                .iter()
+                                .map(|(_, region)| {
+                                     late_region_as_bound_region(this.tcx, region)
                                 })
-                                .unzip();
-                        this.map.late_bound_vars.insert(bounded_ty.hir_id, binders.clone());
+                                .collect();
+                        this.record_late_bound_vars(hir_id, binders.clone());
                         // Even if there are no lifetimes defined here, we still wrap it in a binder
                         // scope. If there happens to be a nested poly trait ref (an error), that
                         // will be `Concatenating` anyways, so we don't have to worry about the depth
                         // being wrong.
                         let scope = Scope::Binder {
-                            hir_id: bounded_ty.hir_id,
+                            hir_id,
                             lifetimes,
                             s: this.scope,
                             scope_type: BinderScopeType::Normal,
@@ -1089,7 +1095,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 // imagine there's a better way to go about this.
                 let (binders, scope_type) = self.poly_trait_ref_binder_info();
 
-                self.map.late_bound_vars.insert(*hir_id, binders);
+                self.record_late_bound_vars(*hir_id, binders);
                 let scope = Scope::Binder {
                     hir_id: *hir_id,
                     lifetimes: FxIndexMap::default(),
@@ -1127,7 +1133,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
         binders.extend(binders_iter);
 
         debug!(?binders);
-        self.map.late_bound_vars.insert(trait_ref.trait_ref.hir_ref_id, binders);
+        self.record_late_bound_vars(trait_ref.trait_ref.hir_ref_id, binders);
 
         // Always introduce a scope here, even if this is in a where clause and
         // we introduced the binders around the bounded Ty. In that case, we
@@ -1211,6 +1217,15 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         }
     }
 
+    fn record_late_bound_vars(&mut self, hir_id: hir::HirId, binder: Vec<ty::BoundVariableKind>) {
+        if let Some(old) = self.map.late_bound_vars.insert(hir_id, binder) {
+            bug!(
+                "overwrote bound vars for {hir_id:?}:\nold={old:?}\nnew={:?}",
+                self.map.late_bound_vars[&hir_id]
+            )
+        }
+    }
+
     /// Visits self by adding a scope and handling recursive walk over the contents with `walk`.
     ///
     /// Handles visiting fns and methods. These are a bit complicated because we must distinguish
@@ -1268,7 +1283,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                 late_region_as_bound_region(self.tcx, &pair.1)
             })
             .collect();
-        self.map.late_bound_vars.insert(hir_id, binders);
+        self.record_late_bound_vars(hir_id, binders);
         let scope = Scope::Binder {
             hir_id,
             lifetimes,
@@ -1315,7 +1330,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                     // regular fns.
                     if let Some(hir::PredicateOrigin::ImplTrait) = where_bound_origin
                         && let hir::LifetimeName::Param(_, hir::ParamName::Fresh) = lifetime_ref.name
-                        && let hir::IsAsync::NotAsync = self.tcx.asyncness(lifetime_ref.hir_id.owner)
+                        && let hir::IsAsync::NotAsync = self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id)
                         && !self.tcx.features().anonymous_lifetime_in_impl_trait
                     {
                         rustc_session::parse::feature_err(
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 54a7f416ce6..9b52decd9c7 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -4,7 +4,7 @@
 //! Paths in macros, imports, expressions, types, patterns are resolved here.
 //! Label and lifetime names are resolved here as well.
 //!
-//! Type-relative name resolution (methods, fields, associated items) happens in `rustc_typeck`.
+//! 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(box_patterns)]
@@ -12,7 +12,6 @@
 #![feature(if_let_guard)]
 #![feature(iter_intersperse)]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(never_type)]
 #![recursion_limit = "256"]
 #![allow(rustdoc::private_intra_doc_links)]
diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs
index 8bd42d8d216..ecb09f0c4b7 100644
--- a/compiler/rustc_save_analysis/src/dump_visitor.rs
+++ b/compiler/rustc_save_analysis/src/dump_visitor.rs
@@ -345,14 +345,14 @@ impl<'tcx> DumpVisitor<'tcx> {
         body: hir::BodyId,
     ) {
         let map = self.tcx.hir();
-        self.nest_typeck_results(item.def_id, |v| {
+        self.nest_typeck_results(item.def_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), fn_data);
+                v.dumper.dump_def(&access_from!(v.save_ctxt, item.def_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, |v| {
+        self.nest_typeck_results(item.def_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), var_data);
+                v.dumper.dump_def(&access_from!(v.save_ctxt, item.def_id.def_id), var_data);
             }
             v.visit_ty(&typ);
             v.visit_expr(expr);
@@ -473,7 +473,7 @@ 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),
+                &access_from!(self.save_ctxt, item.def_id.def_id),
                 Def {
                     kind,
                     id: id_from_def_id(item.def_id.to_def_id()),
@@ -491,7 +491,7 @@ impl<'tcx> DumpVisitor<'tcx> {
             );
         }
 
-        self.nest_typeck_results(item.def_id, |v| {
+        self.nest_typeck_results(item.def_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);
+        let access = access_from!(self.save_ctxt, item.def_id.def_id);
 
         for variant in enum_definition.variants {
             let name = variant.ident.name.to_string();
@@ -612,7 +612,7 @@ impl<'tcx> DumpVisitor<'tcx> {
         }
 
         let map = self.tcx.hir();
-        self.nest_typeck_results(item.def_id, |v| {
+        self.nest_typeck_results(item.def_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));
@@ -648,7 +648,7 @@ impl<'tcx> DumpVisitor<'tcx> {
                 methods.iter().map(|i| id_from_def_id(i.id.def_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),
+                &access_from!(self.save_ctxt, item.def_id.def_id),
                 Def {
                     kind: DefKind::Trait,
                     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), mod_data);
+            self.dumper.dump_def(&access_from!(self.save_ctxt, item.def_id.def_id), mod_data);
         }
     }
 
@@ -913,7 +913,8 @@ impl<'tcx> DumpVisitor<'tcx> {
                     | HirDefKind::AssocTy,
                     _,
                 )
-                | Res::SelfTy { .. } => {
+                | Res::SelfTyParam { .. }
+                | Res::SelfTyAlias { .. } => {
                     self.dump_path_segment_ref(
                         id,
                         &hir::PathSegment::new(ident, hir::HirId::INVALID, Res::Err),
@@ -980,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,
+                    trait_item.def_id.def_id,
                     trait_item.ident,
                     &ty,
                     body,
@@ -994,7 +995,7 @@ impl<'tcx> DumpVisitor<'tcx> {
                 self.process_method(
                     sig,
                     body,
-                    trait_item.def_id,
+                    trait_item.def_id.def_id,
                     trait_item.ident,
                     &trait_item.generics,
                     trait_item.span,
@@ -1050,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,
+                    impl_item.def_id.def_id,
                     impl_item.ident,
                     &ty,
                     Some(&body.value),
@@ -1062,7 +1063,7 @@ impl<'tcx> DumpVisitor<'tcx> {
                 self.process_method(
                     sig,
                     Some(body),
-                    impl_item.def_id,
+                    impl_item.def_id.def_id,
                     impl_item.ident,
                     &impl_item.generics,
                     impl_item.span,
@@ -1136,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);
+                    let access = access_from!(self.save_ctxt, item.def_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);
+                    let parent = self.save_ctxt.tcx.local_parent(item.def_id.def_id);
                     self.dumper.import(
                         &access,
                         Import {
@@ -1157,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);
+                let names = self.tcx.names_imported_by_glob_use(item.def_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);
+                        let access = access_from!(self.save_ctxt, item.def_id.def_id);
                         let span = self.span_from_span(sub_span);
-                        let parent = self.save_ctxt.tcx.local_parent(item.def_id);
+                        let parent = self.save_ctxt.tcx.local_parent(item.def_id.def_id);
                         self.dumper.import(
                             &access,
                             Import {
@@ -1187,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);
+                    let parent = self.save_ctxt.tcx.local_parent(item.def_id.def_id);
                     self.dumper.import(
                         &Access { public: false, reachable: false },
                         Import {
@@ -1235,7 +1236,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
                     let attrs = self.tcx.hir().attrs(item.hir_id());
 
                     self.dumper.dump_def(
-                        &access_from!(self.save_ctxt, item.def_id),
+                        &access_from!(self.save_ctxt, item.def_id.def_id),
                         Def {
                             kind: DefKind::Type,
                             id,
@@ -1323,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, |v| v.visit_item(item));
+                self.nest_typeck_results(item_id.def_id.def_id, |v| v.visit_item(item));
             }
             _ => intravisit::walk_ty(self, t),
         }
@@ -1430,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);
+        let access = access_from!(self.save_ctxt, item.def_id.def_id);
 
         match item.kind {
             hir::ForeignItemKind::Fn(decl, _, ref generics) => {
diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs
index ce03c2a8ad0..aa000b7067b 100644
--- a/compiler/rustc_save_analysis/src/lib.rs
+++ b/compiler/rustc_save_analysis/src/lib.rs
@@ -1,6 +1,5 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(if_let_guard)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
 #![feature(never_type)]
@@ -622,7 +621,7 @@ impl<'tcx> SaveContext<'tcx> {
                 hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => {
                     // #75962: `self.typeck_results` may be different from the `hir_id`'s result.
                     if self.tcx.has_typeck_results(hir_id.owner.to_def_id()) {
-                        self.tcx.typeck(hir_id.owner).qpath_res(qpath, hir_id)
+                        self.tcx.typeck(hir_id.owner.def_id).qpath_res(qpath, hir_id)
                     } else {
                         Res::Err
                     }
@@ -741,7 +740,8 @@ impl<'tcx> SaveContext<'tcx> {
                 _,
             )
             | Res::PrimTy(..)
-            | Res::SelfTy { .. }
+            | Res::SelfTyParam { .. }
+            | Res::SelfTyAlias { .. }
             | Res::ToolMod
             | Res::NonMacroAttr(..)
             | Res::SelfCtor(..)
@@ -806,7 +806,7 @@ impl<'tcx> SaveContext<'tcx> {
 
     fn lookup_def_id(&self, ref_id: hir::HirId) -> Option<DefId> {
         match self.get_path_res(ref_id) {
-            Res::PrimTy(_) | Res::SelfTy { .. } | Res::Err => None,
+            Res::PrimTy(_) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Err => None,
             def => def.opt_def_id(),
         }
     }
@@ -1041,7 +1041,7 @@ fn id_from_hir_id(id: hir::HirId, scx: &SaveContext<'_>) -> rls_data::Id {
         // crate (very unlikely to actually happen).
         rls_data::Id {
             krate: LOCAL_CRATE.as_u32(),
-            index: id.owner.local_def_index.as_u32() | id.local_id.as_u32().reverse_bits(),
+            index: id.owner.def_id.local_def_index.as_u32() | id.local_id.as_u32().reverse_bits(),
         }
     })
 }
diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs
index bae1828cd18..62e9f6520fb 100644
--- a/compiler/rustc_save_analysis/src/sig.rs
+++ b/compiler/rustc_save_analysis/src/sig.rs
@@ -579,7 +579,7 @@ impl<'hir> Sig for hir::Path<'hir> {
         let res = scx.get_path_res(id.ok_or("Missing id for Path")?);
 
         let (name, start, end) = match res {
-            Res::PrimTy(..) | Res::SelfTy { .. } | Res::Err => {
+            Res::PrimTy(..) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Err => {
                 return Ok(Signature { text: path_to_string(self), defs: vec![], refs: vec![] });
             }
             Res::Def(DefKind::AssocConst | DefKind::Variant | DefKind::Ctor(..), _) => {
diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs
index fa9c7bd54c3..1f8d2336c4e 100644
--- a/compiler/rustc_serialize/src/lib.rs
+++ b/compiler/rustc_serialize/src/lib.rs
@@ -14,7 +14,6 @@ Core encoding and decoding interfaces.
 #![feature(min_specialization)]
 #![feature(core_intrinsics)]
 #![feature(maybe_uninit_slice)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(new_uninit)]
 #![feature(allocator_api)]
 #![cfg_attr(test, feature(test))]
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index e01dafe2102..b5962f76b7f 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -219,3 +219,18 @@ impl IntoDiagnostic<'_> for InvalidCharacterInCrateName<'_> {
         diag
     }
 }
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(session::expr_parentheses_needed, applicability = "machine-applicable")]
+pub struct ExprParenthesesNeeded {
+    #[suggestion_part(code = "(")]
+    pub left: Span,
+    #[suggestion_part(code = ")")]
+    pub right: Span,
+}
+
+impl ExprParenthesesNeeded {
+    pub fn surrounding(s: Span) -> Self {
+        ExprParenthesesNeeded { left: s.shrink_to_lo(), right: s.shrink_to_hi() }
+    }
+}
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs
index f6bab775e76..39e871f532c 100644
--- a/compiler/rustc_session/src/lib.rs
+++ b/compiler/rustc_session/src/lib.rs
@@ -1,6 +1,5 @@
 #![feature(if_let_guard)]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(min_specialization)]
 #![feature(never_type)]
 #![feature(once_cell)]
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index d7f1bc0be84..486c514a4f5 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1409,8 +1409,6 @@ options! {
         "the size at which the `large_assignments` lint starts to be emitted"),
     mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "emit noalias metadata for mutable references (default: yes)"),
-    new_llvm_pass_manager: Option<bool> = (None, parse_opt_bool, [TRACKED],
-        "use new LLVM pass manager (default: no)"),
     nll_facts: bool = (false, parse_bool, [UNTRACKED],
         "dump facts from NLL analysis into side files (default: no)"),
     nll_facts_dir: String = ("nll-facts".to_string(), parse_string, [UNTRACKED],
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index b9202af2a67..d97e1df2a16 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -2,7 +2,9 @@
 //! It also serves as an input to the parser itself.
 
 use crate::config::CheckCfg;
-use crate::errors::{FeatureDiagnosticForIssue, FeatureDiagnosticHelp, FeatureGateError};
+use crate::errors::{
+    ExprParenthesesNeeded, FeatureDiagnosticForIssue, FeatureDiagnosticHelp, FeatureGateError,
+};
 use crate::lint::{
     builtin::UNSTABLE_SYNTAX_PRE_EXPANSION, BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId,
 };
@@ -11,7 +13,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
 use rustc_data_structures::sync::{Lock, Lrc};
 use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler};
 use rustc_errors::{
-    fallback_fluent_bundle, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId,
+    fallback_fluent_bundle, AddToDiagnostic, Diagnostic, DiagnosticBuilder, DiagnosticId,
     DiagnosticMessage, EmissionGuarantee, ErrorGuaranteed, IntoDiagnostic, MultiSpan, StashKey,
 };
 use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures};
@@ -325,11 +327,7 @@ impl ParseSess {
     /// Extend an error with a suggestion to wrap an expression with parentheses to allow the
     /// parser to continue parsing the following operation as part of the same expression.
     pub fn expr_parentheses_needed(&self, err: &mut Diagnostic, span: Span) {
-        err.multipart_suggestion(
-            "parentheses are required to parse this as an expression",
-            vec![(span.shrink_to_lo(), "(".to_string()), (span.shrink_to_hi(), ")".to_string())],
-            Applicability::MachineApplicable,
-        );
+        ExprParenthesesNeeded::surrounding(span).add_to_diagnostic(err);
     }
 
     pub fn save_proc_macro_span(&self, span: Span) -> usize {
@@ -376,8 +374,6 @@ impl ParseSess {
     }
 
     #[rustc_lint_diagnostics]
-    #[allow(rustc::diagnostic_outside_of_impl)]
-    #[allow(rustc::untranslatable_diagnostic)]
     pub fn struct_err(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -386,22 +382,16 @@ impl ParseSess {
     }
 
     #[rustc_lint_diagnostics]
-    #[allow(rustc::diagnostic_outside_of_impl)]
-    #[allow(rustc::untranslatable_diagnostic)]
     pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
         self.span_diagnostic.struct_warn(msg)
     }
 
     #[rustc_lint_diagnostics]
-    #[allow(rustc::diagnostic_outside_of_impl)]
-    #[allow(rustc::untranslatable_diagnostic)]
     pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
         self.span_diagnostic.struct_fatal(msg)
     }
 
     #[rustc_lint_diagnostics]
-    #[allow(rustc::diagnostic_outside_of_impl)]
-    #[allow(rustc::untranslatable_diagnostic)]
     pub fn struct_diagnostic<G: EmissionGuarantee>(
         &self,
         msg: impl Into<DiagnosticMessage>,
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 0142e981766..59b544ce9eb 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -288,8 +288,6 @@ impl Session {
     }
 
     #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn struct_span_warn<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -298,8 +296,6 @@ impl Session {
         self.diagnostic().struct_span_warn(sp, msg)
     }
     #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn struct_span_warn_with_expectation<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -309,8 +305,6 @@ impl Session {
         self.diagnostic().struct_span_warn_with_expectation(sp, msg, id)
     }
     #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn struct_span_warn_with_code<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -320,14 +314,10 @@ impl Session {
         self.diagnostic().struct_span_warn_with_code(sp, msg, code)
     }
     #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
         self.diagnostic().struct_warn(msg)
     }
     #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn struct_warn_with_expectation(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -336,8 +326,6 @@ impl Session {
         self.diagnostic().struct_warn_with_expectation(msg, id)
     }
     #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn struct_span_allow<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -346,14 +334,10 @@ impl Session {
         self.diagnostic().struct_span_allow(sp, msg)
     }
     #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
         self.diagnostic().struct_allow(msg)
     }
     #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn struct_expect(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -362,8 +346,6 @@ impl Session {
         self.diagnostic().struct_expect(msg, id)
     }
     #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn struct_span_err<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -372,8 +354,6 @@ impl Session {
         self.diagnostic().struct_span_err(sp, msg)
     }
     #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn struct_span_err_with_code<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -384,8 +364,6 @@ impl Session {
     }
     // FIXME: This method should be removed (every error should have an associated error code).
     #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn struct_err(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -393,8 +371,6 @@ impl Session {
         self.parse_sess.struct_err(msg)
     }
     #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn struct_err_with_code(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -403,8 +379,6 @@ impl Session {
         self.diagnostic().struct_err_with_code(msg, code)
     }
     #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn struct_warn_with_code(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -413,8 +387,6 @@ impl Session {
         self.diagnostic().struct_warn_with_code(msg, code)
     }
     #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn struct_span_fatal<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -423,8 +395,6 @@ impl Session {
         self.diagnostic().struct_span_fatal(sp, msg)
     }
     #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn struct_span_fatal_with_code<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -434,21 +404,15 @@ impl Session {
         self.diagnostic().struct_span_fatal_with_code(sp, msg, code)
     }
     #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
         self.diagnostic().struct_fatal(msg)
     }
 
     #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) -> ! {
         self.diagnostic().span_fatal(sp, msg)
     }
     #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn span_fatal_with_code<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -458,14 +422,10 @@ impl Session {
         self.diagnostic().span_fatal_with_code(sp, msg, code)
     }
     #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> ! {
         self.diagnostic().fatal(msg).raise()
     }
     #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn span_err_or_warn<S: Into<MultiSpan>>(
         &self,
         is_warning: bool,
@@ -479,8 +439,6 @@ impl Session {
         }
     }
     #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn span_err<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -489,8 +447,6 @@ impl Session {
         self.diagnostic().span_err(sp, msg)
     }
     #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn span_err_with_code<S: Into<MultiSpan>>(
         &self,
         sp: S,
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 366fd9d2cd1..f8df4169715 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -15,7 +15,6 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(array_windows)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(if_let_guard)]
 #![feature(negative_impls)]
 #![feature(min_specialization)]
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 502ef67fc67..09727b433b3 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -224,6 +224,7 @@ symbols! {
         Left,
         LinkedList,
         LintPass,
+        LocalKey,
         Mutex,
         MutexGuard,
         N,
@@ -266,6 +267,7 @@ symbols! {
         Rc,
         Ready,
         Receiver,
+        RefCell,
         Relaxed,
         Release,
         Result,
@@ -274,6 +276,7 @@ symbols! {
         Rust,
         RustcDecodable,
         RustcEncodable,
+        RwLock,
         RwLockReadGuard,
         RwLockWriteGuard,
         Send,
@@ -991,7 +994,18 @@ symbols! {
         never_type,
         never_type_fallback,
         new,
+        new_binary,
+        new_debug,
+        new_display,
+        new_lower_exp,
+        new_lower_hex,
+        new_octal,
+        new_pointer,
         new_unchecked,
+        new_upper_exp,
+        new_upper_hex,
+        new_v1,
+        new_v1_formatted,
         next,
         nll,
         no,
@@ -1282,6 +1296,7 @@ symbols! {
         rustc_reallocator,
         rustc_regions,
         rustc_reservation_impl,
+        rustc_safe_intrinsic,
         rustc_serialize,
         rustc_skip_array_during_method_dispatch,
         rustc_specialization_trait,
diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs
index 9d89c9c52b2..c8c6fe2bf85 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);
+            symbol_names.process_attrs(id.def_id.def_id);
         }
 
         for id in crate_items.trait_items() {
-            symbol_names.process_attrs(id.def_id);
+            symbol_names.process_attrs(id.def_id.def_id);
         }
 
         for id in crate_items.impl_items() {
-            symbol_names.process_attrs(id.def_id);
+            symbol_names.process_attrs(id.def_id.def_id);
         }
 
         for id in crate_items.foreign_items() {
-            symbol_names.process_attrs(id.def_id);
+            symbol_names.process_attrs(id.def_id.def_id);
         }
     })
 }
diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs
index a7deab9d2ef..aaba0d7f093 100644
--- a/compiler/rustc_target/src/lib.rs
+++ b/compiler/rustc_target/src/lib.rs
@@ -11,7 +11,6 @@
 #![feature(assert_matches)]
 #![feature(associated_type_bounds)]
 #![feature(exhaustive_patterns)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(min_specialization)]
 #![feature(never_type)]
 #![feature(rustc_attrs)]
diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs
index 803453c4ac4..9f4cc3d80f1 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs
@@ -1,11 +1,12 @@
 use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::freebsd_base::opts();
     base.cpu = "ppc64".into();
     base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
     base.max_atomic_width = Some(64);
+    base.stack_probes = StackProbeType::Inline;
 
     Target {
         llvm_target: "powerpc64-unknown-freebsd".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs
index 1cb9ce40cb1..21955a616c2 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs
@@ -1,11 +1,12 @@
 use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::linux_gnu_base::opts();
     base.cpu = "ppc64".into();
     base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
     base.max_atomic_width = Some(64);
+    base.stack_probes = StackProbeType::Inline;
 
     Target {
         llvm_target: "powerpc64-unknown-linux-gnu".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs
index 159335eb607..bbf86e4ff41 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs
@@ -1,11 +1,12 @@
 use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
     base.cpu = "ppc64".into();
     base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
     base.max_atomic_width = Some(64);
+    base.stack_probes = StackProbeType::Inline;
 
     Target {
         llvm_target: "powerpc64-unknown-linux-musl".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_openbsd.rs
index 9cb3a67dc58..bfa61a21fb3 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_openbsd.rs
@@ -1,11 +1,12 @@
 use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::openbsd_base::opts();
     base.cpu = "ppc64".into();
     base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
     base.max_atomic_width = Some(64);
+    base.stack_probes = StackProbeType::Inline;
 
     Target {
         llvm_target: "powerpc64-unknown-openbsd".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs
index b7420d232ca..4ebf342ad22 100644
--- a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs
@@ -1,11 +1,12 @@
 use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::vxworks_base::opts();
     base.cpu = "ppc64".into();
     base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
     base.max_atomic_width = Some(64);
+    base.stack_probes = StackProbeType::Inline;
 
     Target {
         llvm_target: "powerpc64-unknown-linux-gnu".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs
index a3d18004371..a7ab9078531 100644
--- a/compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs
@@ -1,10 +1,11 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::freebsd_base::opts();
     base.cpu = "ppc64le".into();
     base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
     base.max_atomic_width = Some(64);
+    base.stack_probes = StackProbeType::Inline;
 
     Target {
         llvm_target: "powerpc64le-unknown-freebsd".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs
index e18ff3be448..69fd6be6dc0 100644
--- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs
@@ -1,10 +1,11 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::linux_gnu_base::opts();
     base.cpu = "ppc64le".into();
     base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
     base.max_atomic_width = Some(64);
+    base.stack_probes = StackProbeType::Inline;
 
     Target {
         llvm_target: "powerpc64le-unknown-linux-gnu".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs
index b84943d23a9..ae3a8b54519 100644
--- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs
@@ -1,10 +1,11 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
     base.cpu = "ppc64le".into();
     base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
     base.max_atomic_width = Some(64);
+    base.stack_probes = StackProbeType::Inline;
 
     Target {
         llvm_target: "powerpc64le-unknown-linux-musl".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs
index 75ac66c276d..b5d4e5de05e 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs
@@ -1,11 +1,12 @@
 use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::freebsd_base::opts();
     // Extra hint to linker that we are generating secure-PLT code.
     base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32", "--target=powerpc-unknown-freebsd13.0"]);
     base.max_atomic_width = Some(32);
+    base.stack_probes = StackProbeType::Inline;
 
     Target {
         llvm_target: "powerpc-unknown-freebsd13.0".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs
index 6686a0bbf04..0ceb66c327b 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs
@@ -1,10 +1,11 @@
 use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::linux_gnu_base::opts();
     base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]);
     base.max_atomic_width = Some(32);
+    base.stack_probes = StackProbeType::Inline;
 
     Target {
         llvm_target: "powerpc-unknown-linux-gnu".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs
index 6a250f4b51c..716090f39ca 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs
@@ -1,10 +1,11 @@
 use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::linux_gnu_base::opts();
     base.add_pre_link_args(LinkerFlavor::Gcc, &["-mspe"]);
     base.max_atomic_width = Some(32);
+    base.stack_probes = StackProbeType::Inline;
 
     Target {
         llvm_target: "powerpc-unknown-linux-gnuspe".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs
index 34200c67906..d8cd158584a 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs
@@ -1,10 +1,11 @@
 use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
     base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]);
     base.max_atomic_width = Some(32);
+    base.stack_probes = StackProbeType::Inline;
 
     Target {
         llvm_target: "powerpc-unknown-linux-musl".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs
index 60661ef9b5d..7053e4b9c26 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs
@@ -1,10 +1,11 @@
 use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::netbsd_base::opts();
     base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]);
     base.max_atomic_width = Some(32);
+    base.stack_probes = StackProbeType::Inline;
 
     Target {
         llvm_target: "powerpc-unknown-netbsd".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_openbsd.rs b/compiler/rustc_target/src/spec/powerpc_unknown_openbsd.rs
index ad2c3d40f35..dec85f9961b 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_openbsd.rs
@@ -1,10 +1,11 @@
 use crate::abi::Endian;
-use crate::spec::Target;
+use crate::spec::{StackProbeType, Target};
 
 pub fn target() -> Target {
     let mut base = super::openbsd_base::opts();
     base.endian = Endian::Big;
     base.max_atomic_width = Some(32);
+    base.stack_probes = StackProbeType::Inline;
 
     Target {
         llvm_target: "powerpc-unknown-openbsd".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs
index 3f24966e06e..e0c5db6eacf 100644
--- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs
@@ -1,10 +1,11 @@
 use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::vxworks_base::opts();
     base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32", "--secure-plt"]);
     base.max_atomic_width = Some(32);
+    base.stack_probes = StackProbeType::Inline;
 
     Target {
         llvm_target: "powerpc-unknown-linux-gnu".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs
index 0f04f41f9e5..c7f41b1da87 100644
--- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs
+++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs
@@ -1,10 +1,11 @@
 use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::vxworks_base::opts();
     base.add_pre_link_args(LinkerFlavor::Gcc, &["-mspe", "--secure-plt"]);
     base.max_atomic_width = Some(32);
+    base.stack_probes = StackProbeType::Inline;
 
     Target {
         llvm_target: "powerpc-unknown-linux-gnuspe".into(),
diff --git a/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs
index 8757bbed8ad..9bb9c931f5c 100644
--- a/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs
@@ -1,5 +1,5 @@
 use crate::abi::Endian;
-use crate::spec::Target;
+use crate::spec::{StackProbeType, Target};
 
 pub fn target() -> Target {
     let mut base = super::linux_gnu_base::opts();
@@ -12,6 +12,7 @@ pub fn target() -> Target {
     base.features = "-vector".into();
     base.max_atomic_width = Some(64);
     base.min_global_align = Some(16);
+    base.stack_probes = StackProbeType::Inline;
 
     Target {
         llvm_target: "s390x-unknown-linux-gnu".into(),
diff --git a/compiler/rustc_target/src/spec/s390x_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/s390x_unknown_linux_musl.rs
index 4c855271a2a..f877279781d 100644
--- a/compiler/rustc_target/src/spec/s390x_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/s390x_unknown_linux_musl.rs
@@ -1,5 +1,5 @@
 use crate::abi::Endian;
-use crate::spec::Target;
+use crate::spec::{StackProbeType, Target};
 
 pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
@@ -13,6 +13,7 @@ pub fn target() -> Target {
     base.max_atomic_width = Some(64);
     base.min_global_align = Some(16);
     base.static_position_independent_executables = true;
+    base.stack_probes = StackProbeType::Inline;
 
     Target {
         llvm_target: "s390x-unknown-linux-musl".into(),
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index d35f74974fd..5d52aa07523 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -16,9 +16,7 @@
 #![feature(control_flow_enum)]
 #![feature(drain_filter)]
 #![feature(hash_drain_filter)]
-#![cfg_attr(bootstrap, feature(label_break_value))]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(if_let_guard)]
 #![feature(never_type)]
 #![feature(type_alias_impl_trait)]
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 d62b399c1b5..b0cabc6275f 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1898,7 +1898,9 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
                         // FIXME(compiler-errors): This could be generalized, both to
                         // be more granular, and probably look past other `#[fundamental]`
                         // types, too.
-                        self.tcx.visibility(def.did()).is_accessible_from(body_id.owner, self.tcx)
+                        self.tcx
+                            .visibility(def.did())
+                            .is_accessible_from(body_id.owner.def_id, self.tcx)
                     } else {
                         true
                     }
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 d90b77fc556..fff26547be0 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -659,7 +659,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 _ => {}
             }
 
-            hir_id = self.tcx.hir().local_def_id_to_hir_id(self.tcx.hir().get_parent_item(hir_id));
+            hir_id = self.tcx.hir().get_parent_item(hir_id).into();
         }
     }
 
@@ -2712,7 +2712,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     let parent_id = hir.get_parent_item(arg_hir_id);
                     let typeck_results: &TypeckResults<'tcx> = match &in_progress_typeck_results {
                         Some(t) if t.hir_owner == parent_id => t,
-                        _ => self.tcx.typeck(parent_id),
+                        _ => self.tcx.typeck(parent_id.def_id),
                     };
                     let expr = expr.peel_blocks();
                     let ty = typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error());
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 6f3a9412dde..f13736a76b2 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -102,7 +102,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
     }
 
     /// Attempts to select obligations using `selcx`.
-    fn select(&mut self, selcx: &mut SelectionContext<'a, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
+    fn select(&mut self, selcx: SelectionContext<'a, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
         let span = debug_span!("select", obligation_forest_size = ?self.predicates.len());
         let _enter = span.enter();
 
@@ -197,8 +197,8 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
         &mut self,
         infcx: &InferCtxt<'_, 'tcx>,
     ) -> Vec<FulfillmentError<'tcx>> {
-        let mut selcx = SelectionContext::new(infcx);
-        self.select(&mut selcx)
+        let selcx = SelectionContext::new(infcx);
+        self.select(selcx)
     }
 
     fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
@@ -210,8 +210,8 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
     }
 }
 
-struct FulfillProcessor<'a, 'b, 'tcx> {
-    selcx: &'a mut SelectionContext<'b, 'tcx>,
+struct FulfillProcessor<'a, 'tcx> {
+    selcx: SelectionContext<'a, 'tcx>,
 }
 
 fn mk_pending(os: Vec<PredicateObligation<'_>>) -> Vec<PendingPredicateObligation<'_>> {
@@ -220,7 +220,7 @@ fn mk_pending(os: Vec<PredicateObligation<'_>>) -> Vec<PendingPredicateObligatio
         .collect()
 }
 
-impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
+impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
     type Obligation = PendingPredicateObligation<'tcx>;
     type Error = FulfillmentErrorCode<'tcx>;
     type OUT = Outcome<Self::Obligation, Self::Error>;
@@ -291,7 +291,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
         if obligation.predicate.has_projections() {
             let mut obligations = Vec::new();
             let predicate = crate::traits::project::try_normalize_with_depth_to(
-                self.selcx,
+                &mut self.selcx,
                 obligation.param_env,
                 obligation.cause.clone(),
                 obligation.recursion_depth + 1,
@@ -608,7 +608,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
     }
 }
 
-impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
+impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
     #[instrument(level = "debug", skip(self, obligation, stalled_on))]
     fn process_trait_obligation(
         &mut self,
@@ -643,7 +643,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
                 // information about the types in the trait.
                 stalled_on.clear();
                 stalled_on.extend(substs_infer_vars(
-                    self.selcx,
+                    &self.selcx,
                     trait_obligation.predicate.map_bound(|pred| pred.trait_ref.substs),
                 ));
 
@@ -695,12 +695,12 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
             }
         }
 
-        match project::poly_project_and_unify_type(self.selcx, &project_obligation) {
+        match project::poly_project_and_unify_type(&mut self.selcx, &project_obligation) {
             ProjectAndUnifyResult::Holds(os) => ProcessResult::Changed(mk_pending(os)),
             ProjectAndUnifyResult::FailedNormalization => {
                 stalled_on.clear();
                 stalled_on.extend(substs_infer_vars(
-                    self.selcx,
+                    &self.selcx,
                     project_obligation.predicate.map_bound(|pred| pred.projection_ty.substs),
                 ));
                 ProcessResult::Unchanged
@@ -718,7 +718,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
 
 /// Returns the set of inference variables contained in `substs`.
 fn substs_infer_vars<'a, 'tcx>(
-    selcx: &mut SelectionContext<'a, 'tcx>,
+    selcx: &SelectionContext<'a, 'tcx>,
     substs: ty::Binder<'tcx, SubstsRef<'tcx>>,
 ) -> impl Iterator<Item = TyOrConstInferVar<'tcx>> {
     selcx
diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
index a4b54018228..3008dfcadde 100644
--- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
@@ -46,7 +46,7 @@ impl<'a, 'cx, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'cx, 'tcx> {
     ///   Note that this may cause outlives obligations to be injected
     ///   into the inference context with this body-id.
     /// - `ty`, the type that we are supposed to assume is WF.
-    #[instrument(level = "debug", skip(self, param_env, body_id))]
+    #[instrument(level = "debug", skip(self, param_env, body_id), ret)]
     fn implied_outlives_bounds(
         &self,
         param_env: ty::ParamEnv<'tcx>,
@@ -71,6 +71,7 @@ impl<'a, 'cx, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'cx, 'tcx> {
         let TypeOpOutput { output, constraints, .. } = result;
 
         if let Some(constraints) = constraints {
+            debug!(?constraints);
             // Instantiation may have produced new inference variables and constraints on those
             // variables. Process these constraints.
             let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(self.tcx);
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 27fbfb6dd21..dd49dcecf77 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -626,7 +626,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // the signature, as evidenced by how we treat it during projection.
         // The safe thing to do here is to liberate it, though, which should
         // have no worse effect than skipping the binder here.
-        let liberated_fn_ty = self.infcx.replace_bound_vars_with_placeholders(obligation.self_ty());
+        let liberated_fn_ty =
+            self.infcx.replace_bound_vars_with_placeholders(obligation.predicate.rebind(self_ty));
         let output_ty = self
             .infcx
             .replace_bound_vars_with_placeholders(liberated_fn_ty.fn_sig(self.tcx()).output());
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 5e32a27cdb1..bac34985237 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -35,7 +35,6 @@ use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::fold::BottomUpFolder;
-use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::relate::TypeRelation;
 use rustc_middle::ty::SubstsRef;
 use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
@@ -914,38 +913,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let unbound_input_types =
             stack.fresh_trait_pred.skip_binder().trait_ref.substs.types().any(|ty| ty.is_fresh());
 
-        if stack.obligation.polarity() != ty::ImplPolarity::Negative {
-            // This check was an imperfect workaround for a bug in the old
-            // intercrate mode; it should be removed when that goes away.
-            if unbound_input_types && self.intercrate {
-                debug!("evaluate_stack --> unbound argument, intercrate -->  ambiguous",);
-                // Heuristics: show the diagnostics when there are no candidates in crate.
-                if self.intercrate_ambiguity_causes.is_some() {
-                    debug!("evaluate_stack: intercrate_ambiguity_causes is some");
-                    if let Ok(candidate_set) = self.assemble_candidates(stack) {
-                        if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
-                            let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
-                            let self_ty = trait_ref.self_ty();
-                            let cause = with_no_trimmed_paths!({
-                                IntercrateAmbiguityCause::DownstreamCrate {
-                                    trait_desc: trait_ref.print_only_trait_path().to_string(),
-                                    self_desc: if self_ty.has_concrete_skeleton() {
-                                        Some(self_ty.to_string())
-                                    } else {
-                                        None
-                                    },
-                                }
-                            });
-
-                            debug!(?cause, "evaluate_stack: pushing cause");
-                            self.intercrate_ambiguity_causes.as_mut().unwrap().insert(cause);
-                        }
-                    }
-                }
-                return Ok(EvaluatedToAmbig);
-            }
-        }
-
         if unbound_input_types
             && stack.iter().skip(1).any(|prev| {
                 stack.obligation.param_env == prev.obligation.param_env
@@ -1737,12 +1704,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
             (&ImplCandidate(other_def), &ImplCandidate(victim_def)) => {
                 // See if we can toss out `victim` based on specialization.
-                // This requires us to know *for sure* that the `other` impl applies
-                // i.e., `EvaluatedToOk`.
+                // While this requires us to know *for sure* that the `other` impl applies
+                // we still use modulo regions here.
                 //
-                // FIXME(@lcnr): Using `modulo_regions` here seems kind of scary
-                // to me but is required for `std` to compile, so I didn't change it
-                // for now.
+                // This is fine as specialization currently assumes that specializing
+                // impls have to be always applicable, meaning that the only allowed
+                // region constraints may be constraints also present on the default impl.
                 let tcx = self.tcx();
                 if other.evaluation.must_apply_modulo_regions() {
                     if tcx.specializes((other_def, victim_def)) {
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index e3e78f70b15..32aca4a8a3f 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -49,7 +49,8 @@ fn compute_implied_outlives_bounds<'tcx>(
     let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default();
     let mut wf_args = vec![ty.into()];
 
-    let mut implied_bounds = vec![];
+    let mut outlives_bounds: Vec<ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>> =
+        vec![];
 
     let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(tcx);
 
@@ -65,30 +66,17 @@ fn compute_implied_outlives_bounds<'tcx>(
         // than the ultimate set. (Note: normally there won't be
         // unresolved inference variables here anyway, but there might be
         // during typeck under some circumstances.)
+        //
+        // FIXME(@lcnr): It's not really "always fine", having fewer implied
+        // bounds can be backward incompatible, e.g. #101951 was caused by
+        // us not dealing with inference vars in `TypeOutlives` predicates.
         let obligations = wf::obligations(infcx, param_env, hir::CRATE_HIR_ID, 0, arg, DUMMY_SP)
             .unwrap_or_default();
 
-        // N.B., all of these predicates *ought* to be easily proven
-        // true. In fact, their correctness is (mostly) implied by
-        // other parts of the program. However, in #42552, we had
-        // an annoying scenario where:
-        //
-        // - Some `T::Foo` gets normalized, resulting in a
-        //   variable `_1` and a `T: Trait<Foo=_1>` constraint
-        //   (not sure why it couldn't immediately get
-        //   solved). This result of `_1` got cached.
-        // - These obligations were dropped on the floor here,
-        //   rather than being registered.
-        // - Then later we would get a request to normalize
-        //   `T::Foo` which would result in `_1` being used from
-        //   the cache, but hence without the `T: Trait<Foo=_1>`
-        //   constraint. As a result, `_1` never gets resolved,
-        //   and we get an ICE (in dropck).
-        //
-        // Therefore, we register any predicates involving
-        // inference variables. We restrict ourselves to those
-        // involving inference variables both for efficiency and
-        // to avoids duplicate errors that otherwise show up.
+        // While these predicates should all be implied by other parts of
+        // the program, they are still relevant as they may constrain
+        // inference variables, which is necessary to add the correct
+        // implied bounds in some cases, mostly when dealing with projections.
         fulfill_cx.register_predicate_obligations(
             infcx,
             obligations.iter().filter(|o| o.predicate.has_infer_types_or_consts()).cloned(),
@@ -96,10 +84,10 @@ fn compute_implied_outlives_bounds<'tcx>(
 
         // From the full set of obligations, just filter down to the
         // region relationships.
-        implied_bounds.extend(obligations.into_iter().flat_map(|obligation| {
+        outlives_bounds.extend(obligations.into_iter().filter_map(|obligation| {
             assert!(!obligation.has_escaping_bound_vars());
             match obligation.predicate.kind().no_bound_vars() {
-                None => vec![],
+                None => None,
                 Some(pred) => match pred {
                     ty::PredicateKind::Trait(..)
                     | ty::PredicateKind::Subtype(..)
@@ -109,21 +97,18 @@ fn compute_implied_outlives_bounds<'tcx>(
                     | ty::PredicateKind::ObjectSafe(..)
                     | ty::PredicateKind::ConstEvaluatable(..)
                     | ty::PredicateKind::ConstEquate(..)
-                    | ty::PredicateKind::TypeWellFormedFromEnv(..) => vec![],
+                    | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
                     ty::PredicateKind::WellFormed(arg) => {
                         wf_args.push(arg);
-                        vec![]
+                        None
                     }
 
                     ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => {
-                        vec![OutlivesBound::RegionSubRegion(r_b, r_a)]
+                        Some(ty::OutlivesPredicate(r_a.into(), r_b))
                     }
 
                     ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, r_b)) => {
-                        let ty_a = infcx.resolve_vars_if_possible(ty_a);
-                        let mut components = smallvec![];
-                        push_outlives_components(tcx, ty_a, &mut components);
-                        implied_bounds_from_components(r_b, components)
+                        Some(ty::OutlivesPredicate(ty_a.into(), r_b))
                     }
                 },
             }
@@ -133,9 +118,27 @@ fn compute_implied_outlives_bounds<'tcx>(
     // Ensure that those obligations that we had to solve
     // get solved *here*.
     match fulfill_cx.select_all_or_error(infcx).as_slice() {
-        [] => Ok(implied_bounds),
-        _ => Err(NoSolution),
+        [] => (),
+        _ => return Err(NoSolution),
     }
+
+    // We lazily compute the outlives components as
+    // `select_all_or_error` constrains inference variables.
+    let implied_bounds = outlives_bounds
+        .into_iter()
+        .flat_map(|ty::OutlivesPredicate(a, r_b)| match a.unpack() {
+            ty::GenericArgKind::Lifetime(r_a) => vec![OutlivesBound::RegionSubRegion(r_b, r_a)],
+            ty::GenericArgKind::Type(ty_a) => {
+                let ty_a = infcx.resolve_vars_if_possible(ty_a);
+                let mut components = smallvec![];
+                push_outlives_components(tcx, ty_a, &mut components);
+                implied_bounds_from_components(r_b, components)
+            }
+            ty::GenericArgKind::Const(_) => unreachable!(),
+        })
+        .collect();
+
+    Ok(implied_bounds)
 }
 
 /// When we have an implied bound that `T: 'a`, we can further break
@@ -153,6 +156,9 @@ fn implied_bounds_from_components<'tcx>(
                 Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)),
                 Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)),
                 Component::Projection(p) => Some(OutlivesBound::RegionSubProjection(sub_region, p)),
+                Component::Opaque(def_id, substs) => {
+                    Some(OutlivesBound::RegionSubOpaque(sub_region, def_id, substs))
+                }
                 Component::EscapingProjection(_) =>
                 // If the projection has escaping regions, don't
                 // try to infer any implied bounds even for its
diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs
index 2d39e973ed9..0da28737f69 100644
--- a/compiler/rustc_traits/src/lib.rs
+++ b/compiler/rustc_traits/src/lib.rs
@@ -3,7 +3,6 @@
 
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![recursion_limit = "256"]
 
 #[macro_use]
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index 515a73ead77..3e2553c425e 100644
--- a/compiler/rustc_ty_utils/src/assoc.rs
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -42,7 +42,7 @@ fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> FxHashMap<DefId
 fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
     let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
     let parent_def_id = tcx.hir().get_parent_item(id);
-    let parent_item = tcx.hir().expect_item(parent_def_id);
+    let parent_item = tcx.hir().expect_item(parent_def_id.def_id);
     match parent_item.kind {
         hir::ItemKind::Impl(ref impl_) => {
             if let Some(impl_item_ref) =
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 05738b6c48a..fa1dc90e4a2 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -187,7 +187,7 @@ fn resolve_associated_item<'tcx>(
             // we know the error would've been caught (e.g. in an upstream crate).
             //
             // A better approach might be to just introduce a query (returning
-            // `Result<(), ErrorGuaranteed>`) for the check that `rustc_typeck`
+            // `Result<(), ErrorGuaranteed>`) for the check that `rustc_hir_analysis`
             // performs (i.e. that the definition's type in the `impl` matches
             // the declaration in the `trait`), so that we can cheaply check
             // here if it failed, instead of approximating it.
diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs
index 8524e57cb58..10c18789f74 100644
--- a/compiler/rustc_ty_utils/src/lib.rs
+++ b/compiler/rustc_ty_utils/src/lib.rs
@@ -6,7 +6,6 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(control_flow_enum)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(never_type)]
 #![feature(box_patterns)]
 #![recursion_limit = "256"]
diff --git a/config.toml.example b/config.toml.example
index a967d881b02..ff08dfc553d 100644
--- a/config.toml.example
+++ b/config.toml.example
@@ -291,6 +291,10 @@ changelog-seen = 2
 # on this runtime, such as `-C profile-generate` or `-C instrument-coverage`).
 #profiler = false
 
+# Use the optimized LLVM C intrinsics for `compiler_builtins`, rather than Rust intrinsics.
+# Requires the LLVM submodule to be managed by bootstrap (i.e. not external).
+#optimized-compiler-builtins = false
+
 # Indicates whether the native libraries linked into Cargo will be statically
 # linked or not.
 #cargo-native-static = false
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 0aff1323f97..f651cb02176 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -151,7 +151,6 @@ use core::async_iter::AsyncIterator;
 use core::borrow;
 use core::cmp::Ordering;
 use core::convert::{From, TryFrom};
-#[cfg(not(bootstrap))]
 use core::error::Error;
 use core::fmt;
 use core::future::Future;
@@ -176,7 +175,6 @@ use crate::borrow::Cow;
 use crate::raw_vec::RawVec;
 #[cfg(not(no_global_oom_handling))]
 use crate::str::from_boxed_utf8_unchecked;
-#[cfg(not(bootstrap))]
 #[cfg(not(no_global_oom_handling))]
 use crate::string::String;
 #[cfg(not(no_global_oom_handling))]
@@ -2090,7 +2088,6 @@ impl<S: ?Sized + AsyncIterator + Unpin> AsyncIterator for Box<S> {
     }
 }
 
-#[cfg(not(bootstrap))]
 impl dyn Error {
     #[inline]
     #[stable(feature = "error_downcast", since = "1.3.0")]
@@ -2108,7 +2105,6 @@ impl dyn Error {
     }
 }
 
-#[cfg(not(bootstrap))]
 impl dyn Error + Send {
     #[inline]
     #[stable(feature = "error_downcast", since = "1.3.0")]
@@ -2123,7 +2119,6 @@ impl dyn Error + Send {
     }
 }
 
-#[cfg(not(bootstrap))]
 impl dyn Error + Send + Sync {
     #[inline]
     #[stable(feature = "error_downcast", since = "1.3.0")]
@@ -2138,7 +2133,6 @@ impl dyn Error + Send + Sync {
     }
 }
 
-#[cfg(not(bootstrap))]
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a> {
@@ -2172,7 +2166,6 @@ impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a> {
     }
 }
 
-#[cfg(not(bootstrap))]
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync + 'a> {
@@ -2212,7 +2205,6 @@ impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync +
     }
 }
 
-#[cfg(not(bootstrap))]
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl From<String> for Box<dyn Error + Send + Sync> {
@@ -2257,7 +2249,6 @@ impl From<String> for Box<dyn Error + Send + Sync> {
     }
 }
 
-#[cfg(not(bootstrap))]
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "string_box_error", since = "1.6.0")]
 impl From<String> for Box<dyn Error> {
@@ -2280,7 +2271,6 @@ impl From<String> for Box<dyn Error> {
     }
 }
 
-#[cfg(not(bootstrap))]
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> From<&str> for Box<dyn Error + Send + Sync + 'a> {
@@ -2305,7 +2295,6 @@ impl<'a> From<&str> for Box<dyn Error + Send + Sync + 'a> {
     }
 }
 
-#[cfg(not(bootstrap))]
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "string_box_error", since = "1.6.0")]
 impl From<&str> for Box<dyn Error> {
@@ -2328,7 +2317,6 @@ impl From<&str> for Box<dyn Error> {
     }
 }
 
-#[cfg(not(bootstrap))]
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "cow_box_error", since = "1.22.0")]
 impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + Send + Sync + 'a> {
@@ -2351,7 +2339,6 @@ impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + Send + Sync + 'a> {
     }
 }
 
-#[cfg(not(bootstrap))]
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "cow_box_error", since = "1.22.0")]
 impl<'a> From<Cow<'a, str>> for Box<dyn Error> {
@@ -2373,7 +2360,6 @@ impl<'a> From<Cow<'a, str>> for Box<dyn Error> {
     }
 }
 
-#[cfg(not(bootstrap))]
 #[stable(feature = "box_error", since = "1.8.0")]
 impl<T: core::error::Error> core::error::Error for Box<T> {
     #[allow(deprecated, deprecated_in_future)]
diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs
index 0a20c74b00f..c477c44906c 100644
--- a/library/alloc/src/boxed/thin.rs
+++ b/library/alloc/src/boxed/thin.rs
@@ -2,7 +2,6 @@
 // https://github.com/matthieu-m/rfc2580/blob/b58d1d3cba0d4b5e859d3617ea2d0943aaa31329/examples/thin.rs
 // by matthieu-m
 use crate::alloc::{self, Layout, LayoutError};
-#[cfg(not(bootstrap))]
 use core::error::Error;
 use core::fmt::{self, Debug, Display, Formatter};
 use core::marker::PhantomData;
@@ -274,7 +273,6 @@ impl<H> WithHeader<H> {
     }
 }
 
-#[cfg(not(bootstrap))]
 #[unstable(feature = "thin_box", issue = "92791")]
 impl<T: ?Sized + Error> Error for ThinBox<T> {
     fn source(&self) -> Option<&(dyn Error + 'static)> {
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index cacbd54b6c2..3018d1c9125 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -580,7 +580,7 @@ impl<K, V> BTreeMap<K, V> {
     /// map.insert(1, "a");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_btree_new", issue = "71835")]
+    #[rustc_const_stable(feature = "const_btree_new", since = "CURRENT_RUSTC_VERSION")]
     #[must_use]
     pub const fn new() -> BTreeMap<K, V> {
         BTreeMap { root: None, length: 0, alloc: ManuallyDrop::new(Global), _marker: PhantomData }
@@ -2392,7 +2392,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_btree_new", issue = "71835")]
+    #[rustc_const_unstable(feature = "const_btree_len", issue = "71835")]
     pub const fn len(&self) -> usize {
         self.length
     }
@@ -2413,7 +2413,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_btree_new", issue = "71835")]
+    #[rustc_const_unstable(feature = "const_btree_len", issue = "71835")]
     pub const fn is_empty(&self) -> bool {
         self.len() == 0
     }
diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs
index cd7cdc19207..370b58864af 100644
--- a/library/alloc/src/collections/btree/map/entry.rs
+++ b/library/alloc/src/collections/btree/map/entry.rs
@@ -133,7 +133,6 @@ impl<'a, K: Debug + Ord, V: Debug, A: Allocator + Clone> fmt::Display
     }
 }
 
-#[cfg(not(bootstrap))]
 #[unstable(feature = "map_try_insert", issue = "82766")]
 impl<'a, K: core::fmt::Debug + Ord, V: core::fmt::Debug> core::error::Error
     for crate::collections::btree_map::OccupiedError<'a, K, V>
diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs
index 2cfc0807409..3caaf521240 100644
--- a/library/alloc/src/collections/btree/set.rs
+++ b/library/alloc/src/collections/btree/set.rs
@@ -343,7 +343,7 @@ impl<T> BTreeSet<T> {
     /// let mut set: BTreeSet<i32> = BTreeSet::new();
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_btree_new", issue = "71835")]
+    #[rustc_const_stable(feature = "const_btree_new", since = "CURRENT_RUSTC_VERSION")]
     #[must_use]
     pub const fn new() -> BTreeSet<T> {
         BTreeSet { map: BTreeMap::new() }
@@ -1174,7 +1174,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_btree_new", issue = "71835")]
+    #[rustc_const_unstable(feature = "const_btree_len", issue = "71835")]
     pub const fn len(&self) -> usize {
         self.map.len()
     }
@@ -1193,7 +1193,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_btree_new", issue = "71835")]
+    #[rustc_const_unstable(feature = "const_btree_len", issue = "71835")]
     pub const fn is_empty(&self) -> bool {
         self.len() == 0
     }
diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs
index 21d0def0866..161a375736c 100644
--- a/library/alloc/src/collections/mod.rs
+++ b/library/alloc/src/collections/mod.rs
@@ -153,6 +153,5 @@ trait SpecExtend<I: IntoIterator> {
     fn spec_extend(&mut self, iter: I);
 }
 
-#[cfg(not(bootstrap))]
 #[stable(feature = "try_reserve", since = "1.57.0")]
 impl core::error::Error for TryReserveError {}
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index e3f4deb0875..2a57dad89a7 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -12,11 +12,17 @@ use core::fmt;
 use core::hash::{Hash, Hasher};
 use core::iter::{repeat_with, FromIterator};
 use core::marker::PhantomData;
-use core::mem::{self, ManuallyDrop, MaybeUninit};
+use core::mem::{ManuallyDrop, MaybeUninit, SizedTypeProperties};
 use core::ops::{Index, IndexMut, Range, RangeBounds};
 use core::ptr::{self, NonNull};
 use core::slice;
 
+// This is used in a bunch of intra-doc links.
+// FIXME: For some reason, `#[cfg(doc)]` wasn't sufficient, resulting in
+// failures in linkchecker even though rustdoc built the docs just fine.
+#[allow(unused_imports)]
+use core::mem;
+
 use crate::alloc::{Allocator, Global};
 use crate::collections::TryReserveError;
 use crate::collections::TryReserveErrorKind;
@@ -177,7 +183,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// Marginally more convenient
     #[inline]
     fn cap(&self) -> usize {
-        if mem::size_of::<T>() == 0 {
+        if T::IS_ZST {
             // For zero sized types, we are always at maximum capacity
             MAXIMUM_ZST_CAPACITY
         } else {
@@ -3038,7 +3044,7 @@ impl<T, A: Allocator> From<Vec<T, A>> for VecDeque<T, A> {
     /// `Vec<T>` came from `From<VecDeque<T>>` and hasn't been reallocated.
     fn from(mut other: Vec<T, A>) -> Self {
         let len = other.len();
-        if mem::size_of::<T>() == 0 {
+        if T::IS_ZST {
             // There's no actual allocation for ZSTs to worry about capacity,
             // but `VecDeque` can't handle as much length as `Vec`.
             assert!(len < MAXIMUM_ZST_CAPACITY, "capacity overflow");
@@ -3124,7 +3130,7 @@ impl<T, const N: usize> From<[T; N]> for VecDeque<T> {
     fn from(arr: [T; N]) -> Self {
         let mut deq = VecDeque::with_capacity(N);
         let arr = ManuallyDrop::new(arr);
-        if mem::size_of::<T>() != 0 {
+        if !<T>::IS_ZST {
             // SAFETY: VecDeque::with_capacity ensures that there is enough capacity.
             unsafe {
                 ptr::copy_nonoverlapping(arr.as_ptr(), deq.ptr(), N);
diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs
index aede6d54c6c..11bd4c4dc1b 100644
--- a/library/alloc/src/ffi/c_str.rs
+++ b/library/alloc/src/ffi/c_str.rs
@@ -1122,7 +1122,6 @@ impl CStr {
     }
 }
 
-#[cfg(not(bootstrap))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl core::error::Error for NulError {
     #[allow(deprecated)]
@@ -1131,11 +1130,9 @@ impl core::error::Error for NulError {
     }
 }
 
-#[cfg(not(bootstrap))]
 #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
 impl core::error::Error for FromVecWithNulError {}
 
-#[cfg(not(bootstrap))]
 #[stable(feature = "cstring_into", since = "1.7.0")]
 impl core::error::Error for IntoStringError {
     #[allow(deprecated)]
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 6b3b1c22222..7fde8f670a2 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -99,7 +99,7 @@
 #![feature(coerce_unsized)]
 #![cfg_attr(not(no_global_oom_handling), feature(const_alloc_error))]
 #![feature(const_box)]
-#![cfg_attr(not(no_global_oom_handling), feature(const_btree_new))]
+#![cfg_attr(not(no_global_oom_handling), feature(const_btree_len))]
 #![feature(const_cow_is_borrowed)]
 #![feature(const_convert)]
 #![feature(const_size_of_val)]
@@ -114,8 +114,8 @@
 #![feature(const_waker)]
 #![feature(cstr_from_bytes_until_nul)]
 #![feature(dispatch_from_dyn)]
-#![cfg_attr(not(bootstrap), feature(error_generic_member_access))]
-#![cfg_attr(not(bootstrap), feature(error_in_core))]
+#![feature(error_generic_member_access)]
+#![feature(error_in_core)]
 #![feature(exact_size_is_empty)]
 #![feature(extend_one)]
 #![feature(fmt_internals)]
@@ -132,13 +132,14 @@
 #![feature(nonnull_slice_from_raw_parts)]
 #![feature(pattern)]
 #![feature(pointer_byte_offsets)]
-#![cfg_attr(not(bootstrap), feature(provide_any))]
+#![feature(provide_any)]
 #![feature(ptr_internals)]
 #![feature(ptr_metadata)]
 #![feature(ptr_sub_ptr)]
 #![feature(receiver_trait)]
 #![feature(saturating_int_impl)]
 #![feature(set_ptr_value)]
+#![feature(sized_type_properties)]
 #![feature(slice_from_ptr_range)]
 #![feature(slice_group_by)]
 #![feature(slice_ptr_get)]
@@ -172,7 +173,6 @@
 #![cfg_attr(not(test), feature(generator_trait))]
 #![feature(hashmap_internals)]
 #![feature(lang_items)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(min_specialization)]
 #![feature(negative_impls)]
 #![feature(never_type)]
diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs
index b0f4529abdf..5a10121bbbe 100644
--- a/library/alloc/src/raw_vec.rs
+++ b/library/alloc/src/raw_vec.rs
@@ -3,7 +3,7 @@
 use core::alloc::LayoutError;
 use core::cmp;
 use core::intrinsics;
-use core::mem::{self, ManuallyDrop, MaybeUninit};
+use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties};
 use core::ops::Drop;
 use core::ptr::{self, NonNull, Unique};
 use core::slice;
@@ -168,7 +168,7 @@ impl<T, A: Allocator> RawVec<T, A> {
     #[cfg(not(no_global_oom_handling))]
     fn allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Self {
         // Don't allocate here because `Drop` will not deallocate when `capacity` is 0.
-        if mem::size_of::<T>() == 0 || capacity == 0 {
+        if T::IS_ZST || capacity == 0 {
             Self::new_in(alloc)
         } else {
             // We avoid `unwrap_or_else` here because it bloats the amount of
@@ -229,7 +229,7 @@ impl<T, A: Allocator> RawVec<T, A> {
     /// This will always be `usize::MAX` if `T` is zero-sized.
     #[inline(always)]
     pub fn capacity(&self) -> usize {
-        if mem::size_of::<T>() == 0 { usize::MAX } else { self.cap }
+        if T::IS_ZST { usize::MAX } else { self.cap }
     }
 
     /// Returns a shared reference to the allocator backing this `RawVec`.
@@ -238,7 +238,7 @@ impl<T, A: Allocator> RawVec<T, A> {
     }
 
     fn current_memory(&self) -> Option<(NonNull<u8>, Layout)> {
-        if mem::size_of::<T>() == 0 || self.cap == 0 {
+        if T::IS_ZST || self.cap == 0 {
             None
         } else {
             // We have an allocated chunk of memory, so we can bypass runtime
@@ -380,7 +380,7 @@ impl<T, A: Allocator> RawVec<T, A> {
         // This is ensured by the calling contexts.
         debug_assert!(additional > 0);
 
-        if mem::size_of::<T>() == 0 {
+        if T::IS_ZST {
             // Since we return a capacity of `usize::MAX` when `elem_size` is
             // 0, getting to here necessarily means the `RawVec` is overfull.
             return Err(CapacityOverflow.into());
@@ -406,7 +406,7 @@ impl<T, A: Allocator> RawVec<T, A> {
     // `grow_amortized`, but this method is usually instantiated less often so
     // it's less critical.
     fn grow_exact(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> {
-        if mem::size_of::<T>() == 0 {
+        if T::IS_ZST {
             // Since we return a capacity of `usize::MAX` when the type size is
             // 0, getting to here necessarily means the `RawVec` is overfull.
             return Err(CapacityOverflow.into());
diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs
index 8c9783fe194..a5e7bf2a1a9 100644
--- a/library/alloc/src/slice.rs
+++ b/library/alloc/src/slice.rs
@@ -16,9 +16,7 @@ use core::borrow::{Borrow, BorrowMut};
 #[cfg(not(no_global_oom_handling))]
 use core::cmp::Ordering::{self, Less};
 #[cfg(not(no_global_oom_handling))]
-use core::mem;
-#[cfg(not(no_global_oom_handling))]
-use core::mem::size_of;
+use core::mem::{self, SizedTypeProperties};
 #[cfg(not(no_global_oom_handling))]
 use core::ptr;
 
@@ -1018,7 +1016,7 @@ where
     const MIN_RUN: usize = 10;
 
     // Sorting has no meaningful behavior on zero-sized types.
-    if size_of::<T>() == 0 {
+    if T::IS_ZST {
         return;
     }
 
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index f2448396ce8..983376a282b 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -44,7 +44,6 @@
 
 #[cfg(not(no_global_oom_handling))]
 use core::char::{decode_utf16, REPLACEMENT_CHARACTER};
-#[cfg(not(bootstrap))]
 use core::error::Error;
 use core::fmt;
 use core::hash;
@@ -1941,7 +1940,6 @@ impl fmt::Display for FromUtf16Error {
     }
 }
 
-#[cfg(not(bootstrap))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Error for FromUtf8Error {
     #[allow(deprecated)]
@@ -1950,7 +1948,6 @@ impl Error for FromUtf8Error {
     }
 }
 
-#[cfg(not(bootstrap))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Error for FromUtf16Error {
     #[allow(deprecated)]
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 4377edeee87..a5322953d49 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -2764,7 +2764,6 @@ fn data_offset_align(align: usize) -> usize {
     layout.size() + layout.padding_needed_for(align)
 }
 
-#[cfg(not(bootstrap))]
 #[stable(feature = "arc_error", since = "1.52.0")]
 impl<T: core::error::Error + ?Sized> core::error::Error for Arc<T> {
     #[allow(deprecated, deprecated_in_future)]
diff --git a/library/alloc/src/vec/drain.rs b/library/alloc/src/vec/drain.rs
index 5b73906a1c9..541f99bcfab 100644
--- a/library/alloc/src/vec/drain.rs
+++ b/library/alloc/src/vec/drain.rs
@@ -1,7 +1,7 @@
 use crate::alloc::{Allocator, Global};
 use core::fmt;
 use core::iter::{FusedIterator, TrustedLen};
-use core::mem::{self, ManuallyDrop};
+use core::mem::{self, ManuallyDrop, SizedTypeProperties};
 use core::ptr::{self, NonNull};
 use core::slice::{self};
 
@@ -202,7 +202,7 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
 
         let mut vec = self.vec;
 
-        if mem::size_of::<T>() == 0 {
+        if T::IS_ZST {
             // ZSTs have no identity, so we don't need to move them around, we only need to drop the correct amount.
             // this can be achieved by manipulating the Vec length instead of moving values out from `iter`.
             unsafe {
diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs
index b211421b202..a3f8fe40fd5 100644
--- a/library/alloc/src/vec/in_place_collect.rs
+++ b/library/alloc/src/vec/in_place_collect.rs
@@ -135,7 +135,7 @@
 //! vec.truncate(write_idx);
 //! ```
 use core::iter::{InPlaceIterable, SourceIter, TrustedRandomAccessNoCoerce};
-use core::mem::{self, ManuallyDrop};
+use core::mem::{self, ManuallyDrop, SizedTypeProperties};
 use core::ptr::{self};
 
 use super::{InPlaceDrop, SpecFromIter, SpecFromIterNested, Vec};
@@ -154,7 +154,7 @@ where
     default fn from_iter(mut iterator: I) -> Self {
         // See "Layout constraints" section in the module documentation. We rely on const
         // optimization here since these conditions currently cannot be expressed as trait bounds
-        if mem::size_of::<T>() == 0
+        if T::IS_ZST
             || mem::size_of::<T>()
                 != mem::size_of::<<<I as SourceIter>::Source as AsVecIntoIter>::Item>()
             || mem::align_of::<T>()
diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs
index b4157fd5895..d74e77637bd 100644
--- a/library/alloc/src/vec/into_iter.rs
+++ b/library/alloc/src/vec/into_iter.rs
@@ -8,7 +8,7 @@ use core::iter::{
     FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccessNoCoerce,
 };
 use core::marker::PhantomData;
-use core::mem::{self, ManuallyDrop, MaybeUninit};
+use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties};
 #[cfg(not(no_global_oom_handling))]
 use core::ops::Deref;
 use core::ptr::{self, NonNull};
@@ -149,7 +149,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
     fn next(&mut self) -> Option<T> {
         if self.ptr == self.end {
             None
-        } else if mem::size_of::<T>() == 0 {
+        } else if T::IS_ZST {
             // purposefully don't use 'ptr.offset' because for
             // vectors with 0-size elements this would return the
             // same pointer.
@@ -167,7 +167,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
 
     #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
-        let exact = if mem::size_of::<T>() == 0 {
+        let exact = if T::IS_ZST {
             self.end.addr().wrapping_sub(self.ptr.addr())
         } else {
             unsafe { self.end.sub_ptr(self.ptr) }
@@ -179,7 +179,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
     fn advance_by(&mut self, n: usize) -> Result<(), usize> {
         let step_size = self.len().min(n);
         let to_drop = ptr::slice_from_raw_parts_mut(self.ptr as *mut T, step_size);
-        if mem::size_of::<T>() == 0 {
+        if T::IS_ZST {
             // SAFETY: due to unchecked casts of unsigned amounts to signed offsets the wraparound
             // effectively results in unsigned pointers representing positions 0..usize::MAX,
             // which is valid for ZSTs.
@@ -209,7 +209,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
 
         let len = self.len();
 
-        if mem::size_of::<T>() == 0 {
+        if T::IS_ZST {
             if len < N {
                 self.forget_remaining_elements();
                 // Safety: ZSTs can be conjured ex nihilo, only the amount has to be correct
@@ -253,7 +253,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
         // that `T: Copy` so reading elements from the buffer doesn't invalidate
         // them for `Drop`.
         unsafe {
-            if mem::size_of::<T>() == 0 { mem::zeroed() } else { ptr::read(self.ptr.add(i)) }
+            if T::IS_ZST { mem::zeroed() } else { ptr::read(self.ptr.add(i)) }
         }
     }
 }
@@ -264,7 +264,7 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
     fn next_back(&mut self) -> Option<T> {
         if self.end == self.ptr {
             None
-        } else if mem::size_of::<T>() == 0 {
+        } else if T::IS_ZST {
             // See above for why 'ptr.offset' isn't used
             self.end = self.end.wrapping_byte_sub(1);
 
@@ -280,7 +280,7 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
     #[inline]
     fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
         let step_size = self.len().min(n);
-        if mem::size_of::<T>() == 0 {
+        if T::IS_ZST {
             // SAFETY: same as for advance_by()
             self.end = self.end.wrapping_byte_sub(step_size);
         } else {
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 60b36af5e67..d6d986905e6 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -64,7 +64,7 @@ use core::iter;
 #[cfg(not(no_global_oom_handling))]
 use core::iter::FromIterator;
 use core::marker::PhantomData;
-use core::mem::{self, ManuallyDrop, MaybeUninit};
+use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties};
 use core::ops::{self, Index, IndexMut, Range, RangeBounds};
 use core::ptr::{self, NonNull};
 use core::slice::{self, SliceIndex};
@@ -2347,7 +2347,7 @@ impl<T, A: Allocator, const N: usize> Vec<[T; N], A> {
     #[unstable(feature = "slice_flatten", issue = "95629")]
     pub fn into_flattened(self) -> Vec<T, A> {
         let (ptr, len, cap, alloc) = self.into_raw_parts_with_alloc();
-        let (new_len, new_cap) = if mem::size_of::<T>() == 0 {
+        let (new_len, new_cap) = if T::IS_ZST {
             (len.checked_mul(N).expect("vec len overflow"), usize::MAX)
         } else {
             // SAFETY:
@@ -2677,7 +2677,7 @@ impl<T, A: Allocator> IntoIterator for Vec<T, A> {
             let mut me = ManuallyDrop::new(self);
             let alloc = ManuallyDrop::new(ptr::read(me.allocator()));
             let begin = me.as_mut_ptr();
-            let end = if mem::size_of::<T>() == 0 {
+            let end = if T::IS_ZST {
                 begin.wrapping_byte_add(me.len())
             } else {
                 begin.add(me.len()) as *const T
diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs
index 490c0d8f76c..f30ebd77e24 100644
--- a/library/alloc/tests/lib.rs
+++ b/library/alloc/tests/lib.rs
@@ -32,7 +32,7 @@
 #![feature(slice_group_by)]
 #![feature(slice_partition_dedup)]
 #![feature(string_remove_matches)]
-#![feature(const_btree_new)]
+#![feature(const_btree_len)]
 #![feature(const_default_impls)]
 #![feature(const_trait_impl)]
 #![feature(const_str_from_utf8)]
@@ -41,7 +41,6 @@
 #![feature(pointer_is_aligned)]
 #![feature(slice_flatten)]
 #![feature(thin_box)]
-#![feature(bench_black_box)]
 #![feature(strict_provenance)]
 #![feature(once_cell)]
 #![feature(drain_keep_rest)]
diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs
index f03502429ab..5bb44b40859 100644
--- a/library/core/src/alloc/layout.rs
+++ b/library/core/src/alloc/layout.rs
@@ -5,7 +5,6 @@
 // Your performance intuition is useless. Run perf.
 
 use crate::cmp;
-#[cfg(not(bootstrap))]
 use crate::error::Error;
 use crate::fmt;
 use crate::mem::{self, ValidAlign};
@@ -463,7 +462,6 @@ pub type LayoutErr = LayoutError;
 #[derive(Clone, PartialEq, Eq, Debug)]
 pub struct LayoutError;
 
-#[cfg(not(bootstrap))]
 #[stable(feature = "alloc_layout", since = "1.28.0")]
 impl Error for LayoutError {}
 
diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs
index 61553157478..a4bf6a853a6 100644
--- a/library/core/src/alloc/mod.rs
+++ b/library/core/src/alloc/mod.rs
@@ -21,7 +21,6 @@ pub use self::layout::LayoutErr;
 #[stable(feature = "alloc_layout_error", since = "1.50.0")]
 pub use self::layout::LayoutError;
 
-#[cfg(not(bootstrap))]
 use crate::error::Error;
 use crate::fmt;
 use crate::ptr::{self, NonNull};
@@ -34,7 +33,6 @@ use crate::ptr::{self, NonNull};
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub struct AllocError;
 
-#[cfg(not(bootstrap))]
 #[unstable(
     feature = "allocator_api",
     reason = "the precise API and guarantees it provides may be tweaked.",
diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs
index 165b9d24d93..b82bbf2267a 100644
--- a/library/core/src/array/mod.rs
+++ b/library/core/src/array/mod.rs
@@ -7,7 +7,6 @@
 use crate::borrow::{Borrow, BorrowMut};
 use crate::cmp::Ordering;
 use crate::convert::{Infallible, TryFrom};
-#[cfg(not(bootstrap))]
 use crate::error::Error;
 use crate::fmt;
 use crate::hash::{self, Hash};
@@ -121,7 +120,6 @@ impl fmt::Display for TryFromSliceError {
     }
 }
 
-#[cfg(not(bootstrap))]
 #[stable(feature = "try_from", since = "1.34.0")]
 impl Error for TryFromSliceError {
     #[allow(deprecated)]
@@ -434,7 +432,8 @@ impl<T: Copy> SpecArrayClone for T {
 macro_rules! array_impl_default {
     {$n:expr, $t:ident $($ts:ident)*} => {
         #[stable(since = "1.4.0", feature = "array_default")]
-        impl<T> Default for [T; $n] where T: Default {
+        #[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
+        impl<T> const Default for [T; $n] where T: ~const Default {
             fn default() -> [T; $n] {
                 [$t::default(), $($ts::default()),*]
             }
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index 1abbb39497a..288cab1ef39 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -614,6 +614,7 @@ impl<T, const N: usize> Cell<[T; N]> {
 /// A mutable memory location with dynamically checked borrow rules
 ///
 /// See the [module-level documentation](self) for more.
+#[cfg_attr(not(test), rustc_diagnostic_item = "RefCell")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct RefCell<T: ?Sized> {
     borrow: Cell<BorrowFlag>,
diff --git a/library/core/src/char/decode.rs b/library/core/src/char/decode.rs
index dc8ea66cc6d..11f1c30f6d5 100644
--- a/library/core/src/char/decode.rs
+++ b/library/core/src/char/decode.rs
@@ -1,6 +1,5 @@
 //! UTF-8 and UTF-16 decoding iterators
 
-#[cfg(not(bootstrap))]
 use crate::error::Error;
 use crate::fmt;
 
@@ -124,7 +123,6 @@ impl fmt::Display for DecodeUtf16Error {
     }
 }
 
-#[cfg(not(bootstrap))]
 #[stable(feature = "decode_utf16", since = "1.9.0")]
 impl Error for DecodeUtf16Error {
     #[allow(deprecated)]
diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs
index 72d63ac4b4b..b34a7121631 100644
--- a/library/core/src/char/mod.rs
+++ b/library/core/src/char/mod.rs
@@ -38,7 +38,6 @@ pub use self::methods::encode_utf16_raw;
 #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")]
 pub use self::methods::encode_utf8_raw;
 
-#[cfg(not(bootstrap))]
 use crate::error::Error;
 use crate::fmt::{self, Write};
 use crate::iter::FusedIterator;
@@ -587,6 +586,5 @@ impl fmt::Display for TryFromCharError {
     }
 }
 
-#[cfg(not(bootstrap))]
 #[stable(feature = "u8_from_char", since = "1.59.0")]
 impl Error for TryFromCharError {}
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index 50b8264bac7..f0fa2e1d2c1 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -22,6 +22,7 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
+use crate::const_closure::ConstFnMutClosure;
 use crate::marker::Destruct;
 use crate::marker::StructuralPartialEq;
 
@@ -1222,7 +1223,12 @@ pub const fn min<T: ~const Ord + ~const Destruct>(v1: T, v2: T) -> T {
 #[inline]
 #[must_use]
 #[stable(feature = "cmp_min_max_by", since = "1.53.0")]
-pub fn min_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
+#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+pub const fn min_by<T, F: ~const FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T
+where
+    T: ~const Destruct,
+    F: ~const Destruct,
+{
     match compare(&v1, &v2) {
         Ordering::Less | Ordering::Equal => v1,
         Ordering::Greater => v2,
@@ -1244,8 +1250,24 @@ pub fn min_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
 #[inline]
 #[must_use]
 #[stable(feature = "cmp_min_max_by", since = "1.53.0")]
-pub fn min_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
-    min_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2)))
+#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+pub const fn min_by_key<T, F: ~const FnMut(&T) -> K, K: ~const Ord>(v1: T, v2: T, mut f: F) -> T
+where
+    T: ~const Destruct,
+    F: ~const Destruct,
+    K: ~const Destruct,
+{
+    const fn imp<T, F: ~const FnMut(&T) -> K, K: ~const Ord>(
+        f: &mut F,
+        (v1, v2): (&T, &T),
+    ) -> Ordering
+    where
+        T: ~const Destruct,
+        K: ~const Destruct,
+    {
+        f(v1).cmp(&f(v2))
+    }
+    min_by(v1, v2, ConstFnMutClosure::new(&mut f, imp))
 }
 
 /// Compares and returns the maximum of two values.
@@ -1286,7 +1308,12 @@ pub const fn max<T: ~const Ord + ~const Destruct>(v1: T, v2: T) -> T {
 #[inline]
 #[must_use]
 #[stable(feature = "cmp_min_max_by", since = "1.53.0")]
-pub fn max_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
+#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+pub const fn max_by<T, F: ~const FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T
+where
+    T: ~const Destruct,
+    F: ~const Destruct,
+{
     match compare(&v1, &v2) {
         Ordering::Less | Ordering::Equal => v2,
         Ordering::Greater => v1,
@@ -1308,8 +1335,24 @@ pub fn max_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
 #[inline]
 #[must_use]
 #[stable(feature = "cmp_min_max_by", since = "1.53.0")]
-pub fn max_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
-    max_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2)))
+#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+pub const fn max_by_key<T, F: ~const FnMut(&T) -> K, K: ~const Ord>(v1: T, v2: T, mut f: F) -> T
+where
+    T: ~const Destruct,
+    F: ~const Destruct,
+    K: ~const Destruct,
+{
+    const fn imp<T, F: ~const FnMut(&T) -> K, K: ~const Ord>(
+        f: &mut F,
+        (v1, v2): (&T, &T),
+    ) -> Ordering
+    where
+        T: ~const Destruct,
+        K: ~const Destruct,
+    {
+        f(v1).cmp(&f(v2))
+    }
+    max_by(v1, v2, ConstFnMutClosure::new(&mut f, imp))
 }
 
 // Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types
diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs
index 0480704a6d6..6f23b9d908d 100644
--- a/library/core/src/convert/mod.rs
+++ b/library/core/src/convert/mod.rs
@@ -34,7 +34,6 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-#[cfg(not(bootstrap))]
 use crate::error::Error;
 use crate::fmt;
 use crate::hash::{Hash, Hasher};
@@ -441,7 +440,7 @@ pub trait TryInto<T>: Sized {
 ///
 ///     fn try_from(value: i32) -> Result<Self, Self::Error> {
 ///         if value <= 0 {
-///             Err("GreaterThanZero only accepts value superior than zero!")
+///             Err("GreaterThanZero only accepts values greater than zero!")
 ///         } else {
 ///             Ok(GreaterThanZero(value))
 ///         }
@@ -724,7 +723,6 @@ impl fmt::Display for Infallible {
     }
 }
 
-#[cfg(not(bootstrap))]
 #[stable(feature = "str_parse_error2", since = "1.8.0")]
 impl Error for Infallible {
     fn description(&self) -> &str {
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 905212eb372..372439f14ec 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -709,12 +709,19 @@ pub use macros::Debug;
 
 /// Format trait for an empty format, `{}`.
 ///
+/// Implementing this trait for a type will automatically implement the
+/// [`ToString`][tostring] trait for the type, allowing the usage
+/// of the [`.to_string()`][tostring_function] method. Prefer implementing
+/// the `Display` trait for a type, rather than [`ToString`][tostring].
+///
 /// `Display` is similar to [`Debug`], but `Display` is for user-facing
 /// output, and so cannot be derived.
 ///
 /// For more information on formatters, see [the module-level documentation][module].
 ///
 /// [module]: ../../std/fmt/index.html
+/// [tostring]: ../../std/string/trait.ToString.html
+/// [tostring_function]: ../../std/string/trait.ToString.html#tymethod.to_string
 ///
 /// # Examples
 ///
diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs
index 764e2796202..f9267371aa7 100644
--- a/library/core/src/hint.rs
+++ b/library/core/src/hint.rs
@@ -217,7 +217,7 @@ pub fn spin_loop() {
 ///
 /// [`std::convert::identity`]: crate::convert::identity
 #[inline]
-#[unstable(feature = "bench_black_box", issue = "64102")]
+#[stable(feature = "bench_black_box", since = "CURRENT_RUSTC_VERSION")]
 #[rustc_const_unstable(feature = "const_black_box", issue = "none")]
 pub const fn black_box<T>(dummy: T) -> T {
     crate::intrinsics::black_box(dummy)
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 11c75e2c912..15ee14398b6 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -54,8 +54,6 @@
 )]
 #![allow(missing_docs)]
 
-#[cfg(bootstrap)]
-use crate::marker::Destruct;
 use crate::marker::DiscriminantKind;
 use crate::mem;
 
@@ -790,6 +788,7 @@ extern "rust-intrinsic" {
     /// uninitialized at that point in the control flow.
     ///
     /// This intrinsic should not be used outside of the compiler.
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn rustc_peek<T>(_: T) -> T;
 
     /// Aborts the execution of the process.
@@ -807,6 +806,7 @@ extern "rust-intrinsic" {
     /// On Unix, the
     /// process will probably terminate with a signal like `SIGABRT`, `SIGILL`, `SIGTRAP`, `SIGSEGV` or
     /// `SIGBUS`.  The precise behaviour is not guaranteed and not stable.
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn abort() -> !;
 
     /// Informs the optimizer that this point in the code is not reachable,
@@ -845,6 +845,7 @@ extern "rust-intrinsic" {
     ///
     /// This intrinsic does not have a stable counterpart.
     #[rustc_const_unstable(feature = "const_likely", issue = "none")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn likely(b: bool) -> bool;
 
     /// Hints to the compiler that branch condition is likely to be false.
@@ -859,6 +860,7 @@ extern "rust-intrinsic" {
     ///
     /// This intrinsic does not have a stable counterpart.
     #[rustc_const_unstable(feature = "const_likely", issue = "none")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn unlikely(b: bool) -> bool;
 
     /// Executes a breakpoint trap, for inspection by a debugger.
@@ -878,6 +880,7 @@ extern "rust-intrinsic" {
     ///
     /// The stabilized version of this intrinsic is [`core::mem::size_of`].
     #[rustc_const_stable(feature = "const_size_of", since = "1.40.0")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn size_of<T>() -> usize;
 
     /// The minimum alignment of a type.
@@ -889,6 +892,7 @@ extern "rust-intrinsic" {
     ///
     /// The stabilized version of this intrinsic is [`core::mem::align_of`].
     #[rustc_const_stable(feature = "const_min_align_of", since = "1.40.0")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn min_align_of<T>() -> usize;
     /// The preferred alignment of a type.
     ///
@@ -917,6 +921,7 @@ extern "rust-intrinsic" {
     ///
     /// The stabilized version of this intrinsic is [`core::any::type_name`].
     #[rustc_const_unstable(feature = "const_type_name", issue = "63084")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn type_name<T: ?Sized>() -> &'static str;
 
     /// Gets an identifier which is globally unique to the specified type. This
@@ -930,6 +935,7 @@ extern "rust-intrinsic" {
     ///
     /// The stabilized version of this intrinsic is [`core::any::TypeId::of`].
     #[rustc_const_unstable(feature = "const_type_id", issue = "77125")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn type_id<T: ?Sized + 'static>() -> u64;
 
     /// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited:
@@ -937,6 +943,7 @@ extern "rust-intrinsic" {
     ///
     /// This intrinsic does not have a stable counterpart.
     #[rustc_const_stable(feature = "const_assert_type", since = "1.59.0")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn assert_inhabited<T>();
 
     /// A guard for unsafe functions that cannot ever be executed if `T` does not permit
@@ -944,6 +951,7 @@ extern "rust-intrinsic" {
     ///
     /// This intrinsic does not have a stable counterpart.
     #[rustc_const_unstable(feature = "const_assert_type2", issue = "none")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn assert_zero_valid<T>();
 
     /// A guard for unsafe functions that cannot ever be executed if `T` has invalid
@@ -951,6 +959,7 @@ extern "rust-intrinsic" {
     ///
     /// This intrinsic does not have a stable counterpart.
     #[rustc_const_unstable(feature = "const_assert_type2", issue = "none")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn assert_uninit_valid<T>();
 
     /// Gets a reference to a static `Location` indicating where it was called.
@@ -962,6 +971,7 @@ extern "rust-intrinsic" {
     ///
     /// Consider using [`core::panic::Location::caller`] instead.
     #[rustc_const_unstable(feature = "const_caller_location", issue = "76156")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn caller_location() -> &'static crate::panic::Location<'static>;
 
     /// Moves a value out of scope without running drop glue.
@@ -974,6 +984,7 @@ extern "rust-intrinsic" {
     /// Therefore, implementations must not require the user to uphold
     /// any safety invariants.
     #[rustc_const_unstable(feature = "const_intrinsic_forget", issue = "none")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn forget<T: ?Sized>(_: T);
 
     /// Reinterprets the bits of a value of one type as another type.
@@ -1253,6 +1264,7 @@ extern "rust-intrinsic" {
     ///
     /// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop).
     #[rustc_const_stable(feature = "const_needs_drop", since = "1.40.0")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn needs_drop<T: ?Sized>() -> bool;
 
     /// Calculates the offset from a pointer.
@@ -1297,7 +1309,7 @@ extern "rust-intrinsic" {
     /// any safety invariants.
     ///
     /// Consider using [`pointer::mask`] instead.
-    #[cfg(not(bootstrap))]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn ptr_mask<T>(ptr: *const T, mask: usize) -> *const T;
 
     /// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with
@@ -1489,6 +1501,7 @@ extern "rust-intrinsic" {
     ///
     /// The stabilized version of this intrinsic is
     /// [`f32::min`]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn minnumf32(x: f32, y: f32) -> f32;
     /// Returns the minimum of two `f64` values.
     ///
@@ -1499,6 +1512,7 @@ extern "rust-intrinsic" {
     ///
     /// The stabilized version of this intrinsic is
     /// [`f64::min`]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn minnumf64(x: f64, y: f64) -> f64;
     /// Returns the maximum of two `f32` values.
     ///
@@ -1509,6 +1523,7 @@ extern "rust-intrinsic" {
     ///
     /// The stabilized version of this intrinsic is
     /// [`f32::max`]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn maxnumf32(x: f32, y: f32) -> f32;
     /// Returns the maximum of two `f64` values.
     ///
@@ -1519,6 +1534,7 @@ extern "rust-intrinsic" {
     ///
     /// The stabilized version of this intrinsic is
     /// [`f64::max`]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn maxnumf64(x: f64, y: f64) -> f64;
 
     /// Copies the sign from `y` to `x` for `f32` values.
@@ -1639,6 +1655,7 @@ extern "rust-intrinsic" {
     /// primitives via the `count_ones` method. For example,
     /// [`u32::count_ones`]
     #[rustc_const_stable(feature = "const_ctpop", since = "1.40.0")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn ctpop<T: Copy>(x: T) -> T;
 
     /// Returns the number of leading unset bits (zeroes) in an integer type `T`.
@@ -1676,6 +1693,7 @@ extern "rust-intrinsic" {
     /// assert_eq!(num_leading, 16);
     /// ```
     #[rustc_const_stable(feature = "const_ctlz", since = "1.40.0")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn ctlz<T: Copy>(x: T) -> T;
 
     /// Like `ctlz`, but extra-unsafe as it returns `undef` when
@@ -1732,6 +1750,7 @@ extern "rust-intrinsic" {
     /// assert_eq!(num_trailing, 16);
     /// ```
     #[rustc_const_stable(feature = "const_cttz", since = "1.40.0")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn cttz<T: Copy>(x: T) -> T;
 
     /// Like `cttz`, but extra-unsafe as it returns `undef` when
@@ -1764,6 +1783,7 @@ extern "rust-intrinsic" {
     /// primitives via the `swap_bytes` method. For example,
     /// [`u32::swap_bytes`]
     #[rustc_const_stable(feature = "const_bswap", since = "1.40.0")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn bswap<T: Copy>(x: T) -> T;
 
     /// Reverses the bits in an integer type `T`.
@@ -1777,6 +1797,7 @@ extern "rust-intrinsic" {
     /// primitives via the `reverse_bits` method. For example,
     /// [`u32::reverse_bits`]
     #[rustc_const_stable(feature = "const_bitreverse", since = "1.40.0")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn bitreverse<T: Copy>(x: T) -> T;
 
     /// Performs checked integer addition.
@@ -1790,6 +1811,7 @@ extern "rust-intrinsic" {
     /// primitives via the `overflowing_add` method. For example,
     /// [`u32::overflowing_add`]
     #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn add_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
 
     /// Performs checked integer subtraction
@@ -1803,6 +1825,7 @@ extern "rust-intrinsic" {
     /// primitives via the `overflowing_sub` method. For example,
     /// [`u32::overflowing_sub`]
     #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn sub_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
 
     /// Performs checked integer multiplication
@@ -1816,6 +1839,7 @@ extern "rust-intrinsic" {
     /// primitives via the `overflowing_mul` method. For example,
     /// [`u32::overflowing_mul`]
     #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn mul_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
 
     /// Performs an exact division, resulting in undefined behavior where
@@ -1890,6 +1914,7 @@ extern "rust-intrinsic" {
     /// primitives via the `rotate_left` method. For example,
     /// [`u32::rotate_left`]
     #[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn rotate_left<T: Copy>(x: T, y: T) -> T;
 
     /// Performs rotate right.
@@ -1903,6 +1928,7 @@ extern "rust-intrinsic" {
     /// primitives via the `rotate_right` method. For example,
     /// [`u32::rotate_right`]
     #[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn rotate_right<T: Copy>(x: T, y: T) -> T;
 
     /// Returns (a + b) mod 2<sup>N</sup>, where N is the width of T in bits.
@@ -1916,6 +1942,7 @@ extern "rust-intrinsic" {
     /// primitives via the `wrapping_add` method. For example,
     /// [`u32::wrapping_add`]
     #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn wrapping_add<T: Copy>(a: T, b: T) -> T;
     /// Returns (a - b) mod 2<sup>N</sup>, where N is the width of T in bits.
     ///
@@ -1928,6 +1955,7 @@ extern "rust-intrinsic" {
     /// primitives via the `wrapping_sub` method. For example,
     /// [`u32::wrapping_sub`]
     #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn wrapping_sub<T: Copy>(a: T, b: T) -> T;
     /// Returns (a * b) mod 2<sup>N</sup>, where N is the width of T in bits.
     ///
@@ -1940,6 +1968,7 @@ extern "rust-intrinsic" {
     /// primitives via the `wrapping_mul` method. For example,
     /// [`u32::wrapping_mul`]
     #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn wrapping_mul<T: Copy>(a: T, b: T) -> T;
 
     /// Computes `a + b`, saturating at numeric bounds.
@@ -1953,6 +1982,7 @@ extern "rust-intrinsic" {
     /// primitives via the `saturating_add` method. For example,
     /// [`u32::saturating_add`]
     #[rustc_const_stable(feature = "const_int_saturating", since = "1.40.0")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn saturating_add<T: Copy>(a: T, b: T) -> T;
     /// Computes `a - b`, saturating at numeric bounds.
     ///
@@ -1965,6 +1995,7 @@ extern "rust-intrinsic" {
     /// primitives via the `saturating_sub` method. For example,
     /// [`u32::saturating_sub`]
     #[rustc_const_stable(feature = "const_int_saturating", since = "1.40.0")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn saturating_sub<T: Copy>(a: T, b: T) -> T;
 
     /// Returns the value of the discriminant for the variant in 'v';
@@ -1977,6 +2008,7 @@ extern "rust-intrinsic" {
     ///
     /// The stabilized version of this intrinsic is [`core::mem::discriminant`].
     #[rustc_const_unstable(feature = "const_discriminant", issue = "69821")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant;
 
     /// Returns the number of variants of the type `T` cast to a `usize`;
@@ -1989,6 +2021,7 @@ extern "rust-intrinsic" {
     ///
     /// The to-be-stabilized version of this intrinsic is [`mem::variant_count`].
     #[rustc_const_unstable(feature = "variant_count", issue = "73662")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn variant_count<T>() -> usize;
 
     /// Rust's "try catch" construct which invokes the function pointer `try_fn`
@@ -2022,17 +2055,9 @@ extern "rust-intrinsic" {
     /// Therefore, implementations must not require the user to uphold
     /// any safety invariants.
     #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
-    #[cfg(not(bootstrap))]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn ptr_guaranteed_cmp<T>(ptr: *const T, other: *const T) -> u8;
 
-    #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
-    #[cfg(bootstrap)]
-    pub fn ptr_guaranteed_eq<T>(ptr: *const T, other: *const T) -> bool;
-
-    #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
-    #[cfg(bootstrap)]
-    pub fn ptr_guaranteed_ne<T>(ptr: *const T, other: *const T) -> bool;
-
     /// Allocates a block of memory at compile time.
     /// At runtime, just returns a null pointer.
     ///
@@ -2081,6 +2106,7 @@ extern "rust-intrinsic" {
     ///
     /// [`std::hint::black_box`]: crate::hint::black_box
     #[rustc_const_unstable(feature = "const_black_box", issue = "none")]
+    #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
     pub fn black_box<T>(dummy: T) -> T;
 
     /// `ptr` must point to a vtable.
@@ -2143,7 +2169,6 @@ extern "rust-intrinsic" {
     /// `unreachable_unchecked` is actually being reached. The bug is in *crate A*,
     /// which violates the principle that a `const fn` must behave the same at
     /// compile-time and at run-time. The unsafe code in crate B is fine.
-    #[cfg(not(bootstrap))]
     #[rustc_const_unstable(feature = "const_eval_select", issue = "none")]
     pub fn const_eval_select<ARG, F, G, RET>(arg: ARG, called_in_const: F, called_at_rt: G) -> RET
     where
@@ -2216,16 +2241,6 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -
     diff >= size
 }
 
-#[cfg(bootstrap)]
-pub const fn ptr_guaranteed_cmp(a: *const (), b: *const ()) -> u8 {
-    match (ptr_guaranteed_eq(a, b), ptr_guaranteed_ne(a, b)) {
-        (false, false) => 2,
-        (true, false) => 1,
-        (false, true) => 0,
-        (true, true) => unreachable!(),
-    }
-}
-
 /// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
 /// and destination must *not* overlap.
 ///
@@ -2484,45 +2499,3 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
         write_bytes(dst, val, count)
     }
 }
-
-#[cfg(bootstrap)]
-#[unstable(
-    feature = "const_eval_select",
-    issue = "none",
-    reason = "const_eval_select will never be stable"
-)]
-#[rustc_const_unstable(feature = "const_eval_select", issue = "none")]
-#[lang = "const_eval_select"]
-#[rustc_do_not_const_check]
-#[inline]
-pub const unsafe fn const_eval_select<ARG, F, G, RET>(
-    arg: ARG,
-    _called_in_const: F,
-    called_at_rt: G,
-) -> RET
-where
-    F: ~const FnOnce<ARG, Output = RET>,
-    G: FnOnce<ARG, Output = RET> + ~const Destruct,
-{
-    called_at_rt.call_once(arg)
-}
-
-#[cfg(bootstrap)]
-#[unstable(
-    feature = "const_eval_select",
-    issue = "none",
-    reason = "const_eval_select will never be stable"
-)]
-#[rustc_const_unstable(feature = "const_eval_select", issue = "none")]
-#[lang = "const_eval_select_ct"]
-pub const unsafe fn const_eval_select_ct<ARG, F, G, RET>(
-    arg: ARG,
-    called_in_const: F,
-    _called_at_rt: G,
-) -> RET
-where
-    F: ~const FnOnce<ARG, Output = RET>,
-    G: FnOnce<ARG, Output = RET> + ~const Destruct,
-{
-    called_in_const.call_once(arg)
-}
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index 45be7bdd8db..f6e6732b0e3 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -2431,22 +2431,13 @@ pub trait Iterator {
     ///
     /// # Example
     ///
-    /// Find the maximum value:
-    ///
     /// ```
-    /// fn find_max<I>(iter: I) -> Option<I::Item>
-    ///     where I: Iterator,
-    ///           I::Item: Ord,
-    /// {
-    ///     iter.reduce(|accum, item| {
-    ///         if accum >= item { accum } else { item }
-    ///     })
-    /// }
-    /// let a = [10, 20, 5, -23, 0];
-    /// let b: [u32; 0] = [];
+    /// let reduced: i32 = (1..10).reduce(|acc, e| acc + e).unwrap();
+    /// assert_eq!(reduced, 45);
     ///
-    /// assert_eq!(find_max(a.iter()), Some(&20));
-    /// assert_eq!(find_max(b.iter()), None);
+    /// // Which is equivalent to doing it with `fold`:
+    /// let folded: i32 = (1..10).fold(0, |acc, e| acc + e);
+    /// assert_eq!(reduced, folded);
     /// ```
     #[inline]
     #[stable(feature = "iterator_fold_self", since = "1.51.0")]
@@ -2906,14 +2897,14 @@ pub trait Iterator {
     /// Stopping at the first `true`:
     ///
     /// ```
-    /// let a = [1, 2, 3];
+    /// let a = [-1, 2, 3, 4];
     ///
     /// let mut iter = a.iter();
     ///
-    /// assert_eq!(iter.rposition(|&x| x == 2), Some(1));
+    /// assert_eq!(iter.rposition(|&x| x >= 2), Some(3));
     ///
     /// // we can still use `iter`, as there are more elements.
-    /// assert_eq!(iter.next(), Some(&1));
+    /// assert_eq!(iter.next(), Some(&-1));
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 6fbe7ade732..c3df0d4f9b9 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -138,6 +138,7 @@
 #![feature(const_size_of_val)]
 #![feature(const_slice_from_raw_parts_mut)]
 #![feature(const_slice_ptr_len)]
+#![feature(const_slice_split_at_mut)]
 #![feature(const_str_from_utf8_unchecked_mut)]
 #![feature(const_swap)]
 #![feature(const_trait_impl)]
@@ -194,7 +195,6 @@
 #![feature(link_llvm_intrinsics)]
 #![feature(macro_metavar_expr)]
 #![feature(min_specialization)]
-#![feature(mixed_integer_ops)]
 #![feature(must_not_suspend)]
 #![feature(negative_impls)]
 #![feature(never_type)]
@@ -309,7 +309,6 @@ pub mod clone;
 pub mod cmp;
 pub mod convert;
 pub mod default;
-#[cfg(not(bootstrap))]
 pub mod error;
 pub mod marker;
 pub mod ops;
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index 40a7b696193..5cb5e4458cc 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -806,7 +806,7 @@ pub trait Destruct {}
 /// The implementation of this trait is built-in and cannot be implemented
 /// for any user type.
 #[unstable(feature = "tuple_trait", issue = "none")]
-#[cfg_attr(not(bootstrap), lang = "tuple_trait")]
+#[lang = "tuple_trait"]
 #[rustc_on_unimplemented(message = "`{Self}` is not a tuple")]
 pub trait Tuple {}
 
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index d2dd2941d59..66fca2fd281 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -1178,3 +1178,44 @@ pub const fn discriminant<T>(v: &T) -> Discriminant<T> {
 pub const fn variant_count<T>() -> usize {
     intrinsics::variant_count::<T>()
 }
+
+/// Provides associated constants for various useful properties of types,
+/// to give them a canonical form in our code and make them easier to read.
+///
+/// This is here only to simplify all the ZST checks we need in the library.
+/// It's not on a stabilization track right now.
+#[doc(hidden)]
+#[unstable(feature = "sized_type_properties", issue = "none")]
+pub trait SizedTypeProperties: Sized {
+    /// `true` if this type requires no storage.
+    /// `false` if its [size](size_of) is greater than zero.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(sized_type_properties)]
+    /// use core::mem::SizedTypeProperties;
+    ///
+    /// fn do_something_with<T>() {
+    ///     if T::IS_ZST {
+    ///         // ... special approach ...
+    ///     } else {
+    ///         // ... the normal thing ...
+    ///     }
+    /// }
+    ///
+    /// struct MyUnit;
+    /// assert!(MyUnit::IS_ZST);
+    ///
+    /// // For negative checks, consider using UFCS to emphasize the negation
+    /// assert!(!<i32>::IS_ZST);
+    /// // As it can sometimes hide in the type otherwise
+    /// assert!(!String::IS_ZST);
+    /// ```
+    #[doc(hidden)]
+    #[unstable(feature = "sized_type_properties", issue = "none")]
+    const IS_ZST: bool = size_of::<Self>() == 0;
+}
+#[doc(hidden)]
+#[unstable(feature = "sized_type_properties", issue = "none")]
+impl<T> SizedTypeProperties for T {}
diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs
index 87a37863105..3b98efff293 100644
--- a/library/core/src/mem/transmutability.rs
+++ b/library/core/src/mem/transmutability.rs
@@ -4,7 +4,7 @@
 /// any value of type `Self` are safely transmutable into a value of type `Dst`, in a given `Context`,
 /// notwithstanding whatever safety checks you have asked the compiler to [`Assume`] are satisfied.
 #[unstable(feature = "transmutability", issue = "99571")]
-#[cfg_attr(not(bootstrap), lang = "transmute_trait")]
+#[lang = "transmute_trait"]
 #[rustc_on_unimplemented(
     message = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`.",
     label = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`."
@@ -17,7 +17,7 @@ where
 
 /// What transmutation safety conditions shall the compiler assume that *you* are checking?
 #[unstable(feature = "transmutability", issue = "99571")]
-#[cfg_attr(not(bootstrap), lang = "transmute_opts")]
+#[lang = "transmute_opts"]
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
 pub struct Assume {
     /// When `true`, the compiler assumes that *you* are ensuring (either dynamically or statically) that
diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs
index 1f6b40e5df5..768dd87816d 100644
--- a/library/core/src/num/error.rs
+++ b/library/core/src/num/error.rs
@@ -1,7 +1,6 @@
 //! Error types for conversion to integral types.
 
 use crate::convert::Infallible;
-#[cfg(not(bootstrap))]
 use crate::error::Error;
 use crate::fmt;
 
@@ -147,7 +146,6 @@ impl fmt::Display for ParseIntError {
     }
 }
 
-#[cfg(not(bootstrap))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Error for ParseIntError {
     #[allow(deprecated)]
@@ -156,7 +154,6 @@ impl Error for ParseIntError {
     }
 }
 
-#[cfg(not(bootstrap))]
 #[stable(feature = "try_from", since = "1.34.0")]
 impl Error for TryFromIntError {
     #[allow(deprecated)]
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index e7deb728d15..d6aeee299e3 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -464,12 +464,11 @@ macro_rules! int_impl {
         /// Basic usage:
         ///
         /// ```
-        /// # #![feature(mixed_integer_ops)]
         #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_unsigned(2), Some(3));")]
         #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add_unsigned(3), None);")]
         /// ```
-        #[unstable(feature = "mixed_integer_ops", issue = "87840")]
-        #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -533,12 +532,11 @@ macro_rules! int_impl {
         /// Basic usage:
         ///
         /// ```
-        /// # #![feature(mixed_integer_ops)]
         #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_sub_unsigned(2), Some(-1));")]
         #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).checked_sub_unsigned(3), None);")]
         /// ```
-        #[unstable(feature = "mixed_integer_ops", issue = "87840")]
-        #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -907,12 +905,11 @@ macro_rules! int_impl {
         /// Basic usage:
         ///
         /// ```
-        /// # #![feature(mixed_integer_ops)]
         #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_unsigned(2), 3);")]
         #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_add_unsigned(100), ", stringify!($SelfT), "::MAX);")]
         /// ```
-        #[unstable(feature = "mixed_integer_ops", issue = "87840")]
-        #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -954,12 +951,11 @@ macro_rules! int_impl {
         /// Basic usage:
         ///
         /// ```
-        /// # #![feature(mixed_integer_ops)]
         #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".saturating_sub_unsigned(127), -27);")]
         #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_sub_unsigned(100), ", stringify!($SelfT), "::MIN);")]
         /// ```
-        #[unstable(feature = "mixed_integer_ops", issue = "87840")]
-        #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -1135,12 +1131,11 @@ macro_rules! int_impl {
         /// Basic usage:
         ///
         /// ```
-        /// # #![feature(mixed_integer_ops)]
         #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_add_unsigned(27), 127);")]
         #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.wrapping_add_unsigned(2), ", stringify!($SelfT), "::MIN + 1);")]
         /// ```
-        #[unstable(feature = "mixed_integer_ops", issue = "87840")]
-        #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline(always)]
@@ -1176,12 +1171,11 @@ macro_rules! int_impl {
         /// Basic usage:
         ///
         /// ```
-        /// # #![feature(mixed_integer_ops)]
         #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".wrapping_sub_unsigned(127), -127);")]
         #[doc = concat!("assert_eq!((-2", stringify!($SelfT), ").wrapping_sub_unsigned(", stringify!($UnsignedT), "::MAX), -1);")]
         /// ```
-        #[unstable(feature = "mixed_integer_ops", issue = "87840")]
-        #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline(always)]
@@ -1574,13 +1568,12 @@ macro_rules! int_impl {
         /// Basic usage:
         ///
         /// ```
-        /// # #![feature(mixed_integer_ops)]
         #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_add_unsigned(2), (3, false));")]
         #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN).overflowing_add_unsigned(", stringify!($UnsignedT), "::MAX), (", stringify!($SelfT), "::MAX, false));")]
         #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).overflowing_add_unsigned(3), (", stringify!($SelfT), "::MIN, true));")]
         /// ```
-        #[unstable(feature = "mixed_integer_ops", issue = "87840")]
-        #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -1658,13 +1651,12 @@ macro_rules! int_impl {
         /// Basic usage:
         ///
         /// ```
-        /// # #![feature(mixed_integer_ops)]
         #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_sub_unsigned(2), (-1, false));")]
         #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX).overflowing_sub_unsigned(", stringify!($UnsignedT), "::MAX), (", stringify!($SelfT), "::MIN, false));")]
         #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).overflowing_sub_unsigned(3), (", stringify!($SelfT), "::MAX, true));")]
         /// ```
-        #[unstable(feature = "mixed_integer_ops", issue = "87840")]
-        #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index dd4409198e3..c0be235c120 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -3,7 +3,6 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use crate::ascii;
-#[cfg(not(bootstrap))]
 use crate::error::Error;
 use crate::intrinsics;
 use crate::mem;
@@ -59,7 +58,6 @@ pub use wrapping::Wrapping;
 #[cfg(not(no_fp_fmt_parse))]
 pub use dec2flt::ParseFloatError;
 
-#[cfg(not(bootstrap))]
 #[cfg(not(no_fp_fmt_parse))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Error for ParseFloatError {
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 532a09736a7..da402d66502 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -721,6 +721,160 @@ macro_rules! nonzero_signed_operations {
                     // SAFETY: absolute value of nonzero cannot yield zero values.
                     unsafe { $Uty::new_unchecked(self.get().unsigned_abs()) }
                 }
+
+                /// Returns `true` if `self` is negative and `false` if the
+                /// number is positive.
+                ///
+                /// # Example
+                ///
+                /// ```
+                /// #![feature(nonzero_negation_ops)]
+                ///
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                /// # fn main() { test().unwrap(); }
+                /// # fn test() -> Option<()> {
+                #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")]
+                #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")]
+                ///
+                /// assert!(neg_five.is_negative());
+                /// assert!(!pos_five.is_negative());
+                /// # Some(())
+                /// # }
+                /// ```
+                #[must_use]
+                #[inline]
+                #[unstable(feature = "nonzero_negation_ops", issue = "102443")]
+                pub const fn is_negative(self) -> bool {
+                    self.get().is_negative()
+                }
+
+                /// Checked negation. Computes `-self`, returning `None` if `self == i32::MIN`.
+                ///
+                /// # Example
+                ///
+                /// ```
+                /// #![feature(nonzero_negation_ops)]
+                ///
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                /// # fn main() { test().unwrap(); }
+                /// # fn test() -> Option<()> {
+                #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")]
+                #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")]
+                #[doc = concat!("let min = ", stringify!($Ty), "::new(",
+                                stringify!($Int), "::MIN)?;")]
+                ///
+                /// assert_eq!(pos_five.checked_neg(), Some(neg_five));
+                /// assert_eq!(min.checked_neg(), None);
+                /// # Some(())
+                /// # }
+                /// ```
+                #[inline]
+                #[unstable(feature = "nonzero_negation_ops", issue = "102443")]
+                pub const fn checked_neg(self) -> Option<$Ty> {
+                    if let Some(result) = self.get().checked_neg() {
+                        // SAFETY: negation of nonzero cannot yield zero values.
+                        return Some(unsafe { $Ty::new_unchecked(result) });
+                    }
+                    None
+                }
+
+                /// Negates self, overflowing if this is equal to the minimum value.
+                ///
+                #[doc = concat!("See [`", stringify!($Int), "::overflowing_neg`]")]
+                /// for documentation on overflow behaviour.
+                ///
+                /// # Example
+                ///
+                /// ```
+                /// #![feature(nonzero_negation_ops)]
+                ///
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                /// # fn main() { test().unwrap(); }
+                /// # fn test() -> Option<()> {
+                #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")]
+                #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")]
+                #[doc = concat!("let min = ", stringify!($Ty), "::new(",
+                                stringify!($Int), "::MIN)?;")]
+                ///
+                /// assert_eq!(pos_five.overflowing_neg(), (neg_five, false));
+                /// assert_eq!(min.overflowing_neg(), (min, true));
+                /// # Some(())
+                /// # }
+                /// ```
+                #[inline]
+                #[unstable(feature = "nonzero_negation_ops", issue = "102443")]
+                pub const fn overflowing_neg(self) -> ($Ty, bool) {
+                    let (result, overflow) = self.get().overflowing_neg();
+                    // SAFETY: negation of nonzero cannot yield zero values.
+                    ((unsafe { $Ty::new_unchecked(result) }), overflow)
+                }
+
+                /// Saturating negation. Computes `-self`, returning `MAX` if
+                /// `self == i32::MIN` instead of overflowing.
+                ///
+                /// # Example
+                ///
+                /// ```
+                /// #![feature(nonzero_negation_ops)]
+                ///
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                /// # fn main() { test().unwrap(); }
+                /// # fn test() -> Option<()> {
+                #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")]
+                #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")]
+                #[doc = concat!("let min = ", stringify!($Ty), "::new(",
+                                stringify!($Int), "::MIN)?;")]
+                #[doc = concat!("let min_plus_one = ", stringify!($Ty), "::new(",
+                                stringify!($Int), "::MIN + 1)?;")]
+                #[doc = concat!("let max = ", stringify!($Ty), "::new(",
+                                stringify!($Int), "::MAX)?;")]
+                ///
+                /// assert_eq!(pos_five.saturating_neg(), neg_five);
+                /// assert_eq!(min.saturating_neg(), max);
+                /// assert_eq!(max.saturating_neg(), min_plus_one);
+                /// # Some(())
+                /// # }
+                /// ```
+                #[inline]
+                #[unstable(feature = "nonzero_negation_ops", issue = "102443")]
+                pub const fn saturating_neg(self) -> $Ty {
+                    if let Some(result) = self.checked_neg() {
+                        return result;
+                    }
+                    $Ty::MAX
+                }
+
+                /// Wrapping (modular) negation. Computes `-self`, wrapping around at the boundary
+                /// of the type.
+                ///
+                #[doc = concat!("See [`", stringify!($Int), "::wrapping_neg`]")]
+                /// for documentation on overflow behaviour.
+                ///
+                /// # Example
+                ///
+                /// ```
+                /// #![feature(nonzero_negation_ops)]
+                ///
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                /// # fn main() { test().unwrap(); }
+                /// # fn test() -> Option<()> {
+                #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")]
+                #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")]
+                #[doc = concat!("let min = ", stringify!($Ty), "::new(",
+                                stringify!($Int), "::MIN)?;")]
+                ///
+                /// assert_eq!(pos_five.wrapping_neg(), neg_five);
+                /// assert_eq!(min.wrapping_neg(), min);
+                /// # Some(())
+                /// # }
+                /// ```
+                #[inline]
+                #[unstable(feature = "nonzero_negation_ops", issue = "102443")]
+                pub const fn wrapping_neg(self) -> $Ty {
+                    let result = self.get().wrapping_neg();
+                    // SAFETY: negation of nonzero cannot yield zero values.
+                    unsafe { $Ty::new_unchecked(result) }
+                }
             }
         )+
     }
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 46fd7f2d0e4..46b0ca23034 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -474,13 +474,12 @@ macro_rules! uint_impl {
         /// Basic usage:
         ///
         /// ```
-        /// # #![feature(mixed_integer_ops)]
         #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_signed(2), Some(3));")]
         #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_signed(-2), None);")]
         #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add_signed(3), None);")]
         /// ```
-        #[unstable(feature = "mixed_integer_ops", issue = "87840")]
-        #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -1057,13 +1056,12 @@ macro_rules! uint_impl {
         /// Basic usage:
         ///
         /// ```
-        /// # #![feature(mixed_integer_ops)]
         #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_signed(2), 3);")]
         #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_signed(-2), 0);")]
         #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).saturating_add_signed(4), ", stringify!($SelfT), "::MAX);")]
         /// ```
-        #[unstable(feature = "mixed_integer_ops", issue = "87840")]
-        #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -1198,13 +1196,12 @@ macro_rules! uint_impl {
         /// Basic usage:
         ///
         /// ```
-        /// # #![feature(mixed_integer_ops)]
         #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_add_signed(2), 3);")]
         #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_add_signed(-2), ", stringify!($SelfT), "::MAX);")]
         #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).wrapping_add_signed(4), 1);")]
         /// ```
-        #[unstable(feature = "mixed_integer_ops", issue = "87840")]
-        #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -1564,13 +1561,12 @@ macro_rules! uint_impl {
         /// Basic usage:
         ///
         /// ```
-        /// # #![feature(mixed_integer_ops)]
         #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_add_signed(2), (3, false));")]
         #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_add_signed(-2), (", stringify!($SelfT), "::MAX, true));")]
         #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).overflowing_add_signed(4), (1, true));")]
         /// ```
-        #[unstable(feature = "mixed_integer_ops", issue = "87840")]
-        #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "mixed_integer_ops", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
diff --git a/library/core/src/ops/generator.rs b/library/core/src/ops/generator.rs
index 3ebd6f8cdbd..fee4beb1e84 100644
--- a/library/core/src/ops/generator.rs
+++ b/library/core/src/ops/generator.rs
@@ -83,7 +83,6 @@ pub trait Generator<R = ()> {
     /// `return` statement or implicitly as the last expression of a generator
     /// literal. For example futures would use this as `Result<T, E>` as it
     /// represents a completed future.
-    #[cfg_attr(bootstrap, lang = "generator_return")]
     type Return;
 
     /// Resumes the execution of this generator.
diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs
index 72820283581..d29ae35614c 100644
--- a/library/core/src/ops/range.rs
+++ b/library/core/src/ops/range.rs
@@ -677,7 +677,7 @@ pub enum Bound<T> {
 impl<T> Bound<T> {
     /// Converts from `&Bound<T>` to `Bound<&T>`.
     #[inline]
-    #[stable(feature = "bound_as_ref_shared", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "bound_as_ref_shared", since = "1.65.0")]
     pub fn as_ref(&self) -> Bound<&T> {
         match *self {
             Included(ref x) => Included(x),
diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs
index 4d0d4e12adb..33df9e6c5cd 100644
--- a/library/core/src/ops/try_trait.rs
+++ b/library/core/src/ops/try_trait.rs
@@ -223,7 +223,7 @@ pub trait Try: ~const FromResidual {
 /// Every `Try` type needs to be recreatable from its own associated
 /// `Residual` type, but can also have additional `FromResidual` implementations
 /// to support interconversion with other `Try` types.
-#[cfg_attr(not(bootstrap), rustc_on_unimplemented(
+#[rustc_on_unimplemented(
     on(
         all(
             from_desugaring = "QuestionMark",
@@ -302,87 +302,7 @@ pub trait Try: ~const FromResidual {
         label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`",
         parent_label = "this function should return `Result` or `Option` to accept `?`"
     ),
-))]
-#[cfg_attr(bootstrap, rustc_on_unimplemented(
-    on(
-        all(
-            from_desugaring = "QuestionMark",
-            _Self = "std::result::Result<T, E>",
-            R = "std::option::Option<std::convert::Infallible>"
-        ),
-        message = "the `?` operator can only be used on `Result`s, not `Option`s, \
-            in {ItemContext} that returns `Result`",
-        label = "use `.ok_or(...)?` to provide an error compatible with `{Self}`",
-        enclosing_scope = "this function returns a `Result`"
-    ),
-    on(
-        all(
-            from_desugaring = "QuestionMark",
-            _Self = "std::result::Result<T, E>",
-        ),
-        // There's a special error message in the trait selection code for
-        // `From` in `?`, so this is not shown for result-in-result errors,
-        // and thus it can be phrased more strongly than `ControlFlow`'s.
-        message = "the `?` operator can only be used on `Result`s \
-            in {ItemContext} that returns `Result`",
-        label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
-        enclosing_scope = "this function returns a `Result`"
-    ),
-    on(
-        all(
-            from_desugaring = "QuestionMark",
-            _Self = "std::option::Option<T>",
-            R = "std::result::Result<T, E>",
-        ),
-        message = "the `?` operator can only be used on `Option`s, not `Result`s, \
-            in {ItemContext} that returns `Option`",
-        label = "use `.ok()?` if you want to discard the `{R}` error information",
-        enclosing_scope = "this function returns an `Option`"
-    ),
-    on(
-        all(
-            from_desugaring = "QuestionMark",
-            _Self = "std::option::Option<T>",
-        ),
-        // `Option`-in-`Option` always works, as there's only one possible
-        // residual, so this can also be phrased strongly.
-        message = "the `?` operator can only be used on `Option`s \
-            in {ItemContext} that returns `Option`",
-        label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
-        enclosing_scope = "this function returns an `Option`"
-    ),
-    on(
-        all(
-            from_desugaring = "QuestionMark",
-            _Self = "std::ops::ControlFlow<B, C>",
-            R = "std::ops::ControlFlow<B, C>",
-        ),
-        message = "the `?` operator in {ItemContext} that returns `ControlFlow<B, _>` \
-            can only be used on other `ControlFlow<B, _>`s (with the same Break type)",
-        label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
-        enclosing_scope = "this function returns a `ControlFlow`",
-        note = "unlike `Result`, there's no `From`-conversion performed for `ControlFlow`"
-    ),
-    on(
-        all(
-            from_desugaring = "QuestionMark",
-            _Self = "std::ops::ControlFlow<B, C>",
-            // `R` is not a `ControlFlow`, as that case was matched previously
-        ),
-        message = "the `?` operator can only be used on `ControlFlow`s \
-            in {ItemContext} that returns `ControlFlow`",
-        label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
-        enclosing_scope = "this function returns a `ControlFlow`",
-    ),
-    on(
-        all(from_desugaring = "QuestionMark"),
-        message = "the `?` operator can only be used in {ItemContext} \
-                    that returns `Result` or `Option` \
-                    (or another type that implements `{FromResidual}`)",
-        label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`",
-        enclosing_scope = "this function should return `Result` or `Option` to accept `?`"
-    ),
-))]
+)]
 #[rustc_diagnostic_item = "FromResidual"]
 #[unstable(feature = "try_trait_v2", issue = "84277")]
 #[const_trait]
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 96b16b13256..4a93df4591b 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -834,19 +834,12 @@ impl<T> Option<T> {
     ///
     /// # Examples
     ///
-    /// Converts a string to an integer, turning poorly-formed strings
-    /// into 0 (the default value for integers). [`parse`] converts
-    /// a string to any other type that implements [`FromStr`], returning
-    /// [`None`] on error.
-    ///
     /// ```
-    /// let good_year_from_input = "1909";
-    /// let bad_year_from_input = "190blarg";
-    /// let good_year = good_year_from_input.parse().ok().unwrap_or_default();
-    /// let bad_year = bad_year_from_input.parse().ok().unwrap_or_default();
+    /// let x: Option<u32> = None;
+    /// let y: Option<u32> = Some(12);
     ///
-    /// assert_eq!(1909, good_year);
-    /// assert_eq!(0, bad_year);
+    /// assert_eq!(x.unwrap_or_default(), 0);
+    /// assert_eq!(y.unwrap_or_default(), 12);
     /// ```
     ///
     /// [default value]: Default::default
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index fcdf69a7aaa..d898108be58 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -98,8 +98,8 @@ impl<T: ?Sized> *const T {
     ///
     /// This is a bit safer than `as` because it wouldn't silently change the type if the code is
     /// refactored.
-    #[stable(feature = "ptr_const_cast", since = "CURRENT_RUSTC_VERSION")]
-    #[rustc_const_stable(feature = "ptr_const_cast", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "ptr_const_cast", since = "1.65.0")]
+    #[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")]
     pub const fn cast_mut(self) -> *mut T {
         self as _
     }
@@ -568,7 +568,6 @@ impl<T: ?Sized> *const T {
     ///
     /// For non-`Sized` pointees this operation changes only the data pointer,
     /// leaving the metadata untouched.
-    #[cfg(not(bootstrap))]
     #[unstable(feature = "ptr_mask", issue = "98290")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
     #[inline(always)]
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 460f3df5fee..543ab826c4e 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -103,8 +103,8 @@ impl<T: ?Sized> *mut T {
     /// coercion.
     ///
     /// [`cast_mut`]: #method.cast_mut
-    #[stable(feature = "ptr_const_cast", since = "CURRENT_RUSTC_VERSION")]
-    #[rustc_const_stable(feature = "ptr_const_cast", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "ptr_const_cast", since = "1.65.0")]
+    #[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")]
     pub const fn cast_const(self) -> *const T {
         self as _
     }
@@ -584,7 +584,6 @@ impl<T: ?Sized> *mut T {
     ///
     /// For non-`Sized` pointees this operation changes only the data pointer,
     /// leaving the metadata untouched.
-    #[cfg(not(bootstrap))]
     #[unstable(feature = "ptr_mask", issue = "98290")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
     #[inline(always)]
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs
index 395c5678451..ad39ce38319 100644
--- a/library/core/src/slice/iter.rs
+++ b/library/core/src/slice/iter.rs
@@ -9,7 +9,7 @@ use crate::fmt;
 use crate::intrinsics::{assume, exact_div, unchecked_sub};
 use crate::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce};
 use crate::marker::{PhantomData, Send, Sized, Sync};
-use crate::mem;
+use crate::mem::{self, SizedTypeProperties};
 use crate::num::NonZeroUsize;
 use crate::ptr::NonNull;
 
@@ -91,11 +91,8 @@ impl<'a, T> Iter<'a, T> {
         unsafe {
             assume(!ptr.is_null());
 
-            let end = if mem::size_of::<T>() == 0 {
-                ptr.wrapping_byte_add(slice.len())
-            } else {
-                ptr.add(slice.len())
-            };
+            let end =
+                if T::IS_ZST { ptr.wrapping_byte_add(slice.len()) } else { ptr.add(slice.len()) };
 
             Self { ptr: NonNull::new_unchecked(ptr as *mut T), end, _marker: PhantomData }
         }
@@ -227,11 +224,8 @@ impl<'a, T> IterMut<'a, T> {
         unsafe {
             assume(!ptr.is_null());
 
-            let end = if mem::size_of::<T>() == 0 {
-                ptr.wrapping_byte_add(slice.len())
-            } else {
-                ptr.add(slice.len())
-            };
+            let end =
+                if T::IS_ZST { ptr.wrapping_byte_add(slice.len()) } else { ptr.add(slice.len()) };
 
             Self { ptr: NonNull::new_unchecked(ptr), end, _marker: PhantomData }
         }
diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs
index 6c9e7574e17..ce51d48e3e5 100644
--- a/library/core/src/slice/iter/macros.rs
+++ b/library/core/src/slice/iter/macros.rs
@@ -100,7 +100,7 @@ macro_rules! iterator {
             // Unsafe because the offset must not exceed `self.len()`.
             #[inline(always)]
             unsafe fn pre_dec_end(&mut self, offset: usize) -> * $raw_mut T {
-                if mem::size_of::<T>() == 0 {
+                if T::IS_ZST {
                     zst_shrink!(self, offset);
                     self.ptr.as_ptr()
                 } else {
@@ -140,7 +140,7 @@ macro_rules! iterator {
                 // since we check if the iterator is empty first.
                 unsafe {
                     assume(!self.ptr.as_ptr().is_null());
-                    if mem::size_of::<T>() != 0 {
+                    if !<T>::IS_ZST {
                         assume(!self.end.is_null());
                     }
                     if is_empty!(self) {
@@ -166,7 +166,7 @@ macro_rules! iterator {
             fn nth(&mut self, n: usize) -> Option<$elem> {
                 if n >= len!(self) {
                     // This iterator is now empty.
-                    if mem::size_of::<T>() == 0 {
+                    if T::IS_ZST {
                         // We have to do it this way as `ptr` may never be 0, but `end`
                         // could be (due to wrapping).
                         self.end = self.ptr.as_ptr();
@@ -355,7 +355,7 @@ macro_rules! iterator {
                 // empty first.
                 unsafe {
                     assume(!self.ptr.as_ptr().is_null());
-                    if mem::size_of::<T>() != 0 {
+                    if !<T>::IS_ZST {
                         assume(!self.end.is_null());
                     }
                     if is_empty!(self) {
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index ff601137ff6..aed8fbf092e 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -9,7 +9,7 @@
 use crate::cmp::Ordering::{self, Greater, Less};
 use crate::intrinsics::{assert_unsafe_precondition, exact_div};
 use crate::marker::Copy;
-use crate::mem;
+use crate::mem::{self, SizedTypeProperties};
 use crate::num::NonZeroUsize;
 use crate::ops::{Bound, FnMut, OneSidedRange, Range, RangeBounds};
 use crate::option::Option;
@@ -1580,7 +1580,8 @@ impl<T> [T] {
     #[inline]
     #[track_caller]
     #[must_use]
-    pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
+    #[rustc_const_unstable(feature = "const_slice_split_at_mut", issue = "101804")]
+    pub const fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
         assert!(mid <= self.len());
         // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which
         // fulfills the requirements of `from_raw_parts_mut`.
@@ -1679,9 +1680,10 @@ impl<T> [T] {
     /// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
     /// ```
     #[unstable(feature = "slice_split_at_unchecked", reason = "new API", issue = "76014")]
+    #[rustc_const_unstable(feature = "const_slice_split_at_mut", issue = "101804")]
     #[inline]
     #[must_use]
-    pub unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
+    pub const unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
         let len = self.len();
         let ptr = self.as_mut_ptr();
 
@@ -2074,7 +2076,7 @@ impl<T> [T] {
         SplitN::new(self.split(pred), n)
     }
 
-    /// Returns an iterator over subslices separated by elements that match
+    /// Returns an iterator over mutable subslices separated by elements that match
     /// `pred`, limited to returning at most `n` items. The matched element is
     /// not contained in the subslices.
     ///
@@ -2643,9 +2645,10 @@ impl<T> [T] {
     /// less than or equal to any value at a position `j > index`. Additionally, this reordering is
     /// unstable (i.e. any number of equal elements may end up at position `index`), in-place
     /// (i.e. does not allocate), and *O*(*n*) worst-case. This function is also/ known as "kth
-    /// element" in other libraries. It returns a triplet of the following values: all elements less
-    /// than the one at the given index, the value at the given index, and all elements greater than
-    /// the one at the given index.
+    /// element" in other libraries. It returns a triplet of the following from the reordered slice:
+    /// the subslice prior to `index`, the element at `index`, and the subslice after `index`;
+    /// accordingly, the values in those two subslices will respectively all be less-than-or-equal-to
+    /// and greater-than-or-equal-to the value of the element at `index`.
     ///
     /// # Current implementation
     ///
@@ -2689,10 +2692,11 @@ impl<T> [T] {
     /// less than or equal to any value at a position `j > index` using the comparator function.
     /// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at
     /// position `index`), in-place (i.e. does not allocate), and *O*(*n*) worst-case. This function
-    /// is also known as "kth element" in other libraries. It returns a triplet of the following
-    /// values: all elements less than the one at the given index, the value at the given index,
-    /// and all elements greater than the one at the given index, using the provided comparator
-    /// function.
+    /// is also known as "kth element" in other libraries. It returns a triplet of the following from
+    /// the slice reordered according to the provided comparator function: the subslice prior to
+    /// `index`, the element at `index`, and the subslice after `index`; accordingly, the values in
+    /// those two subslices will respectively all be less-than-or-equal-to and greater-than-or-equal-to
+    /// the value of the element at `index`.
     ///
     /// # Current implementation
     ///
@@ -2740,10 +2744,11 @@ impl<T> [T] {
     /// less than or equal to any value at a position `j > index` using the key extraction function.
     /// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at
     /// position `index`), in-place (i.e. does not allocate), and *O*(*n*) worst-case. This function
-    /// is also known as "kth element" in other libraries. It returns a triplet of the following
-    /// values: all elements less than the one at the given index, the value at the given index, and
-    /// all elements greater than the one at the given index, using the provided key extraction
-    /// function.
+    /// is also known as "kth element" in other libraries. It returns a triplet of the following from
+    /// the slice reordered according to the provided key extraction function: the subslice prior to
+    /// `index`, the element at `index`, and the subslice after `index`; accordingly, the values in
+    /// those two subslices will respectively all be less-than-or-equal-to and greater-than-or-equal-to
+    /// the value of the element at `index`.
     ///
     /// # Current implementation
     ///
@@ -3456,7 +3461,7 @@ impl<T> [T] {
     #[must_use]
     pub unsafe fn align_to<U>(&self) -> (&[T], &[U], &[T]) {
         // Note that most of this function will be constant-evaluated,
-        if mem::size_of::<U>() == 0 || mem::size_of::<T>() == 0 {
+        if U::IS_ZST || T::IS_ZST {
             // handle ZSTs specially, which is – don't handle them at all.
             return (self, &[], &[]);
         }
@@ -3517,7 +3522,7 @@ impl<T> [T] {
     #[must_use]
     pub unsafe fn align_to_mut<U>(&mut self) -> (&mut [T], &mut [U], &mut [T]) {
         // Note that most of this function will be constant-evaluated,
-        if mem::size_of::<U>() == 0 || mem::size_of::<T>() == 0 {
+        if U::IS_ZST || T::IS_ZST {
             // handle ZSTs specially, which is – don't handle them at all.
             return (self, &mut [], &mut []);
         }
@@ -4063,7 +4068,7 @@ impl<T, const N: usize> [[T; N]] {
     /// ```
     #[unstable(feature = "slice_flatten", issue = "95629")]
     pub fn flatten(&self) -> &[T] {
-        let len = if crate::mem::size_of::<T>() == 0 {
+        let len = if T::IS_ZST {
             self.len().checked_mul(N).expect("slice len overflow")
         } else {
             // SAFETY: `self.len() * N` cannot overflow because `self` is
@@ -4101,7 +4106,7 @@ impl<T, const N: usize> [[T; N]] {
     /// ```
     #[unstable(feature = "slice_flatten", issue = "95629")]
     pub fn flatten_mut(&mut self) -> &mut [T] {
-        let len = if crate::mem::size_of::<T>() == 0 {
+        let len = if T::IS_ZST {
             self.len().checked_mul(N).expect("slice len overflow")
         } else {
             // SAFETY: `self.len() * N` cannot overflow because `self` is
diff --git a/library/core/src/slice/rotate.rs b/library/core/src/slice/rotate.rs
index 4589c6c0f04..fa8c238f8e7 100644
--- a/library/core/src/slice/rotate.rs
+++ b/library/core/src/slice/rotate.rs
@@ -1,5 +1,5 @@
 use crate::cmp;
-use crate::mem::{self, MaybeUninit};
+use crate::mem::{self, MaybeUninit, SizedTypeProperties};
 use crate::ptr;
 
 /// Rotates the range `[mid-left, mid+right)` such that the element at `mid` becomes the first
@@ -63,7 +63,7 @@ use crate::ptr;
 /// when `left < right` the swapping happens from the left instead.
 pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize) {
     type BufType = [usize; 32];
-    if mem::size_of::<T>() == 0 {
+    if T::IS_ZST {
         return;
     }
     loop {
diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs
index c6c03c0b0db..87f77b7f21d 100644
--- a/library/core/src/slice/sort.rs
+++ b/library/core/src/slice/sort.rs
@@ -7,7 +7,7 @@
 //! stable sorting implementation.
 
 use crate::cmp;
-use crate::mem::{self, MaybeUninit};
+use crate::mem::{self, MaybeUninit, SizedTypeProperties};
 use crate::ptr;
 
 /// When dropped, copies from `src` into `dest`.
@@ -813,7 +813,7 @@ where
     F: FnMut(&T, &T) -> bool,
 {
     // Sorting has no meaningful behavior on zero-sized types.
-    if mem::size_of::<T>() == 0 {
+    if T::IS_ZST {
         return;
     }
 
@@ -898,7 +898,7 @@ where
         panic!("partition_at_index index {} greater than length of slice {}", index, v.len());
     }
 
-    if mem::size_of::<T>() == 0 {
+    if T::IS_ZST {
         // Sorting has no meaningful behavior on zero-sized types. Do nothing.
     } else if index == v.len() - 1 {
         // Find max element and place it in the last position of the array. We're free to use
diff --git a/library/core/src/str/error.rs b/library/core/src/str/error.rs
index 343889b6999..a11b5add42e 100644
--- a/library/core/src/str/error.rs
+++ b/library/core/src/str/error.rs
@@ -1,6 +1,5 @@
 //! Defines utf8 error type.
 
-#[cfg(not(bootstrap))]
 use crate::error::Error;
 use crate::fmt;
 
@@ -124,7 +123,6 @@ impl fmt::Display for Utf8Error {
     }
 }
 
-#[cfg(not(bootstrap))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Error for Utf8Error {
     #[allow(deprecated)]
@@ -148,7 +146,6 @@ impl fmt::Display for ParseBoolError {
     }
 }
 
-#[cfg(not(bootstrap))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Error for ParseBoolError {
     #[allow(deprecated)]
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index f673aa2a44b..fbc0fc397a5 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -2642,5 +2642,4 @@ impl_fn_for_zst! {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg(not(bootstrap))]
 impl !crate::error::Error for &str {}
diff --git a/library/core/src/time.rs b/library/core/src/time.rs
index 4f29ecc0fba..2b85d6e2225 100644
--- a/library/core/src/time.rs
+++ b/library/core/src/time.rs
@@ -29,6 +29,20 @@ const NANOS_PER_MICRO: u32 = 1_000;
 const MILLIS_PER_SEC: u64 = 1_000;
 const MICROS_PER_SEC: u64 = 1_000_000;
 
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[repr(transparent)]
+#[rustc_layout_scalar_valid_range_start(0)]
+#[rustc_layout_scalar_valid_range_end(999_999_999)]
+struct Nanoseconds(u32);
+
+impl Default for Nanoseconds {
+    #[inline]
+    fn default() -> Self {
+        // SAFETY: 0 is within the valid range
+        unsafe { Nanoseconds(0) }
+    }
+}
+
 /// A `Duration` type to represent a span of time, typically used for system
 /// timeouts.
 ///
@@ -71,7 +85,7 @@ const MICROS_PER_SEC: u64 = 1_000_000;
 #[cfg_attr(not(test), rustc_diagnostic_item = "Duration")]
 pub struct Duration {
     secs: u64,
-    nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC
+    nanos: Nanoseconds, // Always 0 <= nanos < NANOS_PER_SEC
 }
 
 impl Duration {
@@ -188,7 +202,8 @@ impl Duration {
             None => panic!("overflow in Duration::new"),
         };
         let nanos = nanos % NANOS_PER_SEC;
-        Duration { secs, nanos }
+        // SAFETY: nanos % NANOS_PER_SEC < NANOS_PER_SEC, therefore nanos is within the valid range
+        Duration { secs, nanos: unsafe { Nanoseconds(nanos) } }
     }
 
     /// Creates a new `Duration` from the specified number of whole seconds.
@@ -208,7 +223,7 @@ impl Duration {
     #[inline]
     #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
     pub const fn from_secs(secs: u64) -> Duration {
-        Duration { secs, nanos: 0 }
+        Duration::new(secs, 0)
     }
 
     /// Creates a new `Duration` from the specified number of milliseconds.
@@ -228,10 +243,7 @@ impl Duration {
     #[inline]
     #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
     pub const fn from_millis(millis: u64) -> Duration {
-        Duration {
-            secs: millis / MILLIS_PER_SEC,
-            nanos: ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI,
-        }
+        Duration::new(millis / MILLIS_PER_SEC, ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI)
     }
 
     /// Creates a new `Duration` from the specified number of microseconds.
@@ -251,10 +263,7 @@ impl Duration {
     #[inline]
     #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
     pub const fn from_micros(micros: u64) -> Duration {
-        Duration {
-            secs: micros / MICROS_PER_SEC,
-            nanos: ((micros % MICROS_PER_SEC) as u32) * NANOS_PER_MICRO,
-        }
+        Duration::new(micros / MICROS_PER_SEC, ((micros % MICROS_PER_SEC) as u32) * NANOS_PER_MICRO)
     }
 
     /// Creates a new `Duration` from the specified number of nanoseconds.
@@ -274,10 +283,7 @@ impl Duration {
     #[inline]
     #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
     pub const fn from_nanos(nanos: u64) -> Duration {
-        Duration {
-            secs: nanos / (NANOS_PER_SEC as u64),
-            nanos: (nanos % (NANOS_PER_SEC as u64)) as u32,
-        }
+        Duration::new(nanos / (NANOS_PER_SEC as u64), (nanos % (NANOS_PER_SEC as u64)) as u32)
     }
 
     /// Returns true if this `Duration` spans no time.
@@ -301,7 +307,7 @@ impl Duration {
     #[rustc_const_stable(feature = "duration_zero", since = "1.53.0")]
     #[inline]
     pub const fn is_zero(&self) -> bool {
-        self.secs == 0 && self.nanos == 0
+        self.secs == 0 && self.nanos.0 == 0
     }
 
     /// Returns the number of _whole_ seconds contained by this `Duration`.
@@ -352,7 +358,7 @@ impl Duration {
     #[must_use]
     #[inline]
     pub const fn subsec_millis(&self) -> u32 {
-        self.nanos / NANOS_PER_MILLI
+        self.nanos.0 / NANOS_PER_MILLI
     }
 
     /// Returns the fractional part of this `Duration`, in whole microseconds.
@@ -375,7 +381,7 @@ impl Duration {
     #[must_use]
     #[inline]
     pub const fn subsec_micros(&self) -> u32 {
-        self.nanos / NANOS_PER_MICRO
+        self.nanos.0 / NANOS_PER_MICRO
     }
 
     /// Returns the fractional part of this `Duration`, in nanoseconds.
@@ -398,7 +404,7 @@ impl Duration {
     #[must_use]
     #[inline]
     pub const fn subsec_nanos(&self) -> u32 {
-        self.nanos
+        self.nanos.0
     }
 
     /// Returns the total number of whole milliseconds contained by this `Duration`.
@@ -416,7 +422,7 @@ impl Duration {
     #[must_use]
     #[inline]
     pub const fn as_millis(&self) -> u128 {
-        self.secs as u128 * MILLIS_PER_SEC as u128 + (self.nanos / NANOS_PER_MILLI) as u128
+        self.secs as u128 * MILLIS_PER_SEC as u128 + (self.nanos.0 / NANOS_PER_MILLI) as u128
     }
 
     /// Returns the total number of whole microseconds contained by this `Duration`.
@@ -434,7 +440,7 @@ impl Duration {
     #[must_use]
     #[inline]
     pub const fn as_micros(&self) -> u128 {
-        self.secs as u128 * MICROS_PER_SEC as u128 + (self.nanos / NANOS_PER_MICRO) as u128
+        self.secs as u128 * MICROS_PER_SEC as u128 + (self.nanos.0 / NANOS_PER_MICRO) as u128
     }
 
     /// Returns the total number of nanoseconds contained by this `Duration`.
@@ -452,7 +458,7 @@ impl Duration {
     #[must_use]
     #[inline]
     pub const fn as_nanos(&self) -> u128 {
-        self.secs as u128 * NANOS_PER_SEC as u128 + self.nanos as u128
+        self.secs as u128 * NANOS_PER_SEC as u128 + self.nanos.0 as u128
     }
 
     /// Checked `Duration` addition. Computes `self + other`, returning [`None`]
@@ -475,7 +481,7 @@ impl Duration {
     #[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")]
     pub const fn checked_add(self, rhs: Duration) -> Option<Duration> {
         if let Some(mut secs) = self.secs.checked_add(rhs.secs) {
-            let mut nanos = self.nanos + rhs.nanos;
+            let mut nanos = self.nanos.0 + rhs.nanos.0;
             if nanos >= NANOS_PER_SEC {
                 nanos -= NANOS_PER_SEC;
                 if let Some(new_secs) = secs.checked_add(1) {
@@ -485,7 +491,7 @@ impl Duration {
                 }
             }
             debug_assert!(nanos < NANOS_PER_SEC);
-            Some(Duration { secs, nanos })
+            Some(Duration::new(secs, nanos))
         } else {
             None
         }
@@ -535,16 +541,16 @@ impl Duration {
     #[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")]
     pub const fn checked_sub(self, rhs: Duration) -> Option<Duration> {
         if let Some(mut secs) = self.secs.checked_sub(rhs.secs) {
-            let nanos = if self.nanos >= rhs.nanos {
-                self.nanos - rhs.nanos
+            let nanos = if self.nanos.0 >= rhs.nanos.0 {
+                self.nanos.0 - rhs.nanos.0
             } else if let Some(sub_secs) = secs.checked_sub(1) {
                 secs = sub_secs;
-                self.nanos + NANOS_PER_SEC - rhs.nanos
+                self.nanos.0 + NANOS_PER_SEC - rhs.nanos.0
             } else {
                 return None;
             };
             debug_assert!(nanos < NANOS_PER_SEC);
-            Some(Duration { secs, nanos })
+            Some(Duration::new(secs, nanos))
         } else {
             None
         }
@@ -593,13 +599,13 @@ impl Duration {
     #[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")]
     pub const fn checked_mul(self, rhs: u32) -> Option<Duration> {
         // Multiply nanoseconds as u64, because it cannot overflow that way.
-        let total_nanos = self.nanos as u64 * rhs as u64;
+        let total_nanos = self.nanos.0 as u64 * rhs as u64;
         let extra_secs = total_nanos / (NANOS_PER_SEC as u64);
         let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32;
         if let Some(s) = self.secs.checked_mul(rhs as u64) {
             if let Some(secs) = s.checked_add(extra_secs) {
                 debug_assert!(nanos < NANOS_PER_SEC);
-                return Some(Duration { secs, nanos });
+                return Some(Duration::new(secs, nanos));
             }
         }
         None
@@ -653,9 +659,9 @@ impl Duration {
             let secs = self.secs / (rhs as u64);
             let carry = self.secs - secs * (rhs as u64);
             let extra_nanos = carry * (NANOS_PER_SEC as u64) / (rhs as u64);
-            let nanos = self.nanos / rhs + (extra_nanos as u32);
+            let nanos = self.nanos.0 / rhs + (extra_nanos as u32);
             debug_assert!(nanos < NANOS_PER_SEC);
-            Some(Duration { secs, nanos })
+            Some(Duration::new(secs, nanos))
         } else {
             None
         }
@@ -677,7 +683,7 @@ impl Duration {
     #[inline]
     #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
     pub const fn as_secs_f64(&self) -> f64 {
-        (self.secs as f64) + (self.nanos as f64) / (NANOS_PER_SEC as f64)
+        (self.secs as f64) + (self.nanos.0 as f64) / (NANOS_PER_SEC as f64)
     }
 
     /// Returns the number of seconds contained by this `Duration` as `f32`.
@@ -696,7 +702,7 @@ impl Duration {
     #[inline]
     #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
     pub const fn as_secs_f32(&self) -> f32 {
-        (self.secs as f32) + (self.nanos as f32) / (NANOS_PER_SEC as f32)
+        (self.secs as f32) + (self.nanos.0 as f32) / (NANOS_PER_SEC as f32)
     }
 
     /// Creates a new `Duration` from the specified number of seconds represented
@@ -987,13 +993,13 @@ macro_rules! sum_durations {
         for entry in $iter {
             total_secs =
                 total_secs.checked_add(entry.secs).expect("overflow in iter::sum over durations");
-            total_nanos = match total_nanos.checked_add(entry.nanos as u64) {
+            total_nanos = match total_nanos.checked_add(entry.nanos.0 as u64) {
                 Some(n) => n,
                 None => {
                     total_secs = total_secs
                         .checked_add(total_nanos / NANOS_PER_SEC as u64)
                         .expect("overflow in iter::sum over durations");
-                    (total_nanos % NANOS_PER_SEC as u64) + entry.nanos as u64
+                    (total_nanos % NANOS_PER_SEC as u64) + entry.nanos.0 as u64
                 }
             };
         }
@@ -1001,7 +1007,7 @@ macro_rules! sum_durations {
             .checked_add(total_nanos / NANOS_PER_SEC as u64)
             .expect("overflow in iter::sum over durations");
         total_nanos = total_nanos % NANOS_PER_SEC as u64;
-        Duration { secs: total_secs, nanos: total_nanos as u32 }
+        Duration::new(total_secs, total_nanos as u32)
     }};
 }
 
@@ -1166,27 +1172,27 @@ impl fmt::Debug for Duration {
         let prefix = if f.sign_plus() { "+" } else { "" };
 
         if self.secs > 0 {
-            fmt_decimal(f, self.secs, self.nanos, NANOS_PER_SEC / 10, prefix, "s")
-        } else if self.nanos >= NANOS_PER_MILLI {
+            fmt_decimal(f, self.secs, self.nanos.0, NANOS_PER_SEC / 10, prefix, "s")
+        } else if self.nanos.0 >= NANOS_PER_MILLI {
             fmt_decimal(
                 f,
-                (self.nanos / NANOS_PER_MILLI) as u64,
-                self.nanos % NANOS_PER_MILLI,
+                (self.nanos.0 / NANOS_PER_MILLI) as u64,
+                self.nanos.0 % NANOS_PER_MILLI,
                 NANOS_PER_MILLI / 10,
                 prefix,
                 "ms",
             )
-        } else if self.nanos >= NANOS_PER_MICRO {
+        } else if self.nanos.0 >= NANOS_PER_MICRO {
             fmt_decimal(
                 f,
-                (self.nanos / NANOS_PER_MICRO) as u64,
-                self.nanos % NANOS_PER_MICRO,
+                (self.nanos.0 / NANOS_PER_MICRO) as u64,
+                self.nanos.0 % NANOS_PER_MICRO,
                 NANOS_PER_MICRO / 10,
                 prefix,
                 "µs",
             )
         } else {
-            fmt_decimal(f, self.nanos as u64, 0, 1, prefix, "ns")
+            fmt_decimal(f, self.nanos.0 as u64, 0, 1, prefix, "ns")
         }
     }
 }
@@ -1317,7 +1323,7 @@ macro_rules! try_from_secs {
             return Err(FromFloatSecsError { kind: FromFloatSecsErrorKind::OverflowOrNan });
         };
 
-        Ok(Duration { secs, nanos })
+        Ok(Duration::new(secs, nanos))
     }};
 }
 
diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs
index aa8a2425bf4..fc91fe468cc 100644
--- a/library/core/src/tuple.rs
+++ b/library/core/src/tuple.rs
@@ -93,7 +93,8 @@ macro_rules! tuple_impls {
         maybe_tuple_doc! {
             $($T)+ @
             #[stable(feature = "rust1", since = "1.0.0")]
-            impl<$($T:Default),+> Default for ($($T,)+) {
+            #[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
+            impl<$($T: ~const Default),+> const Default for ($($T,)+) {
                 #[inline]
                 fn default() -> ($($T,)+) {
                     ($({ let x: $T = Default::default(); x},)+)
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 46f603eaeba..6d58ed9743d 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -2,7 +2,6 @@
 #![feature(array_chunks)]
 #![feature(array_methods)]
 #![feature(array_windows)]
-#![feature(bench_black_box)]
 #![feature(bigint_helper_methods)]
 #![feature(cell_update)]
 #![feature(const_assume)]
diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs
index 354200d4c95..5cf6ec81789 100644
--- a/library/std/src/backtrace.rs
+++ b/library/std/src/backtrace.rs
@@ -58,7 +58,7 @@
 //! `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` at runtime might not actually change
 //! how backtraces are captured.
 
-#![stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
+#![stable(feature = "backtrace", since = "1.65.0")]
 
 #[cfg(test)]
 mod tests;
@@ -104,7 +104,7 @@ use crate::vec::Vec;
 /// previous point in time. In some instances the `Backtrace` type may
 /// internally be empty due to configuration. For more information see
 /// `Backtrace::capture`.
-#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
+#[stable(feature = "backtrace", since = "1.65.0")]
 #[must_use]
 pub struct Backtrace {
     inner: Inner,
@@ -112,21 +112,21 @@ pub struct Backtrace {
 
 /// The current status of a backtrace, indicating whether it was captured or
 /// whether it is empty for some other reason.
-#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
+#[stable(feature = "backtrace", since = "1.65.0")]
 #[non_exhaustive]
 #[derive(Debug, PartialEq, Eq)]
 pub enum BacktraceStatus {
     /// Capturing a backtrace is not supported, likely because it's not
     /// implemented for the current platform.
-    #[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "backtrace", since = "1.65.0")]
     Unsupported,
     /// Capturing a backtrace has been disabled through either the
     /// `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` environment variables.
-    #[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "backtrace", since = "1.65.0")]
     Disabled,
     /// A backtrace has been captured and the `Backtrace` should print
     /// reasonable information when rendered.
-    #[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "backtrace", since = "1.65.0")]
     Captured,
 }
 
@@ -173,7 +173,7 @@ enum BytesOrWide {
     Wide(Vec<u16>),
 }
 
-#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
+#[stable(feature = "backtrace", since = "1.65.0")]
 impl fmt::Debug for Backtrace {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         let capture = match &self.inner {
@@ -289,7 +289,7 @@ impl Backtrace {
     ///
     /// To forcibly capture a backtrace regardless of environment variables, use
     /// the `Backtrace::force_capture` function.
-    #[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "backtrace", since = "1.65.0")]
     #[inline(never)] // want to make sure there's a frame here to remove
     pub fn capture() -> Backtrace {
         if !Backtrace::enabled() {
@@ -308,7 +308,7 @@ impl Backtrace {
     /// Note that capturing a backtrace can be an expensive operation on some
     /// platforms, so this should be used with caution in performance-sensitive
     /// parts of code.
-    #[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "backtrace", since = "1.65.0")]
     #[inline(never)] // want to make sure there's a frame here to remove
     pub fn force_capture() -> Backtrace {
         Backtrace::create(Backtrace::force_capture as usize)
@@ -316,8 +316,8 @@ impl Backtrace {
 
     /// Forcibly captures a disabled backtrace, regardless of environment
     /// variable configuration.
-    #[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
-    #[rustc_const_stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "backtrace", since = "1.65.0")]
+    #[rustc_const_stable(feature = "backtrace", since = "1.65.0")]
     pub const fn disabled() -> Backtrace {
         Backtrace { inner: Inner::Disabled }
     }
@@ -361,7 +361,7 @@ impl Backtrace {
     /// Returns the status of this backtrace, indicating whether this backtrace
     /// request was unsupported, disabled, or a stack trace was actually
     /// captured.
-    #[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
+    #[stable(feature = "backtrace", since = "1.65.0")]
     #[must_use]
     pub fn status(&self) -> BacktraceStatus {
         match self.inner {
@@ -381,7 +381,7 @@ impl<'a> Backtrace {
     }
 }
 
-#[stable(feature = "backtrace", since = "CURRENT_RUSTC_VERSION")]
+#[stable(feature = "backtrace", since = "1.65.0")]
 impl fmt::Display for Backtrace {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         let capture = match &self.inner {
diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs
index 9845d1faf9a..d2db4bb7a46 100644
--- a/library/std/src/collections/hash/map.rs
+++ b/library/std/src/collections/hash/map.rs
@@ -9,7 +9,6 @@ use crate::borrow::Borrow;
 use crate::cell::Cell;
 use crate::collections::TryReserveError;
 use crate::collections::TryReserveErrorKind;
-#[cfg(not(bootstrap))]
 use crate::error::Error;
 use crate::fmt::{self, Debug};
 #[allow(deprecated)]
@@ -2160,7 +2159,6 @@ impl<'a, K: Debug, V: Debug> fmt::Display for OccupiedError<'a, K, V> {
     }
 }
 
-#[cfg(not(bootstrap))]
 #[unstable(feature = "map_try_insert", issue = "82766")]
 impl<'a, K: fmt::Debug, V: fmt::Debug> Error for OccupiedError<'a, K, V> {
     #[allow(deprecated)]
diff --git a/library/std/src/env.rs b/library/std/src/env.rs
index 463f714064c..6eb7cbea626 100644
--- a/library/std/src/env.rs
+++ b/library/std/src/env.rs
@@ -603,7 +603,7 @@ pub fn home_dir() -> Option<PathBuf> {
 /// # Platform-specific behavior
 ///
 /// On Unix, returns the value of the `TMPDIR` environment variable if it is
-/// set, otherwise for non-Android it returns `/tmp`. If Android, since there
+/// set, otherwise for non-Android it returns `/tmp`. On Android, since there
 /// is no global temporary folder (it is usually allocated per-app), it returns
 /// `/data/local/tmp`.
 /// On Windows, the behavior is equivalent to that of [`GetTempPath2`][GetTempPath2] /
diff --git a/library/std/src/error.rs b/library/std/src/error.rs
index e4505959536..05f8fd8de32 100644
--- a/library/std/src/error.rs
+++ b/library/std/src/error.rs
@@ -4,242 +4,12 @@
 #[cfg(test)]
 mod tests;
 
-#[cfg(bootstrap)]
-use core::array;
-#[cfg(bootstrap)]
-use core::convert::Infallible;
-
-#[cfg(bootstrap)]
-use crate::alloc::{AllocError, LayoutError};
-#[cfg(bootstrap)]
-use crate::any::Demand;
-#[cfg(bootstrap)]
-use crate::any::{Provider, TypeId};
 use crate::backtrace::Backtrace;
-#[cfg(bootstrap)]
-use crate::borrow::Cow;
-#[cfg(bootstrap)]
-use crate::cell;
-#[cfg(bootstrap)]
-use crate::char;
-#[cfg(bootstrap)]
-use crate::fmt::Debug;
-#[cfg(bootstrap)]
-use crate::fmt::Display;
 use crate::fmt::{self, Write};
-#[cfg(bootstrap)]
-use crate::io;
-#[cfg(bootstrap)]
-use crate::mem::transmute;
-#[cfg(bootstrap)]
-use crate::num;
-#[cfg(bootstrap)]
-use crate::str;
-#[cfg(bootstrap)]
-use crate::string;
-#[cfg(bootstrap)]
-use crate::sync::Arc;
-#[cfg(bootstrap)]
-use crate::time;
 
-#[cfg(not(bootstrap))]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::error::Error;
 
-/// `Error` is a trait representing the basic expectations for error values,
-/// i.e., values of type `E` in [`Result<T, E>`].
-///
-/// Errors must describe themselves through the [`Display`] and [`Debug`]
-/// traits. Error messages are typically concise lowercase sentences without
-/// trailing punctuation:
-///
-/// ```
-/// let err = "NaN".parse::<u32>().unwrap_err();
-/// assert_eq!(err.to_string(), "invalid digit found in string");
-/// ```
-///
-/// Errors may provide cause information. [`Error::source()`] is generally
-/// used when errors cross "abstraction boundaries". If one module must report
-/// an error that is caused by an error from a lower-level module, it can allow
-/// accessing that error via [`Error::source()`]. This makes it possible for the
-/// high-level module to provide its own errors while also revealing some of the
-/// implementation for debugging.
-#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(test), rustc_diagnostic_item = "Error")]
-#[cfg(bootstrap)]
-pub trait Error: Debug + Display {
-    /// The lower-level source of this error, if any.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::error::Error;
-    /// use std::fmt;
-    ///
-    /// #[derive(Debug)]
-    /// struct SuperError {
-    ///     source: SuperErrorSideKick,
-    /// }
-    ///
-    /// impl fmt::Display for SuperError {
-    ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-    ///         write!(f, "SuperError is here!")
-    ///     }
-    /// }
-    ///
-    /// impl Error for SuperError {
-    ///     fn source(&self) -> Option<&(dyn Error + 'static)> {
-    ///         Some(&self.source)
-    ///     }
-    /// }
-    ///
-    /// #[derive(Debug)]
-    /// struct SuperErrorSideKick;
-    ///
-    /// impl fmt::Display for SuperErrorSideKick {
-    ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-    ///         write!(f, "SuperErrorSideKick is here!")
-    ///     }
-    /// }
-    ///
-    /// impl Error for SuperErrorSideKick {}
-    ///
-    /// fn get_super_error() -> Result<(), SuperError> {
-    ///     Err(SuperError { source: SuperErrorSideKick })
-    /// }
-    ///
-    /// fn main() {
-    ///     match get_super_error() {
-    ///         Err(e) => {
-    ///             println!("Error: {e}");
-    ///             println!("Caused by: {}", e.source().unwrap());
-    ///         }
-    ///         _ => println!("No error"),
-    ///     }
-    /// }
-    /// ```
-    #[stable(feature = "error_source", since = "1.30.0")]
-    fn source(&self) -> Option<&(dyn Error + 'static)> {
-        None
-    }
-
-    /// Gets the `TypeId` of `self`.
-    #[doc(hidden)]
-    #[unstable(
-        feature = "error_type_id",
-        reason = "this is memory-unsafe to override in user code",
-        issue = "60784"
-    )]
-    fn type_id(&self, _: private::Internal) -> TypeId
-    where
-        Self: 'static,
-    {
-        TypeId::of::<Self>()
-    }
-
-    /// ```
-    /// if let Err(e) = "xc".parse::<u32>() {
-    ///     // Print `e` itself, no need for description().
-    ///     eprintln!("Error: {e}");
-    /// }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[deprecated(since = "1.42.0", note = "use the Display impl or to_string()")]
-    fn description(&self) -> &str {
-        "description() is deprecated; use Display"
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[deprecated(
-        since = "1.33.0",
-        note = "replaced by Error::source, which can support downcasting"
-    )]
-    #[allow(missing_docs)]
-    fn cause(&self) -> Option<&dyn Error> {
-        self.source()
-    }
-
-    /// Provides type based access to context intended for error reports.
-    ///
-    /// Used in conjunction with [`Demand::provide_value`] and [`Demand::provide_ref`] to extract
-    /// references to member variables from `dyn Error` trait objects.
-    ///
-    /// # Example
-    ///
-    /// ```rust
-    /// #![feature(provide_any)]
-    /// #![feature(error_generic_member_access)]
-    /// use core::fmt;
-    /// use core::any::Demand;
-    ///
-    /// #[derive(Debug)]
-    /// struct MyBacktrace {
-    ///     // ...
-    /// }
-    ///
-    /// impl MyBacktrace {
-    ///     fn new() -> MyBacktrace {
-    ///         // ...
-    ///         # MyBacktrace {}
-    ///     }
-    /// }
-    ///
-    /// #[derive(Debug)]
-    /// struct SourceError {
-    ///     // ...
-    /// }
-    ///
-    /// impl fmt::Display for SourceError {
-    ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-    ///         write!(f, "Example Source Error")
-    ///     }
-    /// }
-    ///
-    /// impl std::error::Error for SourceError {}
-    ///
-    /// #[derive(Debug)]
-    /// struct Error {
-    ///     source: SourceError,
-    ///     backtrace: MyBacktrace,
-    /// }
-    ///
-    /// impl fmt::Display for Error {
-    ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-    ///         write!(f, "Example Error")
-    ///     }
-    /// }
-    ///
-    /// impl std::error::Error for Error {
-    ///     fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
-    ///         demand
-    ///             .provide_ref::<MyBacktrace>(&self.backtrace)
-    ///             .provide_ref::<dyn std::error::Error + 'static>(&self.source);
-    ///     }
-    /// }
-    ///
-    /// fn main() {
-    ///     let backtrace = MyBacktrace::new();
-    ///     let source = SourceError {};
-    ///     let error = Error { source, backtrace };
-    ///     let dyn_error = &error as &dyn std::error::Error;
-    ///     let backtrace_ref = dyn_error.request_ref::<MyBacktrace>().unwrap();
-    ///
-    ///     assert!(core::ptr::eq(&error.backtrace, backtrace_ref));
-    /// }
-    /// ```
-    #[unstable(feature = "error_generic_member_access", issue = "99301")]
-    #[allow(unused_variables)]
-    fn provide<'a>(&'a self, demand: &mut Demand<'a>) {}
-}
-
-#[cfg(bootstrap)]
-#[unstable(feature = "error_generic_member_access", issue = "99301")]
-impl<'b> Provider for dyn Error + 'b {
-    fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
-        self.provide(demand)
-    }
-}
-
 mod private {
     // This is a hack to prevent `type_id` from being overridden by `Error`
     // implementations, since that can enable unsound downcasting.
@@ -248,799 +18,6 @@ mod private {
     pub struct Internal;
 }
 
-#[cfg(bootstrap)]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a> {
-    /// Converts a type of [`Error`] into a box of dyn [`Error`].
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::error::Error;
-    /// use std::fmt;
-    /// use std::mem;
-    ///
-    /// #[derive(Debug)]
-    /// struct AnError;
-    ///
-    /// impl fmt::Display for AnError {
-    ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-    ///         write!(f, "An error")
-    ///     }
-    /// }
-    ///
-    /// impl Error for AnError {}
-    ///
-    /// let an_error = AnError;
-    /// assert!(0 == mem::size_of_val(&an_error));
-    /// let a_boxed_error = Box::<dyn Error>::from(an_error);
-    /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
-    /// ```
-    fn from(err: E) -> Box<dyn Error + 'a> {
-        Box::new(err)
-    }
-}
-
-#[cfg(bootstrap)]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync + 'a> {
-    /// Converts a type of [`Error`] + [`Send`] + [`Sync`] into a box of
-    /// dyn [`Error`] + [`Send`] + [`Sync`].
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::error::Error;
-    /// use std::fmt;
-    /// use std::mem;
-    ///
-    /// #[derive(Debug)]
-    /// struct AnError;
-    ///
-    /// impl fmt::Display for AnError {
-    ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-    ///         write!(f, "An error")
-    ///     }
-    /// }
-    ///
-    /// impl Error for AnError {}
-    ///
-    /// unsafe impl Send for AnError {}
-    ///
-    /// unsafe impl Sync for AnError {}
-    ///
-    /// let an_error = AnError;
-    /// assert!(0 == mem::size_of_val(&an_error));
-    /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(an_error);
-    /// assert!(
-    ///     mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
-    /// ```
-    fn from(err: E) -> Box<dyn Error + Send + Sync + 'a> {
-        Box::new(err)
-    }
-}
-
-#[cfg(bootstrap)]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl From<String> for Box<dyn Error + Send + Sync> {
-    /// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::error::Error;
-    /// use std::mem;
-    ///
-    /// let a_string_error = "a string error".to_string();
-    /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_string_error);
-    /// assert!(
-    ///     mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
-    /// ```
-    #[inline]
-    fn from(err: String) -> Box<dyn Error + Send + Sync> {
-        struct StringError(String);
-
-        impl Error for StringError {
-            #[allow(deprecated)]
-            fn description(&self) -> &str {
-                &self.0
-            }
-        }
-
-        impl Display for StringError {
-            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                Display::fmt(&self.0, f)
-            }
-        }
-
-        // Purposefully skip printing "StringError(..)"
-        impl Debug for StringError {
-            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                Debug::fmt(&self.0, f)
-            }
-        }
-
-        Box::new(StringError(err))
-    }
-}
-
-#[cfg(bootstrap)]
-#[stable(feature = "string_box_error", since = "1.6.0")]
-impl From<String> for Box<dyn Error> {
-    /// Converts a [`String`] into a box of dyn [`Error`].
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::error::Error;
-    /// use std::mem;
-    ///
-    /// let a_string_error = "a string error".to_string();
-    /// let a_boxed_error = Box::<dyn Error>::from(a_string_error);
-    /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
-    /// ```
-    fn from(str_err: String) -> Box<dyn Error> {
-        let err1: Box<dyn Error + Send + Sync> = From::from(str_err);
-        let err2: Box<dyn Error> = err1;
-        err2
-    }
-}
-
-#[cfg(bootstrap)]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> From<&str> for Box<dyn Error + Send + Sync + 'a> {
-    /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
-    ///
-    /// [`str`]: prim@str
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::error::Error;
-    /// use std::mem;
-    ///
-    /// let a_str_error = "a str error";
-    /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_str_error);
-    /// assert!(
-    ///     mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
-    /// ```
-    #[inline]
-    fn from(err: &str) -> Box<dyn Error + Send + Sync + 'a> {
-        From::from(String::from(err))
-    }
-}
-
-#[cfg(bootstrap)]
-#[stable(feature = "string_box_error", since = "1.6.0")]
-impl From<&str> for Box<dyn Error> {
-    /// Converts a [`str`] into a box of dyn [`Error`].
-    ///
-    /// [`str`]: prim@str
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::error::Error;
-    /// use std::mem;
-    ///
-    /// let a_str_error = "a str error";
-    /// let a_boxed_error = Box::<dyn Error>::from(a_str_error);
-    /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
-    /// ```
-    fn from(err: &str) -> Box<dyn Error> {
-        From::from(String::from(err))
-    }
-}
-
-#[cfg(bootstrap)]
-#[stable(feature = "cow_box_error", since = "1.22.0")]
-impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + Send + Sync + 'a> {
-    /// Converts a [`Cow`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::error::Error;
-    /// use std::mem;
-    /// use std::borrow::Cow;
-    ///
-    /// let a_cow_str_error = Cow::from("a str error");
-    /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_cow_str_error);
-    /// assert!(
-    ///     mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
-    /// ```
-    fn from(err: Cow<'b, str>) -> Box<dyn Error + Send + Sync + 'a> {
-        From::from(String::from(err))
-    }
-}
-
-#[cfg(bootstrap)]
-#[stable(feature = "cow_box_error", since = "1.22.0")]
-impl<'a> From<Cow<'a, str>> for Box<dyn Error> {
-    /// Converts a [`Cow`] into a box of dyn [`Error`].
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::error::Error;
-    /// use std::mem;
-    /// use std::borrow::Cow;
-    ///
-    /// let a_cow_str_error = Cow::from("a str error");
-    /// let a_boxed_error = Box::<dyn Error>::from(a_cow_str_error);
-    /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
-    /// ```
-    fn from(err: Cow<'a, str>) -> Box<dyn Error> {
-        From::from(String::from(err))
-    }
-}
-
-#[cfg(bootstrap)]
-#[unstable(feature = "never_type", issue = "35121")]
-impl Error for ! {}
-
-#[cfg(bootstrap)]
-#[unstable(
-    feature = "allocator_api",
-    reason = "the precise API and guarantees it provides may be tweaked.",
-    issue = "32838"
-)]
-impl Error for AllocError {}
-
-#[cfg(bootstrap)]
-#[stable(feature = "alloc_layout", since = "1.28.0")]
-impl Error for LayoutError {}
-
-#[cfg(bootstrap)]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Error for str::ParseBoolError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        "failed to parse bool"
-    }
-}
-
-#[cfg(bootstrap)]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Error for str::Utf8Error {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        "invalid utf-8: corrupt contents"
-    }
-}
-
-#[cfg(bootstrap)]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Error for num::ParseIntError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        self.__description()
-    }
-}
-
-#[cfg(bootstrap)]
-#[stable(feature = "try_from", since = "1.34.0")]
-impl Error for num::TryFromIntError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        self.__description()
-    }
-}
-
-#[cfg(bootstrap)]
-#[stable(feature = "try_from", since = "1.34.0")]
-impl Error for array::TryFromSliceError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        self.__description()
-    }
-}
-
-#[cfg(bootstrap)]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Error for num::ParseFloatError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        self.__description()
-    }
-}
-
-#[cfg(bootstrap)]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Error for string::FromUtf8Error {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        "invalid utf-8"
-    }
-}
-
-#[cfg(bootstrap)]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Error for string::FromUtf16Error {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        "invalid utf-16"
-    }
-}
-
-#[cfg(bootstrap)]
-#[stable(feature = "str_parse_error2", since = "1.8.0")]
-impl Error for Infallible {
-    fn description(&self) -> &str {
-        match *self {}
-    }
-}
-
-#[cfg(bootstrap)]
-#[stable(feature = "decode_utf16", since = "1.9.0")]
-impl Error for char::DecodeUtf16Error {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        "unpaired surrogate found"
-    }
-}
-
-#[cfg(bootstrap)]
-#[stable(feature = "u8_from_char", since = "1.59.0")]
-impl Error for char::TryFromCharError {}
-
-#[cfg(bootstrap)]
-#[unstable(feature = "map_try_insert", issue = "82766")]
-impl<'a, K: Debug + Ord, V: Debug> Error
-    for crate::collections::btree_map::OccupiedError<'a, K, V>
-{
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        "key already exists"
-    }
-}
-
-#[cfg(bootstrap)]
-#[unstable(feature = "map_try_insert", issue = "82766")]
-impl<'a, K: Debug, V: Debug> Error for crate::collections::hash_map::OccupiedError<'a, K, V> {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        "key already exists"
-    }
-}
-
-#[cfg(bootstrap)]
-#[stable(feature = "box_error", since = "1.8.0")]
-impl<T: Error> Error for Box<T> {
-    #[allow(deprecated, deprecated_in_future)]
-    fn description(&self) -> &str {
-        Error::description(&**self)
-    }
-
-    #[allow(deprecated)]
-    fn cause(&self) -> Option<&dyn Error> {
-        Error::cause(&**self)
-    }
-
-    fn source(&self) -> Option<&(dyn Error + 'static)> {
-        Error::source(&**self)
-    }
-}
-
-#[cfg(bootstrap)]
-#[unstable(feature = "thin_box", issue = "92791")]
-impl<T: ?Sized + crate::error::Error> crate::error::Error for crate::boxed::ThinBox<T> {
-    fn source(&self) -> Option<&(dyn crate::error::Error + 'static)> {
-        use core::ops::Deref;
-        self.deref().source()
-    }
-}
-
-#[cfg(bootstrap)]
-#[stable(feature = "error_by_ref", since = "1.51.0")]
-impl<'a, T: Error + ?Sized> Error for &'a T {
-    #[allow(deprecated, deprecated_in_future)]
-    fn description(&self) -> &str {
-        Error::description(&**self)
-    }
-
-    #[allow(deprecated)]
-    fn cause(&self) -> Option<&dyn Error> {
-        Error::cause(&**self)
-    }
-
-    fn source(&self) -> Option<&(dyn Error + 'static)> {
-        Error::source(&**self)
-    }
-
-    fn provide<'b>(&'b self, demand: &mut Demand<'b>) {
-        Error::provide(&**self, demand);
-    }
-}
-
-#[cfg(bootstrap)]
-#[stable(feature = "arc_error", since = "1.52.0")]
-impl<T: Error + ?Sized> Error for Arc<T> {
-    #[allow(deprecated, deprecated_in_future)]
-    fn description(&self) -> &str {
-        Error::description(&**self)
-    }
-
-    #[allow(deprecated)]
-    fn cause(&self) -> Option<&dyn Error> {
-        Error::cause(&**self)
-    }
-
-    fn source(&self) -> Option<&(dyn Error + 'static)> {
-        Error::source(&**self)
-    }
-
-    fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
-        Error::provide(&**self, demand);
-    }
-}
-
-#[cfg(bootstrap)]
-#[stable(feature = "fmt_error", since = "1.11.0")]
-impl Error for fmt::Error {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        "an error occurred when formatting an argument"
-    }
-}
-
-#[cfg(bootstrap)]
-#[stable(feature = "try_borrow", since = "1.13.0")]
-impl Error for cell::BorrowError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        "already mutably borrowed"
-    }
-}
-
-#[cfg(bootstrap)]
-#[stable(feature = "try_borrow", since = "1.13.0")]
-impl Error for cell::BorrowMutError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        "already borrowed"
-    }
-}
-
-#[cfg(bootstrap)]
-#[stable(feature = "try_from", since = "1.34.0")]
-impl Error for char::CharTryFromError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        "converted integer out of range for `char`"
-    }
-}
-
-#[cfg(bootstrap)]
-#[stable(feature = "char_from_str", since = "1.20.0")]
-impl Error for char::ParseCharError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        self.__description()
-    }
-}
-
-#[cfg(bootstrap)]
-#[stable(feature = "try_reserve", since = "1.57.0")]
-impl Error for alloc::collections::TryReserveError {}
-
-#[cfg(bootstrap)]
-#[unstable(feature = "duration_checked_float", issue = "83400")]
-impl Error for time::FromFloatSecsError {}
-
-#[cfg(bootstrap)]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Error for alloc::ffi::NulError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        "nul byte found in data"
-    }
-}
-
-#[cfg(bootstrap)]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl From<alloc::ffi::NulError> for io::Error {
-    /// Converts a [`alloc::ffi::NulError`] into a [`io::Error`].
-    fn from(_: alloc::ffi::NulError) -> io::Error {
-        io::const_io_error!(io::ErrorKind::InvalidInput, "data provided contains a nul byte")
-    }
-}
-
-#[cfg(bootstrap)]
-#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
-impl Error for core::ffi::FromBytesWithNulError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        self.__description()
-    }
-}
-
-#[cfg(bootstrap)]
-#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
-impl Error for core::ffi::FromBytesUntilNulError {}
-
-#[cfg(bootstrap)]
-#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
-impl Error for alloc::ffi::FromVecWithNulError {}
-
-#[cfg(bootstrap)]
-#[stable(feature = "cstring_into", since = "1.7.0")]
-impl Error for alloc::ffi::IntoStringError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        "C string contained non-utf8 bytes"
-    }
-
-    fn source(&self) -> Option<&(dyn Error + 'static)> {
-        Some(self.__source())
-    }
-}
-
-#[cfg(bootstrap)]
-impl<'a> dyn Error + 'a {
-    /// Request a reference of type `T` as context about this error.
-    #[unstable(feature = "error_generic_member_access", issue = "99301")]
-    pub fn request_ref<T: ?Sized + 'static>(&'a self) -> Option<&'a T> {
-        core::any::request_ref(self)
-    }
-
-    /// Request a value of type `T` as context about this error.
-    #[unstable(feature = "error_generic_member_access", issue = "99301")]
-    pub fn request_value<T: 'static>(&'a self) -> Option<T> {
-        core::any::request_value(self)
-    }
-}
-
-// Copied from `any.rs`.
-#[cfg(bootstrap)]
-impl dyn Error + 'static {
-    /// Returns `true` if the inner type is the same as `T`.
-    #[stable(feature = "error_downcast", since = "1.3.0")]
-    #[inline]
-    pub fn is<T: Error + 'static>(&self) -> bool {
-        // Get `TypeId` of the type this function is instantiated with.
-        let t = TypeId::of::<T>();
-
-        // Get `TypeId` of the type in the trait object (`self`).
-        let concrete = self.type_id(private::Internal);
-
-        // Compare both `TypeId`s on equality.
-        t == concrete
-    }
-
-    /// Returns some reference to the inner value if it is of type `T`, or
-    /// `None` if it isn't.
-    #[stable(feature = "error_downcast", since = "1.3.0")]
-    #[inline]
-    pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
-        if self.is::<T>() {
-            unsafe { Some(&*(self as *const dyn Error as *const T)) }
-        } else {
-            None
-        }
-    }
-
-    /// Returns some mutable reference to the inner value if it is of type `T`, or
-    /// `None` if it isn't.
-    #[stable(feature = "error_downcast", since = "1.3.0")]
-    #[inline]
-    pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
-        if self.is::<T>() {
-            unsafe { Some(&mut *(self as *mut dyn Error as *mut T)) }
-        } else {
-            None
-        }
-    }
-}
-
-#[cfg(bootstrap)]
-impl dyn Error + 'static + Send {
-    /// Forwards to the method defined on the type `dyn Error`.
-    #[stable(feature = "error_downcast", since = "1.3.0")]
-    #[inline]
-    pub fn is<T: Error + 'static>(&self) -> bool {
-        <dyn Error + 'static>::is::<T>(self)
-    }
-
-    /// Forwards to the method defined on the type `dyn Error`.
-    #[stable(feature = "error_downcast", since = "1.3.0")]
-    #[inline]
-    pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
-        <dyn Error + 'static>::downcast_ref::<T>(self)
-    }
-
-    /// Forwards to the method defined on the type `dyn Error`.
-    #[stable(feature = "error_downcast", since = "1.3.0")]
-    #[inline]
-    pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
-        <dyn Error + 'static>::downcast_mut::<T>(self)
-    }
-
-    /// Request a reference of type `T` as context about this error.
-    #[unstable(feature = "error_generic_member_access", issue = "99301")]
-    pub fn request_ref<T: ?Sized + 'static>(&self) -> Option<&T> {
-        <dyn Error>::request_ref(self)
-    }
-
-    /// Request a value of type `T` as context about this error.
-    #[unstable(feature = "error_generic_member_access", issue = "99301")]
-    pub fn request_value<T: 'static>(&self) -> Option<T> {
-        <dyn Error>::request_value(self)
-    }
-}
-
-#[cfg(bootstrap)]
-impl dyn Error + 'static + Send + Sync {
-    /// Forwards to the method defined on the type `dyn Error`.
-    #[stable(feature = "error_downcast", since = "1.3.0")]
-    #[inline]
-    pub fn is<T: Error + 'static>(&self) -> bool {
-        <dyn Error + 'static>::is::<T>(self)
-    }
-
-    /// Forwards to the method defined on the type `dyn Error`.
-    #[stable(feature = "error_downcast", since = "1.3.0")]
-    #[inline]
-    pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
-        <dyn Error + 'static>::downcast_ref::<T>(self)
-    }
-
-    /// Forwards to the method defined on the type `dyn Error`.
-    #[stable(feature = "error_downcast", since = "1.3.0")]
-    #[inline]
-    pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
-        <dyn Error + 'static>::downcast_mut::<T>(self)
-    }
-
-    /// Request a reference of type `T` as context about this error.
-    #[unstable(feature = "error_generic_member_access", issue = "99301")]
-    pub fn request_ref<T: ?Sized + 'static>(&self) -> Option<&T> {
-        <dyn Error>::request_ref(self)
-    }
-
-    /// Request a value of type `T` as context about this error.
-    #[unstable(feature = "error_generic_member_access", issue = "99301")]
-    pub fn request_value<T: 'static>(&self) -> Option<T> {
-        <dyn Error>::request_value(self)
-    }
-}
-
-#[cfg(bootstrap)]
-impl dyn Error {
-    #[inline]
-    #[stable(feature = "error_downcast", since = "1.3.0")]
-    /// Attempts to downcast the box to a concrete type.
-    pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error>> {
-        if self.is::<T>() {
-            unsafe {
-                let raw: *mut dyn Error = Box::into_raw(self);
-                Ok(Box::from_raw(raw as *mut T))
-            }
-        } else {
-            Err(self)
-        }
-    }
-
-    /// Returns an iterator starting with the current error and continuing with
-    /// recursively calling [`Error::source`].
-    ///
-    /// If you want to omit the current error and only use its sources,
-    /// use `skip(1)`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(error_iter)]
-    /// use std::error::Error;
-    /// use std::fmt;
-    ///
-    /// #[derive(Debug)]
-    /// struct A;
-    ///
-    /// #[derive(Debug)]
-    /// struct B(Option<Box<dyn Error + 'static>>);
-    ///
-    /// impl fmt::Display for A {
-    ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-    ///         write!(f, "A")
-    ///     }
-    /// }
-    ///
-    /// impl fmt::Display for B {
-    ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-    ///         write!(f, "B")
-    ///     }
-    /// }
-    ///
-    /// impl Error for A {}
-    ///
-    /// impl Error for B {
-    ///     fn source(&self) -> Option<&(dyn Error + 'static)> {
-    ///         self.0.as_ref().map(|e| e.as_ref())
-    ///     }
-    /// }
-    ///
-    /// let b = B(Some(Box::new(A)));
-    ///
-    /// // let err : Box<Error> = b.into(); // or
-    /// let err = &b as &(dyn Error);
-    ///
-    /// let mut iter = err.sources();
-    ///
-    /// assert_eq!("B".to_string(), iter.next().unwrap().to_string());
-    /// assert_eq!("A".to_string(), iter.next().unwrap().to_string());
-    /// assert!(iter.next().is_none());
-    /// assert!(iter.next().is_none());
-    /// ```
-    #[unstable(feature = "error_iter", issue = "58520")]
-    #[inline]
-    pub fn sources(&self) -> Sources<'_> {
-        // You may think this method would be better in the Error trait, and you'd be right.
-        // Unfortunately that doesn't work, not because of the object safety rules but because we
-        // save a reference to self in Sources below as a trait object. If this method was
-        // declared in Error, then self would have the type &T where T is some concrete type which
-        // implements Error. We would need to coerce self to have type &dyn Error, but that requires
-        // that Self has a known size (i.e., Self: Sized). We can't put that bound on Error
-        // since that would forbid Error trait objects, and we can't put that bound on the method
-        // because that means the method can't be called on trait objects (we'd also need the
-        // 'static bound, but that isn't allowed because methods with bounds on Self other than
-        // Sized are not object-safe). Requiring an Unsize bound is not backwards compatible.
-
-        Sources { current: Some(self) }
-    }
-}
-
-/// An iterator over an [`Error`] and its sources.
-///
-/// If you want to omit the initial error and only process
-/// its sources, use `skip(1)`.
-#[unstable(feature = "error_iter", issue = "58520")]
-#[derive(Clone, Debug)]
-#[cfg(bootstrap)]
-pub struct Sources<'a> {
-    current: Option<&'a (dyn Error + 'static)>,
-}
-
-#[cfg(bootstrap)]
-#[unstable(feature = "error_iter", issue = "58520")]
-impl<'a> Iterator for Sources<'a> {
-    type Item = &'a (dyn Error + 'static);
-
-    fn next(&mut self) -> Option<Self::Item> {
-        let current = self.current;
-        self.current = self.current.and_then(Error::source);
-        current
-    }
-}
-
-#[cfg(bootstrap)]
-impl dyn Error + Send {
-    #[inline]
-    #[stable(feature = "error_downcast", since = "1.3.0")]
-    /// Attempts to downcast the box to a concrete type.
-    pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error + Send>> {
-        let err: Box<dyn Error> = self;
-        <dyn Error>::downcast(err).map_err(|s| unsafe {
-            // Reapply the `Send` marker.
-            transmute::<Box<dyn Error>, Box<dyn Error + Send>>(s)
-        })
-    }
-}
-
-#[cfg(bootstrap)]
-impl dyn Error + Send + Sync {
-    #[inline]
-    #[stable(feature = "error_downcast", since = "1.3.0")]
-    /// Attempts to downcast the box to a concrete type.
-    pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
-        let err: Box<dyn Error> = self;
-        <dyn Error>::downcast(err).map_err(|s| unsafe {
-            // Reapply the `Send + Sync` marker.
-            transmute::<Box<dyn Error>, Box<dyn Error + Send + Sync>>(s)
-        })
-    }
-}
-
 /// An error reporter that prints an error and its sources.
 ///
 /// Report also exposes configuration options for formatting the error sources, either entirely on a
diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs
index 29b09fcc527..feb3fb989a7 100644
--- a/library/std/src/io/error.rs
+++ b/library/std/src/io/error.rs
@@ -76,7 +76,6 @@ impl fmt::Debug for Error {
     }
 }
 
-#[cfg(not(bootstrap))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl From<alloc::ffi::NulError> for Error {
     /// Converts a [`alloc::ffi::NulError`] into a [`Error`].
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 01a3873c75c..eeace2c43c4 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -1045,7 +1045,7 @@ pub trait Read {
 ///     Ok(())
 /// }
 /// ```
-#[stable(feature = "io_read_to_string", since = "CURRENT_RUSTC_VERSION")]
+#[stable(feature = "io_read_to_string", since = "1.65.0")]
 pub fn read_to_string<R: Read>(mut reader: R) -> Result<String> {
     let mut buf = String::new();
     reader.read_to_string(&mut buf)?;
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 3131dd47269..64b62fd3bba 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -252,10 +252,8 @@
 #![feature(dropck_eyepatch)]
 #![feature(exhaustive_patterns)]
 #![feature(intra_doc_pointers)]
-#![cfg_attr(bootstrap, feature(label_break_value))]
 #![feature(lang_items)]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(linkage)]
 #![feature(link_cfg)]
 #![feature(min_specialization)]
@@ -282,9 +280,9 @@
 #![feature(cstr_internals)]
 #![feature(duration_checked_float)]
 #![feature(duration_constants)]
-#![cfg_attr(not(bootstrap), feature(error_generic_member_access))]
-#![cfg_attr(not(bootstrap), feature(error_in_core))]
-#![cfg_attr(not(bootstrap), feature(error_iter))]
+#![feature(error_generic_member_access)]
+#![feature(error_in_core)]
+#![feature(error_iter)]
 #![feature(exact_size_is_empty)]
 #![feature(exclusive_wrapper)]
 #![feature(extend_one)]
@@ -296,7 +294,6 @@
 #![feature(is_some_with)]
 #![feature(maybe_uninit_slice)]
 #![feature(maybe_uninit_write_slice)]
-#![feature(mixed_integer_ops)]
 #![feature(nonnull_slice_from_raw_parts)]
 #![feature(panic_can_unwind)]
 #![feature(panic_info_message)]
@@ -351,7 +348,6 @@
 #![feature(trace_macros)]
 //
 // Only used in tests/benchmarks:
-#![feature(bench_black_box)]
 //
 // Only for const-ness:
 #![feature(const_io_structs)]
diff --git a/library/std/src/os/fd/mod.rs b/library/std/src/os/fd/mod.rs
index a456947534a..c6aa7c77dbc 100644
--- a/library/std/src/os/fd/mod.rs
+++ b/library/std/src/os/fd/mod.rs
@@ -1,16 +1,25 @@
 //! Owned and borrowed Unix-like file descriptors.
+//!
+//! This module is supported on Unix platforms and WASI, which both use a
+//! similar file descriptor system for referencing OS resources.
 
 #![stable(feature = "io_safety", since = "1.63.0")]
 #![deny(unsafe_op_in_unsafe_fn)]
 
 // `RawFd`, `AsRawFd`, etc.
-pub mod raw;
+mod raw;
 
 // `OwnedFd`, `AsFd`, etc.
-pub mod owned;
+mod owned;
 
 // Implementations for `AsRawFd` etc. for network types.
 mod net;
 
 #[cfg(test)]
 mod tests;
+
+// Export the types and traits for the public API.
+#[unstable(feature = "os_fd", issue = "98699")]
+pub use owned::*;
+#[unstable(feature = "os_fd", issue = "98699")]
+pub use raw::*;
diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs
index 71e33fb9ed8..9875c389d8a 100644
--- a/library/std/src/os/fd/owned.rs
+++ b/library/std/src/os/fd/owned.rs
@@ -206,10 +206,8 @@ pub trait AsFd {
     /// ```rust,no_run
     /// use std::fs::File;
     /// # use std::io;
-    /// # #[cfg(target_os = "wasi")]
-    /// # use std::os::wasi::io::{AsFd, BorrowedFd};
-    /// # #[cfg(unix)]
-    /// # use std::os::unix::io::{AsFd, BorrowedFd};
+    /// # #[cfg(any(unix, target_os = "wasi"))]
+    /// # use std::os::fd::{AsFd, BorrowedFd};
     ///
     /// let mut f = File::open("foo.txt")?;
     /// # #[cfg(any(unix, target_os = "wasi"))]
diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs
index 1b3d110426f..f92a0506670 100644
--- a/library/std/src/os/fd/raw.rs
+++ b/library/std/src/os/fd/raw.rs
@@ -42,10 +42,8 @@ pub trait AsRawFd {
     /// ```no_run
     /// use std::fs::File;
     /// # use std::io;
-    /// #[cfg(unix)]
-    /// use std::os::unix::io::{AsRawFd, RawFd};
-    /// #[cfg(target_os = "wasi")]
-    /// use std::os::wasi::io::{AsRawFd, RawFd};
+    /// #[cfg(any(unix, target_os = "wasi"))]
+    /// use std::os::fd::{AsRawFd, RawFd};
     ///
     /// let mut f = File::open("foo.txt")?;
     /// // Note that `raw_fd` is only valid as long as `f` exists.
@@ -83,10 +81,8 @@ pub trait FromRawFd {
     /// ```no_run
     /// use std::fs::File;
     /// # use std::io;
-    /// #[cfg(unix)]
-    /// use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd};
-    /// #[cfg(target_os = "wasi")]
-    /// use std::os::wasi::io::{FromRawFd, IntoRawFd, RawFd};
+    /// #[cfg(any(unix, target_os = "wasi"))]
+    /// use std::os::fd::{FromRawFd, IntoRawFd, RawFd};
     ///
     /// let f = File::open("foo.txt")?;
     /// # #[cfg(any(unix, target_os = "wasi"))]
@@ -121,10 +117,8 @@ pub trait IntoRawFd {
     /// ```no_run
     /// use std::fs::File;
     /// # use std::io;
-    /// #[cfg(unix)]
-    /// use std::os::unix::io::{IntoRawFd, RawFd};
-    /// #[cfg(target_os = "wasi")]
-    /// use std::os::wasi::io::{IntoRawFd, RawFd};
+    /// #[cfg(any(unix, target_os = "wasi"))]
+    /// use std::os::fd::{IntoRawFd, RawFd};
     ///
     /// let f = File::open("foo.txt")?;
     /// #[cfg(any(unix, target_os = "wasi"))]
diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs
index 18c64b51007..f62f5af774f 100644
--- a/library/std/src/os/mod.rs
+++ b/library/std/src/os/mod.rs
@@ -147,7 +147,7 @@ pub mod solid;
 pub mod vxworks;
 
 #[cfg(any(unix, target_os = "wasi", doc))]
-mod fd;
+pub mod fd;
 
 #[cfg(any(target_os = "linux", target_os = "android", doc))]
 mod net;
diff --git a/library/std/src/os/unix/io/fd.rs b/library/std/src/os/unix/io/fd.rs
deleted file mode 100644
index d4cb696459b..00000000000
--- a/library/std/src/os/unix/io/fd.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-//! Owned and borrowed file descriptors.
-
-// Tests for this module
-#[cfg(test)]
-mod tests;
-
-#[stable(feature = "io_safety", since = "1.63.0")]
-pub use crate::os::fd::owned::*;
diff --git a/library/std/src/os/unix/io/mod.rs b/library/std/src/os/unix/io/mod.rs
index 3ab5606f889..25b5dbff14f 100644
--- a/library/std/src/os/unix/io/mod.rs
+++ b/library/std/src/os/unix/io/mod.rs
@@ -77,10 +77,9 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-mod fd;
-mod raw;
-
-#[stable(feature = "io_safety", since = "1.63.0")]
-pub use fd::*;
 #[stable(feature = "rust1", since = "1.0.0")]
-pub use raw::*;
+pub use crate::os::fd::*;
+
+// Tests for this module
+#[cfg(test)]
+mod tests;
diff --git a/library/std/src/os/unix/io/raw.rs b/library/std/src/os/unix/io/raw.rs
deleted file mode 100644
index a4d2ba797d9..00000000000
--- a/library/std/src/os/unix/io/raw.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-//! Unix-specific extensions to general I/O primitives.
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use crate::os::fd::raw::*;
diff --git a/library/std/src/os/unix/io/fd/tests.rs b/library/std/src/os/unix/io/tests.rs
index 84d2a7a1a91..84d2a7a1a91 100644
--- a/library/std/src/os/unix/io/fd/tests.rs
+++ b/library/std/src/os/unix/io/tests.rs
diff --git a/library/std/src/os/wasi/io/mod.rs b/library/std/src/os/wasi/io/mod.rs
index 6c884e2eaf4..d528590d75b 100644
--- a/library/std/src/os/wasi/io/mod.rs
+++ b/library/std/src/os/wasi/io/mod.rs
@@ -1,12 +1,6 @@
 //! WASI-specific extensions to general I/O primitives.
 
-#![deny(unsafe_op_in_unsafe_fn)]
 #![unstable(feature = "wasi_ext", issue = "71213")]
 
-mod fd;
-mod raw;
-
-#[unstable(feature = "wasi_ext", issue = "71213")]
-pub use fd::*;
 #[unstable(feature = "wasi_ext", issue = "71213")]
-pub use raw::*;
+pub use crate::os::fd::*;
diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs
index 98f6cc7aa3e..b8bcdbece0a 100644
--- a/library/std/src/rt.rs
+++ b/library/std/src/rt.rs
@@ -160,15 +160,12 @@ fn lang_start<T: crate::process::Termination + 'static>(
     main: fn() -> T,
     argc: isize,
     argv: *const *const u8,
-    #[cfg(not(bootstrap))] sigpipe: u8,
+    sigpipe: u8,
 ) -> isize {
     let Ok(v) = lang_start_internal(
         &move || crate::sys_common::backtrace::__rust_begin_short_backtrace(main).report().to_i32(),
         argc,
         argv,
-        #[cfg(bootstrap)]
-        2, // Temporary inlining of sigpipe::DEFAULT until bootstrap stops being special
-        #[cfg(not(bootstrap))]
         sigpipe,
     );
     v
diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs
index 9ab781561e9..ee2c79b6669 100644
--- a/library/std/src/sync/rwlock.rs
+++ b/library/std/src/sync/rwlock.rs
@@ -76,6 +76,7 @@ use crate::sys_common::rwlock as sys;
 ///
 /// [`Mutex`]: super::Mutex
 #[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "RwLock")]
 pub struct RwLock<T: ?Sized> {
     inner: sys::MovableRwLock,
     poison: poison::Flag,
diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs
index 3c3770708b1..7c70ddbd9b9 100644
--- a/library/std/src/sys/unix/os.rs
+++ b/library/std/src/sys/unix/os.rs
@@ -125,7 +125,9 @@ pub fn error_string(errno: i32) -> String {
         }
 
         let p = p as *const _;
-        str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned()
+        // We can't always expect a UTF-8 environment. When we don't get that luxury,
+        // it's better to give a low-quality error message than none at all.
+        String::from_utf8_lossy(CStr::from_ptr(p).to_bytes()).into()
     }
 }
 
diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs
index dff973f59d1..cca9c676701 100644
--- a/library/std/src/sys/unix/time.rs
+++ b/library/std/src/sys/unix/time.rs
@@ -7,6 +7,12 @@ const NSEC_PER_SEC: u64 = 1_000_000_000;
 pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
 
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[repr(transparent)]
+#[rustc_layout_scalar_valid_range_start(0)]
+#[rustc_layout_scalar_valid_range_end(999_999_999)]
+struct Nanoseconds(u32);
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct SystemTime {
     pub(in crate::sys::unix) t: Timespec,
 }
@@ -14,7 +20,7 @@ pub struct SystemTime {
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub(in crate::sys::unix) struct Timespec {
     tv_sec: i64,
-    tv_nsec: i64,
+    tv_nsec: Nanoseconds,
 }
 
 impl SystemTime {
@@ -46,18 +52,20 @@ impl fmt::Debug for SystemTime {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("SystemTime")
             .field("tv_sec", &self.t.tv_sec)
-            .field("tv_nsec", &self.t.tv_nsec)
+            .field("tv_nsec", &self.t.tv_nsec.0)
             .finish()
     }
 }
 
 impl Timespec {
     pub const fn zero() -> Timespec {
-        Timespec { tv_sec: 0, tv_nsec: 0 }
+        Timespec::new(0, 0)
     }
 
-    fn new(tv_sec: i64, tv_nsec: i64) -> Timespec {
-        Timespec { tv_sec, tv_nsec }
+    const fn new(tv_sec: i64, tv_nsec: i64) -> Timespec {
+        assert!(tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC as i64);
+        // SAFETY: The assert above checks tv_nsec is within the valid range
+        Timespec { tv_sec, tv_nsec: unsafe { Nanoseconds(tv_nsec as u32) } }
     }
 
     pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
@@ -75,12 +83,12 @@ impl Timespec {
             //
             // Ideally this code could be rearranged such that it more
             // directly expresses the lower-cost behavior we want from it.
-            let (secs, nsec) = if self.tv_nsec >= other.tv_nsec {
-                ((self.tv_sec - other.tv_sec) as u64, (self.tv_nsec - other.tv_nsec) as u32)
+            let (secs, nsec) = if self.tv_nsec.0 >= other.tv_nsec.0 {
+                ((self.tv_sec - other.tv_sec) as u64, self.tv_nsec.0 - other.tv_nsec.0)
             } else {
                 (
                     (self.tv_sec - other.tv_sec - 1) as u64,
-                    self.tv_nsec as u32 + (NSEC_PER_SEC as u32) - other.tv_nsec as u32,
+                    self.tv_nsec.0 + (NSEC_PER_SEC as u32) - other.tv_nsec.0,
                 )
             };
 
@@ -102,7 +110,7 @@ impl Timespec {
 
         // Nano calculations can't overflow because nanos are <1B which fit
         // in a u32.
-        let mut nsec = other.subsec_nanos() + self.tv_nsec as u32;
+        let mut nsec = other.subsec_nanos() + self.tv_nsec.0;
         if nsec >= NSEC_PER_SEC as u32 {
             nsec -= NSEC_PER_SEC as u32;
             secs = secs.checked_add(1)?;
@@ -118,7 +126,7 @@ impl Timespec {
             .and_then(|secs| self.tv_sec.checked_sub(secs))?;
 
         // Similar to above, nanos can't overflow.
-        let mut nsec = self.tv_nsec as i32 - other.subsec_nanos() as i32;
+        let mut nsec = self.tv_nsec.0 as i32 - other.subsec_nanos() as i32;
         if nsec < 0 {
             nsec += NSEC_PER_SEC as i32;
             secs = secs.checked_sub(1)?;
@@ -130,7 +138,7 @@ impl Timespec {
     pub fn to_timespec(&self) -> Option<libc::timespec> {
         Some(libc::timespec {
             tv_sec: self.tv_sec.try_into().ok()?,
-            tv_nsec: self.tv_nsec.try_into().ok()?,
+            tv_nsec: self.tv_nsec.0.try_into().ok()?,
         })
     }
 }
@@ -293,7 +301,7 @@ mod inner {
         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             f.debug_struct("Instant")
                 .field("tv_sec", &self.t.tv_sec)
-                .field("tv_nsec", &self.t.tv_nsec)
+                .field("tv_nsec", &self.t.tv_nsec.0)
                 .finish()
         }
     }
@@ -334,7 +342,7 @@ mod inner {
                     let mut t = MaybeUninit::uninit();
                     cvt(unsafe { clock_gettime64(clock, t.as_mut_ptr()) }).unwrap();
                     let t = unsafe { t.assume_init() };
-                    return Timespec { tv_sec: t.tv_sec, tv_nsec: t.tv_nsec as i64 };
+                    return Timespec::new(t.tv_sec, t.tv_nsec as i64);
                 }
             }
 
diff --git a/library/std/src/sys/unsupported/locks/condvar.rs b/library/std/src/sys/unsupported/locks/condvar.rs
index e703fd0d269..527a26a12bc 100644
--- a/library/std/src/sys/unsupported/locks/condvar.rs
+++ b/library/std/src/sys/unsupported/locks/condvar.rs
@@ -7,6 +7,7 @@ pub type MovableCondvar = Condvar;
 
 impl Condvar {
     #[inline]
+    #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
     pub const fn new() -> Condvar {
         Condvar {}
     }
diff --git a/library/std/src/sys/unsupported/locks/mutex.rs b/library/std/src/sys/unsupported/locks/mutex.rs
index 2be0b34b985..87ea475c6e3 100644
--- a/library/std/src/sys/unsupported/locks/mutex.rs
+++ b/library/std/src/sys/unsupported/locks/mutex.rs
@@ -12,6 +12,7 @@ unsafe impl Sync for Mutex {} // no threads on this platform
 
 impl Mutex {
     #[inline]
+    #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
     pub const fn new() -> Mutex {
         Mutex { locked: Cell::new(false) }
     }
diff --git a/library/std/src/sys/unsupported/locks/rwlock.rs b/library/std/src/sys/unsupported/locks/rwlock.rs
index aca5fb7152c..5292691b955 100644
--- a/library/std/src/sys/unsupported/locks/rwlock.rs
+++ b/library/std/src/sys/unsupported/locks/rwlock.rs
@@ -12,6 +12,7 @@ unsafe impl Sync for RwLock {} // no threads on this platform
 
 impl RwLock {
     #[inline]
+    #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
     pub const fn new() -> RwLock {
         RwLock { mode: Cell::new(0) }
     }
diff --git a/library/std/src/sys_common/condvar.rs b/library/std/src/sys_common/condvar.rs
index f3ac1061b89..8bc5b24115d 100644
--- a/library/std/src/sys_common/condvar.rs
+++ b/library/std/src/sys_common/condvar.rs
@@ -15,6 +15,7 @@ pub struct Condvar {
 impl Condvar {
     /// Creates a new condition variable for use.
     #[inline]
+    #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
     pub const fn new() -> Self {
         Self { inner: imp::MovableCondvar::new(), check: CondvarCheck::new() }
     }
diff --git a/library/std/src/sys_common/condvar/check.rs b/library/std/src/sys_common/condvar/check.rs
index ce8f3670487..4ac9e62bf86 100644
--- a/library/std/src/sys_common/condvar/check.rs
+++ b/library/std/src/sys_common/condvar/check.rs
@@ -50,6 +50,7 @@ pub struct NoCheck;
 
 #[allow(dead_code)]
 impl NoCheck {
+    #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
     pub const fn new() -> Self {
         Self
     }
diff --git a/library/std/src/sys_common/mutex.rs b/library/std/src/sys_common/mutex.rs
index 48479f5bdb3..7b9f7ef5487 100644
--- a/library/std/src/sys_common/mutex.rs
+++ b/library/std/src/sys_common/mutex.rs
@@ -61,6 +61,7 @@ unsafe impl Sync for MovableMutex {}
 impl MovableMutex {
     /// Creates a new mutex.
     #[inline]
+    #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
     pub const fn new() -> Self {
         Self(imp::MovableMutex::new())
     }
diff --git a/library/std/src/sys_common/rwlock.rs b/library/std/src/sys_common/rwlock.rs
index 36d721fcbcb..042981dac60 100644
--- a/library/std/src/sys_common/rwlock.rs
+++ b/library/std/src/sys_common/rwlock.rs
@@ -15,6 +15,7 @@ pub struct MovableRwLock(imp::MovableRwLock);
 impl MovableRwLock {
     /// Creates a new reader-writer lock for use.
     #[inline]
+    #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
     pub const fn new() -> Self {
         Self(imp::MovableRwLock::new())
     }
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index 8aedfc4a6b8..ffd17dc9909 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -95,6 +95,7 @@ use crate::fmt;
 /// [loader lock]: https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-best-practices
 /// [`JoinHandle::join`]: crate::thread::JoinHandle::join
 /// [`with`]: LocalKey::with
+#[cfg_attr(not(test), rustc_diagnostic_item = "LocalKey")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct LocalKey<T: 'static> {
     // This outer `LocalKey<T>` type is what's going to be stored in statics,
diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs
index 3b7193adcc7..33c6ea58532 100644
--- a/library/test/src/lib.rs
+++ b/library/test/src/lib.rs
@@ -15,7 +15,6 @@
 
 #![unstable(feature = "test", issue = "50297")]
 #![doc(test(attr(deny(warnings))))]
-#![feature(bench_black_box)]
 #![feature(internal_output_capture)]
 #![feature(staged_api)]
 #![feature(process_exitcode_internals)]
diff --git a/src/bootstrap/build.rs b/src/bootstrap/build.rs
index ab34d5c1e55..cd1f418028c 100644
--- a/src/bootstrap/build.rs
+++ b/src/bootstrap/build.rs
@@ -1,43 +1,7 @@
-use env::consts::{EXE_EXTENSION, EXE_SUFFIX};
 use std::env;
-use std::ffi::OsString;
-use std::path::PathBuf;
-
-/// Given an executable called `name`, return the filename for the
-/// executable for a particular target.
-pub fn exe(name: &PathBuf) -> PathBuf {
-    if EXE_EXTENSION != "" && name.extension() != Some(EXE_EXTENSION.as_ref()) {
-        let mut name: OsString = name.clone().into();
-        name.push(EXE_SUFFIX);
-        name.into()
-    } else {
-        name.clone()
-    }
-}
 
 fn main() {
     let host = env::var("HOST").unwrap();
     println!("cargo:rerun-if-changed=build.rs");
-    println!("cargo:rerun-if-env-changed=RUSTC");
     println!("cargo:rustc-env=BUILD_TRIPLE={}", host);
-
-    // This may not be a canonicalized path.
-    let mut rustc = PathBuf::from(env::var_os("RUSTC").unwrap());
-
-    if rustc.is_relative() {
-        println!("cargo:rerun-if-env-changed=PATH");
-        for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) {
-            let absolute = dir.join(&exe(&rustc));
-            if absolute.exists() {
-                rustc = absolute;
-                break;
-            }
-        }
-    }
-    assert!(rustc.is_absolute());
-
-    // FIXME: if the path is not utf-8, this is going to break. Unfortunately
-    // Cargo doesn't have a way for us to specify non-utf-8 paths easily, so
-    // we'll need to invent some encoding scheme if this becomes a problem.
-    println!("cargo:rustc-env=RUSTC={}", rustc.to_str().unwrap());
 }
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index bc6283ef467..415774d7255 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -724,6 +724,7 @@ impl<'a> Builder<'a> {
                 dist::Miri,
                 dist::LlvmTools,
                 dist::RustDev,
+                dist::Bootstrap,
                 dist::Extended,
                 // It seems that PlainSourceTarball somehow changes how some of the tools
                 // perceive their dependencies (see #93033) which would invalidate fingerprints
@@ -1556,13 +1557,12 @@ impl<'a> Builder<'a> {
         match mode {
             Mode::ToolBootstrap => {
                 // Restrict the allowed features to those passed by rustbuild, so we don't depend on nightly accidentally.
-                // HACK: because anyhow does feature detection in build.rs, we need to allow the backtrace feature too.
-                rustflags.arg("-Zallow-features=binary-dep-depinfo,backtrace");
+                rustflags.arg("-Zallow-features=binary-dep-depinfo");
             }
             Mode::ToolStd => {
                 // Right now this is just compiletest and a few other tools that build on stable.
                 // Allow them to use `feature(test)`, but nothing else.
-                rustflags.arg("-Zallow-features=binary-dep-depinfo,test,backtrace,proc_macro_internals,proc_macro_diagnostic,proc_macro_span");
+                rustflags.arg("-Zallow-features=binary-dep-depinfo,test,proc_macro_internals,proc_macro_diagnostic,proc_macro_span");
             }
             Mode::Std | Mode::Rustc | Mode::Codegen | Mode::ToolRustc => {}
         }
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index c13e83f6c86..58cf3edc317 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -299,9 +299,7 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car
 
     // Determine if we're going to compile in optimized C intrinsics to
     // the `compiler-builtins` crate. These intrinsics live in LLVM's
-    // `compiler-rt` repository, but our `src/llvm-project` submodule isn't
-    // always checked out, so we need to conditionally look for this. (e.g. if
-    // an external LLVM is used we skip the LLVM submodule checkout).
+    // `compiler-rt` repository.
     //
     // Note that this shouldn't affect the correctness of `compiler-builtins`,
     // but only its speed. Some intrinsics in C haven't been translated to Rust
@@ -312,8 +310,15 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car
     // If `compiler-rt` is available ensure that the `c` feature of the
     // `compiler-builtins` crate is enabled and it's configured to learn where
     // `compiler-rt` is located.
-    let compiler_builtins_root = builder.src.join("src/llvm-project/compiler-rt");
-    let compiler_builtins_c_feature = if compiler_builtins_root.exists() {
+    let compiler_builtins_c_feature = if builder.config.optimized_compiler_builtins {
+        if !builder.is_rust_llvm(target) {
+            panic!(
+                "need a managed LLVM submodule for optimized intrinsics support; unset `llvm-config` or `optimized-compiler-builtins`"
+            );
+        }
+
+        builder.update_submodule(&Path::new("src").join("llvm-project"));
+        let compiler_builtins_root = builder.src.join("src/llvm-project/compiler-rt");
         // Note that `libprofiler_builtins/build.rs` also computes this so if
         // you're changing something here please also change that.
         cargo.env("RUST_COMPILER_RT_ROOT", &compiler_builtins_root);
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 7c062460c4f..f29b5170ea5 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -73,6 +73,8 @@ pub struct Config {
     pub color: Color,
     pub patch_binaries_for_nix: bool,
     pub stage0_metadata: Stage0Metadata,
+    /// Whether to use the `c` feature of the `compiler_builtins` crate.
+    pub optimized_compiler_builtins: bool,
 
     pub on_fail: Option<String>,
     pub stage: u32,
@@ -597,6 +599,7 @@ define_config! {
         bench_stage: Option<u32> = "bench-stage",
         patch_binaries_for_nix: Option<bool> = "patch-binaries-for-nix",
         metrics: Option<bool> = "metrics",
+        optimized_compiler_builtins: Option<bool> = "optimized-compiler-builtins",
     }
 }
 
@@ -772,21 +775,20 @@ impl Config {
 
         // set by build.rs
         config.build = TargetSelection::from_user(&env!("BUILD_TRIPLE"));
+
         let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
         // Undo `src/bootstrap`
         config.src = manifest_dir.parent().unwrap().parent().unwrap().to_owned();
         config.out = PathBuf::from("build");
 
-        config.initial_cargo = PathBuf::from(env!("CARGO"));
-        config.initial_rustc = PathBuf::from(env!("RUSTC"));
-
         config
     }
 
     pub fn parse(args: &[String]) -> Config {
         let flags = Flags::parse(&args);
-
         let mut config = Config::default_opts();
+
+        // Set flags.
         config.exclude = flags.exclude.into_iter().map(|path| TaskPath::parse(path)).collect();
         config.include_default_paths = flags.include_default_paths;
         config.rustc_error_format = flags.rustc_error_format;
@@ -805,7 +807,49 @@ impl Config {
         config.llvm_profile_use = flags.llvm_profile_use;
         config.llvm_profile_generate = flags.llvm_profile_generate;
 
+        // Infer the rest of the configuration.
+
+        // Infer the source directory. This is non-trivial because we want to support a downloaded bootstrap binary,
+        // running on a completely machine from where it was compiled.
+        let mut cmd = Command::new("git");
+        // NOTE: we cannot support running from outside the repository because the only path we have available
+        // is set at compile time, which can be wrong if bootstrap was downloaded from source.
+        // We still support running outside the repository if we find we aren't in a git directory.
+        cmd.arg("rev-parse").arg("--show-toplevel");
+        // Discard stderr because we expect this to fail when building from a tarball.
+        let output = cmd
+            .stderr(std::process::Stdio::null())
+            .output()
+            .ok()
+            .and_then(|output| if output.status.success() { Some(output) } else { None });
+        if let Some(output) = output {
+            let git_root = String::from_utf8(output.stdout).unwrap();
+            // We need to canonicalize this path to make sure it uses backslashes instead of forward slashes.
+            let git_root = PathBuf::from(git_root.trim()).canonicalize().unwrap();
+            let s = git_root.to_str().unwrap();
+
+            // Bootstrap is quite bad at handling /? in front of paths
+            config.src = match s.strip_prefix("\\\\?\\") {
+                Some(p) => PathBuf::from(p),
+                None => PathBuf::from(git_root),
+            };
+        } else {
+            // We're building from a tarball, not git sources.
+            // We don't support pre-downloaded bootstrap in this case.
+        }
+
+        if cfg!(test) {
+            // Use the build directory of the original x.py invocation, so that we can set `initial_rustc` properly.
+            config.out = Path::new(
+                &env::var_os("CARGO_TARGET_DIR").expect("cargo test directly is not supported"),
+            )
+            .parent()
+            .unwrap()
+            .to_path_buf();
+        }
+
         let stage0_json = t!(std::fs::read(&config.src.join("src").join("stage0.json")));
+
         config.stage0_metadata = t!(serde_json::from_slice::<Stage0Metadata>(&stage0_json));
 
         #[cfg(test)]
@@ -861,7 +905,6 @@ impl Config {
 
         let build = toml.build.unwrap_or_default();
 
-        set(&mut config.initial_rustc, build.rustc.map(PathBuf::from));
         set(&mut config.out, flags.build_dir.or_else(|| build.build_dir.map(PathBuf::from)));
         // NOTE: Bootstrap spawns various commands with different working directories.
         // To avoid writing to random places on the file system, `config.out` needs to be an absolute path.
@@ -870,6 +913,16 @@ impl Config {
             config.out = crate::util::absolute(&config.out);
         }
 
+        config.initial_rustc = build
+            .rustc
+            .map(PathBuf::from)
+            .unwrap_or_else(|| config.out.join(config.build.triple).join("stage0/bin/rustc"));
+        config.initial_cargo = build
+            .cargo
+            .map(PathBuf::from)
+            .unwrap_or_else(|| config.out.join(config.build.triple).join("stage0/bin/cargo"));
+
+        // NOTE: it's important this comes *after* we set `initial_rustc` just above.
         if config.dry_run {
             let dir = config.out.join("tmp-dry-run");
             t!(fs::create_dir_all(&dir));
@@ -916,6 +969,7 @@ impl Config {
         set(&mut config.print_step_timings, build.print_step_timings);
         set(&mut config.print_step_rusage, build.print_step_rusage);
         set(&mut config.patch_binaries_for_nix, build.patch_binaries_for_nix);
+        set(&mut config.optimized_compiler_builtins, build.optimized_compiler_builtins);
 
         config.verbose = cmp::max(config.verbose, flags.verbose);
 
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 563e67a326f..42352285182 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -1844,23 +1844,21 @@ fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: TargetSelection) {
 ///
 /// Returns whether the files were actually copied.
 fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir: &Path) -> bool {
-    if let Some(config) = builder.config.target_config.get(&target) {
-        if config.llvm_config.is_some() && !builder.config.llvm_from_ci {
-            // If the LLVM was externally provided, then we don't currently copy
-            // artifacts into the sysroot. This is not necessarily the right
-            // choice (in particular, it will require the LLVM dylib to be in
-            // the linker's load path at runtime), but the common use case for
-            // external LLVMs is distribution provided LLVMs, and in that case
-            // they're usually in the standard search path (e.g., /usr/lib) and
-            // copying them here is going to cause problems as we may end up
-            // with the wrong files and isn't what distributions want.
-            //
-            // This behavior may be revisited in the future though.
-            //
-            // If the LLVM is coming from ourselves (just from CI) though, we
-            // still want to install it, as it otherwise won't be available.
-            return false;
-        }
+    if !builder.is_rust_llvm(target) {
+        // If the LLVM was externally provided, then we don't currently copy
+        // artifacts into the sysroot. This is not necessarily the right
+        // choice (in particular, it will require the LLVM dylib to be in
+        // the linker's load path at runtime), but the common use case for
+        // external LLVMs is distribution provided LLVMs, and in that case
+        // they're usually in the standard search path (e.g., /usr/lib) and
+        // copying them here is going to cause problems as we may end up
+        // with the wrong files and isn't what distributions want.
+        //
+        // This behavior may be revisited in the future though.
+        //
+        // If the LLVM is coming from ourselves (just from CI) though, we
+        // still want to install it, as it otherwise won't be available.
+        return false;
     }
 
     // On macOS, rustc (and LLVM tools) link to an unversioned libLLVM.dylib
@@ -1879,7 +1877,7 @@ fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir
         let mut cmd = Command::new(llvm_config);
         cmd.arg("--libfiles");
         builder.verbose(&format!("running {:?}", cmd));
-        let files = output(&mut cmd);
+        let files = if builder.config.dry_run { "".into() } else { output(&mut cmd) };
         let build_llvm_out = &builder.llvm_out(builder.config.build);
         let target_llvm_out = &builder.llvm_out(target);
         for file in files.trim_end().split(' ') {
@@ -2057,6 +2055,41 @@ impl Step for RustDev {
     }
 }
 
+// Tarball intended for internal consumption to ease rustc/std development.
+//
+// Should not be considered stable by end users.
+#[derive(Clone, Debug, Eq, Hash, PartialEq)]
+pub struct Bootstrap {
+    pub target: TargetSelection,
+}
+
+impl Step for Bootstrap {
+    type Output = Option<GeneratedTarball>;
+    const DEFAULT: bool = false;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.alias("bootstrap")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(Bootstrap { target: run.target });
+    }
+
+    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
+        let target = self.target;
+
+        let tarball = Tarball::new(builder, "bootstrap", &target.triple);
+
+        let bootstrap_outdir = &builder.bootstrap_out;
+        for file in &["bootstrap", "llvm-config-wrapper", "rustc", "rustdoc", "sccache-plus-cl"] {
+            tarball.add_file(bootstrap_outdir.join(exe(file, target)), "bootstrap/bin", 0o755);
+        }
+
+        Some(tarball.generate())
+    }
+}
+
 /// Tarball containing a prebuilt version of the build-manifest tool, intended to be used by the
 /// release process to avoid cloning the monorepo and building stuff.
 ///
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index b421ebc2d01..c83490316b6 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -198,6 +198,7 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &'static str, Option<&[&'static str]>)]
     (None, "bootstrap", None),
     (Some(Mode::Rustc), "parallel_compiler", None),
     (Some(Mode::ToolRustc), "parallel_compiler", None),
+    (Some(Mode::Codegen), "parallel_compiler", None),
     (Some(Mode::Std), "stdarch_intel_sde", None),
     (Some(Mode::Std), "no_fp_fmt_parse", None),
     (Some(Mode::Std), "no_global_oom_handling", None),
@@ -458,19 +459,18 @@ impl Build {
             .expect("failed to read src/version");
         let version = version.trim();
 
-        let bootstrap_out = if std::env::var("BOOTSTRAP_PYTHON").is_ok() {
-            out.join("bootstrap").join("debug")
-        } else {
-            let workspace_target_dir = std::env::var("CARGO_TARGET_DIR")
-                .map(PathBuf::from)
-                .unwrap_or_else(|_| src.join("target"));
-            let bootstrap_out = workspace_target_dir.join("debug");
-            if !bootstrap_out.join("rustc").exists() && !cfg!(test) {
-                // this restriction can be lifted whenever https://github.com/rust-lang/rfcs/pull/3028 is implemented
-                panic!("run `cargo build --bins` before `cargo run`")
-            }
-            bootstrap_out
-        };
+        let bootstrap_out = std::env::current_exe()
+            .expect("could not determine path to running process")
+            .parent()
+            .unwrap()
+            .to_path_buf();
+        if !bootstrap_out.join(exe("rustc", config.build)).exists() && !cfg!(test) {
+            // this restriction can be lifted whenever https://github.com/rust-lang/rfcs/pull/3028 is implemented
+            panic!(
+                "`rustc` not found in {}, run `cargo build --bins` before `cargo run`",
+                bootstrap_out.display()
+            )
+        }
 
         let mut build = Build {
             initial_rustc: config.initial_rustc.clone(),
diff --git a/src/ci/docker/host-x86_64/disabled/dist-x86_64-haiku/Dockerfile b/src/ci/docker/host-x86_64/disabled/dist-x86_64-haiku/Dockerfile
index 5ddd3f18039..637b5fa22f9 100644
--- a/src/ci/docker/host-x86_64/disabled/dist-x86_64-haiku/Dockerfile
+++ b/src/ci/docker/host-x86_64/disabled/dist-x86_64-haiku/Dockerfile
@@ -47,4 +47,6 @@ ENV RUST_CONFIGURE_ARGS --disable-jemalloc \
   --set=$TARGET.cc=x86_64-unknown-haiku-gcc \
   --set=$TARGET.cxx=x86_64-unknown-haiku-g++ \
   --set=$TARGET.llvm-config=/bin/llvm-config-haiku
+ENV EXTERNAL_LLVM 1
+
 ENV SCRIPT python3 ../x.py dist --host=$HOST --target=$HOST
diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
index 126c292b38e..8250ec0c311 100644
--- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
@@ -129,4 +129,6 @@ ENV RUST_CONFIGURE_ARGS --enable-extended --enable-lld --disable-docs \
   --set target.wasm32-wasi.wasi-root=/wasm32-wasi \
   --musl-root-armv7=/musl-armv7
 
+ENV EXTERNAL_LLVM 1
+
 ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
index 973c43072bf..b960239807a 100644
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
@@ -82,7 +82,7 @@ ENV RUST_CONFIGURE_ARGS \
 ENV SCRIPT ../src/ci/pgo.sh python3 ../x.py dist \
     --host $HOSTS --target $HOSTS \
     --include-default-paths \
-    build-manifest
+    build-manifest bootstrap
 ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang
 
 # This is the only builder which will create source tarballs
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-13-stage1/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-13-stage1/Dockerfile
index 23f2215c2d9..1289f116fe9 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-13-stage1/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-13-stage1/Dockerfile
@@ -29,6 +29,7 @@ RUN sh /scripts/sccache.sh
 # We are disabling CI LLVM since this builder is intentionally using a host
 # LLVM, rather than the typical src/llvm-project LLVM.
 ENV NO_DOWNLOAD_CI_LLVM 1
+ENV EXTERNAL_LLVM 1
 
 # Using llvm-link-shared due to libffi issues -- see #34486
 ENV RUST_CONFIGURE_ARGS \
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-13/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-13/Dockerfile
index 8f6831bc54e..4b89a72baa1 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-13/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-13/Dockerfile
@@ -40,6 +40,7 @@ RUN sh /scripts/sccache.sh
 # We are disabling CI LLVM since this builder is intentionally using a host
 # LLVM, rather than the typical src/llvm-project LLVM.
 ENV NO_DOWNLOAD_CI_LLVM 1
+ENV EXTERNAL_LLVM 1
 
 # Using llvm-link-shared due to libffi issues -- see #34486
 ENV RUST_CONFIGURE_ARGS \
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index f020c31079e..9f401779900 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -462,7 +462,7 @@ jobs:
 
           - name: dist-x86_64-apple
             env:
-              SCRIPT: ./x.py dist --host=x86_64-apple-darwin --target=x86_64-apple-darwin
+              SCRIPT: ./x.py dist bootstrap --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin
               RUST_CONFIGURE_ARGS: --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
               MACOSX_DEPLOYMENT_TARGET: 10.7
@@ -474,7 +474,7 @@ jobs:
 
           - name: dist-apple-various
             env:
-              SCRIPT: ./x.py dist --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim
+              SCRIPT: ./x.py dist bootstrap --include-default-paths --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim
               RUST_CONFIGURE_ARGS: --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
               MACOSX_DEPLOYMENT_TARGET: 10.7
@@ -485,7 +485,7 @@ jobs:
 
           - name: dist-x86_64-apple-alt
             env:
-              SCRIPT: ./x.py dist
+              SCRIPT: ./x.py dist bootstrap --include-default-paths
               RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
               MACOSX_DEPLOYMENT_TARGET: 10.7
@@ -515,7 +515,7 @@ jobs:
           # This target only needs to support 11.0 and up as nothing else supports the hardware
           - name: dist-aarch64-apple
             env:
-              SCRIPT: ./x.py dist --stage 2
+              SCRIPT: ./x.py dist bootstrap --include-default-paths --stage 2
               RUST_CONFIGURE_ARGS: >-
                 --build=x86_64-apple-darwin
                 --host=aarch64-apple-darwin
@@ -659,7 +659,7 @@ jobs:
                 --target=x86_64-pc-windows-msvc
                 --enable-full-tools
                 --enable-profiler
-              SCRIPT: PGO_HOST=x86_64-pc-windows-msvc src/ci/pgo.sh python x.py dist
+              SCRIPT: PGO_HOST=x86_64-pc-windows-msvc src/ci/pgo.sh python x.py dist bootstrap --include-default-paths
               DIST_REQUIRE_ALL_TOOLS: 1
             <<: *job-windows-xl
 
@@ -671,7 +671,7 @@ jobs:
                 --target=i686-pc-windows-msvc,i586-pc-windows-msvc
                 --enable-full-tools
                 --enable-profiler
-              SCRIPT: python x.py dist
+              SCRIPT: python x.py dist bootstrap --include-default-paths
               DIST_REQUIRE_ALL_TOOLS: 1
             <<: *job-windows-xl
 
@@ -682,7 +682,7 @@ jobs:
                 --host=aarch64-pc-windows-msvc
                 --enable-full-tools
                 --enable-profiler
-              SCRIPT: python x.py dist
+              SCRIPT: python x.py dist bootstrap --include-default-paths
               DIST_REQUIRE_ALL_TOOLS: 1
               # Hack around this SDK version, because it doesn't work with clang.
               # See https://github.com/rust-lang/rust/issues/88796
@@ -699,14 +699,14 @@ jobs:
               # We are intentionally allowing an old toolchain on this builder (and that's
               # incompatible with LLVM downloads today).
               NO_DOWNLOAD_CI_LLVM: 1
-              SCRIPT: python x.py dist
+              SCRIPT: python x.py dist bootstrap --include-default-paths
               CUSTOM_MINGW: 1
               DIST_REQUIRE_ALL_TOOLS: 1
             <<: *job-windows-xl
 
           - name: dist-x86_64-mingw
             env:
-              SCRIPT: python x.py dist
+              SCRIPT: python x.py dist bootstrap --include-default-paths
               RUST_CONFIGURE_ARGS: >-
                 --build=x86_64-pc-windows-gnu
                 --enable-full-tools
@@ -722,7 +722,7 @@ jobs:
           - name: dist-x86_64-msvc-alt
             env:
               RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler
-              SCRIPT: python x.py dist
+              SCRIPT: python x.py dist bootstrap --include-default-paths
             <<: *job-windows-xl
 
   try:
diff --git a/src/ci/run.sh b/src/ci/run.sh
index 9a247fb60a8..9d98ce22498 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -69,6 +69,11 @@ RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.codegen-units-std=1"
 # space required for CI artifacts.
 RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --dist-compression-formats=xz"
 
+# Enable the `c` feature for compiler_builtins, but only when the `compiler-rt` source is available.
+if [ "$EXTERNAL_LLVM" = "" ]; then
+  RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.optimized-compiler-builtins"
+fi
+
 if [ "$DIST_SRC" = "" ]; then
   RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-dist-src"
 fi
diff --git a/src/doc/unstable-book/src/compiler-flags/self-profile-events.md b/src/doc/unstable-book/src/compiler-flags/self-profile-events.md
index 3ce18743be5..3e644f786f6 100644
--- a/src/doc/unstable-book/src/compiler-flags/self-profile-events.md
+++ b/src/doc/unstable-book/src/compiler-flags/self-profile-events.md
@@ -41,7 +41,7 @@ $ rustc -Zself-profile -Zself-profile-events=default,args
 
 - `llvm`
   - Adds tracing information about LLVM passes and codegeneration.
-  - Disabled by default because this only works when `-Znew-llvm-pass-manager` is enabled.
+  - Disabled by default because this significantly increases the trace file size.
 
 ## Event synonyms
 
diff --git a/src/etc/natvis/libcore.natvis b/src/etc/natvis/libcore.natvis
index a4e8a57e4b1..624d8cc5cc5 100644
--- a/src/etc/natvis/libcore.natvis
+++ b/src/etc/natvis/libcore.natvis
@@ -154,10 +154,10 @@
   </Type>
 
   <Type Name="core::time::Duration">
-    <DisplayString>{secs,d}s {nanos,d}ns</DisplayString>
+    <DisplayString>{secs,d}s {nanos.__0,d}ns</DisplayString>
     <Expand>
       <Item Name="seconds">secs,d</Item>
-      <Item Name="nanoseconds">nanos,d</Item>
+      <Item Name="nanoseconds">nanos.__0,d</Item>
     </Expand>
   </Type>
 </AutoVisualizer>
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index c8aa51c3a49..7893429f26f 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -718,10 +718,6 @@ pub(crate) fn record_extern_trait(cx: &mut DocContext<'_>, did: DefId) {
     debug!("record_extern_trait: {:?}", did);
     let trait_ = build_external_trait(cx, did);
 
-    let trait_ = clean::TraitWithExtraInfo {
-        trait_,
-        is_notable: clean::utils::has_doc_flag(cx.tcx, did, sym::notable_trait),
-    };
     cx.external_traits.borrow_mut().insert(did, trait_);
     cx.active_extern_traits.remove(&did);
 }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 375737e9bc4..704292c1048 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -17,6 +17,7 @@ use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::PredicateOrigin;
+use rustc_hir_analysis::hir_ty_to_ty;
 use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
 use rustc_middle::middle::resolve_lifetime as rl;
 use rustc_middle::ty::fold::TypeFolder;
@@ -26,7 +27,6 @@ use rustc_middle::{bug, span_bug};
 use rustc_span::hygiene::{AstPass, MacroKind};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{self, ExpnKind};
-use rustc_typeck::hir_ty_to_ty;
 
 use std::assert_matches::assert_matches;
 use std::collections::hash_map::Entry;
@@ -632,7 +632,7 @@ fn clean_ty_generics<'tcx>(
     let mut impl_trait = BTreeMap::<ImplTraitParam, Vec<GenericBound>>::default();
 
     // Bounds in the type_params and lifetimes fields are repeated in the
-    // predicates field (see rustc_typeck::collect::ty_generics), so remove
+    // predicates field (see rustc_hir_analysis::collect::ty_generics), so remove
     // them.
     let stripped_params = gens
         .params
@@ -1080,7 +1080,7 @@ pub(crate) fn clean_impl_item<'tcx>(
         let mut what_rustc_thinks =
             Item::from_def_id_and_parts(local_did, Some(impl_.ident.name), inner, cx);
 
-        let impl_ref = cx.tcx.impl_trait_ref(cx.tcx.local_parent(impl_.def_id));
+        let impl_ref = cx.tcx.impl_trait_ref(cx.tcx.local_parent(impl_.def_id.def_id));
 
         // Trait impl items always inherit the impl's visibility --
         // we don't want to show `pub`.
@@ -1325,7 +1325,7 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type
                 segments: trait_segments.iter().map(|x| clean_path_segment(x, cx)).collect(),
             };
             register_res(cx, trait_.res);
-            let self_def_id = DefId::local(qself.hir_id.owner.local_def_index);
+            let self_def_id = DefId::local(qself.hir_id.owner.def_id.local_def_index);
             let self_type = clean_ty(qself, cx);
             let should_show_cast = compute_should_show_cast(Some(self_def_id), &trait_, &self_type);
             Type::QPath(Box::new(QPathData {
@@ -2037,7 +2037,7 @@ fn clean_extern_crate<'tcx>(
     cx: &mut DocContext<'tcx>,
 ) -> Vec<Item> {
     // this is the ID of the `extern crate` statement
-    let cnum = cx.tcx.extern_mod_stmt_cnum(krate.def_id).unwrap_or(LOCAL_CRATE);
+    let cnum = cx.tcx.extern_mod_stmt_cnum(krate.def_id.def_id).unwrap_or(LOCAL_CRATE);
     // this is the ID of the crate itself
     let crate_def_id = cnum.as_def_id();
     let attrs = cx.tcx.hir().attrs(krate.hir_id());
@@ -2099,7 +2099,7 @@ fn clean_use_statement<'tcx>(
     let attrs = cx.tcx.hir().attrs(import.hir_id());
     let inline_attr = attrs.lists(sym::doc).get_word_attr(sym::inline);
     let pub_underscore = visibility.is_public() && name == kw::Underscore;
-    let current_mod = cx.tcx.parent_module_from_def_id(import.def_id);
+    let current_mod = cx.tcx.parent_module_from_def_id(import.def_id.def_id);
 
     // The parent of the module in which this import resides. This
     // is the same as `current_mod` if that's already the top
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index f973fd0889e..5a4fa05e261 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -21,6 +21,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{BodyId, Mutability};
+use rustc_hir_analysis::check::intrinsic::intrinsic_operation_unsafety;
 use rustc_index::vec::IndexVec;
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::{self, TyCtxt};
@@ -31,7 +32,6 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{self, FileName, Loc};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi::Abi;
-use rustc_typeck::check::intrinsic::intrinsic_operation_unsafety;
 
 use crate::clean::cfg::Cfg;
 use crate::clean::clean_visibility;
@@ -119,7 +119,7 @@ pub(crate) struct Crate {
     pub(crate) module: Item,
     pub(crate) primitives: ThinVec<(DefId, PrimitiveType)>,
     /// Only here so that they can be filtered through the rustdoc passes.
-    pub(crate) external_traits: Rc<RefCell<FxHashMap<DefId, TraitWithExtraInfo>>>,
+    pub(crate) external_traits: Rc<RefCell<FxHashMap<DefId, Trait>>>,
 }
 
 impl Crate {
@@ -132,13 +132,6 @@ impl Crate {
     }
 }
 
-/// This struct is used to wrap additional information added by rustdoc on a `trait` item.
-#[derive(Clone, Debug)]
-pub(crate) struct TraitWithExtraInfo {
-    pub(crate) trait_: Trait,
-    pub(crate) is_notable: bool,
-}
-
 #[derive(Copy, Clone, Debug)]
 pub(crate) struct ExternalCrate {
     pub(crate) crate_num: CrateNum,
@@ -689,7 +682,7 @@ impl Item {
                 let abi = tcx.fn_sig(self.item_id.as_def_id().unwrap()).abi();
                 hir::FnHeader {
                     unsafety: if abi == Abi::RustIntrinsic {
-                        intrinsic_operation_unsafety(self.name.unwrap())
+                        intrinsic_operation_unsafety(tcx, self.item_id.as_def_id().unwrap())
                     } else {
                         hir::Unsafety::Unsafe
                     },
@@ -1530,6 +1523,9 @@ impl Trait {
     pub(crate) fn is_auto(&self, tcx: TyCtxt<'_>) -> bool {
         tcx.trait_is_auto(self.def_id)
     }
+    pub(crate) fn is_notable_trait(&self, tcx: TyCtxt<'_>) -> bool {
+        tcx.is_doc_notable_trait(self.def_id)
+    }
     pub(crate) fn unsafety(&self, tcx: TyCtxt<'_>) -> hir::Unsafety {
         tcx.trait_def(self.def_id).unsafety
     }
@@ -2201,8 +2197,11 @@ impl Path {
     /// Checks if this is a `T::Name` path for an associated type.
     pub(crate) fn is_assoc_ty(&self) -> bool {
         match self.res {
-            Res::SelfTy { .. } if self.segments.len() != 1 => true,
-            Res::Def(DefKind::TyParam, _) if self.segments.len() != 1 => true,
+            Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _)
+                if self.segments.len() != 1 =>
+            {
+                true
+            }
             Res::Def(DefKind::AssocTy, _) => true,
             _ => false,
         }
@@ -2535,12 +2534,11 @@ mod size_asserts {
     // These are in alphabetical order, which is easy to maintain.
     static_assert_size!(Crate, 72); // frequently moved by-value
     static_assert_size!(DocFragment, 32);
-    #[cfg(not(bootstrap))]
-    static_assert_size!(GenericArg, 56);
+    static_assert_size!(GenericArg, 48);
     static_assert_size!(GenericArgs, 32);
     static_assert_size!(GenericParamDef, 56);
     static_assert_size!(Item, 56);
-    static_assert_size!(ItemKind, 96);
+    static_assert_size!(ItemKind, 88);
     static_assert_size!(PathSegment, 40);
-    static_assert_size!(Type, 56);
+    static_assert_size!(Type, 48);
 }
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index edcd81061f8..6b844710514 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -454,7 +454,9 @@ pub(crate) fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type {
 
     match path.res {
         Res::PrimTy(p) => Primitive(PrimitiveType::from(p)),
-        Res::SelfTy { .. } if path.segments.len() == 1 => Generic(kw::SelfUpper),
+        Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } if path.segments.len() == 1 => {
+            Generic(kw::SelfUpper)
+        }
         Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => Generic(path.segments[0].name),
         _ => {
             let _ = register_res(cx, path.res);
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 76562d26a55..f00dff9828d 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -25,7 +25,7 @@ use std::rc::Rc;
 use std::sync::LazyLock;
 
 use crate::clean::inline::build_external_trait;
-use crate::clean::{self, ItemId, TraitWithExtraInfo};
+use crate::clean::{self, ItemId};
 use crate::config::{Options as RustdocOptions, OutputFormat, RenderOptions};
 use crate::formats::cache::Cache;
 use crate::passes::collect_intra_doc_links::PreprocessedMarkdownLink;
@@ -58,7 +58,7 @@ pub(crate) struct DocContext<'tcx> {
     /// Most of this logic is copied from rustc_lint::late.
     pub(crate) param_env: ParamEnv<'tcx>,
     /// Later on moved through `clean::Crate` into `cache`
-    pub(crate) external_traits: Rc<RefCell<FxHashMap<DefId, clean::TraitWithExtraInfo>>>,
+    pub(crate) external_traits: Rc<RefCell<FxHashMap<DefId, clean::Trait>>>,
     /// Used while populating `external_traits` to ensure we don't process the same trait twice at
     /// the same time.
     pub(crate) active_extern_traits: FxHashSet<DefId>,
@@ -293,7 +293,7 @@ pub(crate) fn create_config(
         override_queries: Some(|_sess, providers, _external_providers| {
             // Most lints will require typechecking, so just don't run them.
             providers.lint_mod = |_, _| {};
-            // Prevent `rustc_typeck::check_crate` from calling `typeck` on all bodies.
+            // Prevent `rustc_hir_analysis::check_crate` from calling `typeck` on all bodies.
             providers.typeck_item_bodies = |_, _| {};
             // hack so that `used_trait_imports` won't try to call typeck
             providers.used_trait_imports = |_, _| {
@@ -388,9 +388,7 @@ pub(crate) fn run_global_ctxt(
     // Note that in case of `#![no_core]`, the trait is not available.
     if let Some(sized_trait_did) = ctxt.tcx.lang_items().sized_trait() {
         let sized_trait = build_external_trait(&mut ctxt, sized_trait_did);
-        ctxt.external_traits
-            .borrow_mut()
-            .insert(sized_trait_did, TraitWithExtraInfo { trait_: sized_trait, is_notable: false });
+        ctxt.external_traits.borrow_mut().insert(sized_trait_did, sized_trait);
     }
 
     debug!("crate: {:?}", tcx.hir().krate());
diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs
index ed702f5c4a9..c6f1f9de51a 100644
--- a/src/librustdoc/fold.rs
+++ b/src/librustdoc/fold.rs
@@ -94,7 +94,7 @@ pub(crate) trait DocFolder: Sized {
 
         let external_traits = { std::mem::take(&mut *c.external_traits.borrow_mut()) };
         for (k, mut v) in external_traits {
-            v.trait_.items = v.trait_.items.into_iter().filter_map(|i| self.fold_item(i)).collect();
+            v.items = v.items.into_iter().filter_map(|i| self.fold_item(i)).collect();
             c.external_traits.borrow_mut().insert(k, v);
         }
 
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index 86392610d2c..2e428cfddcf 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -4,7 +4,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::{sym, Symbol};
+use rustc_span::Symbol;
 
 use crate::clean::{self, types::ExternalLocation, ExternalCrate, ItemId, PrimitiveType};
 use crate::core::DocContext;
@@ -62,7 +62,7 @@ pub(crate) struct Cache {
     /// Implementations of a crate should inherit the documentation of the
     /// parent trait if no extra documentation is specified, and default methods
     /// should show up in documentation about trait implementations.
-    pub(crate) traits: FxHashMap<DefId, clean::TraitWithExtraInfo>,
+    pub(crate) traits: FxHashMap<DefId, clean::Trait>,
 
     /// When rendering traits, it's often useful to be able to list all
     /// implementors of the trait, and this mapping is exactly, that: a mapping
@@ -225,12 +225,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
         // Propagate a trait method's documentation to all implementors of the
         // trait.
         if let clean::TraitItem(ref t) = *item.kind {
-            self.cache.traits.entry(item.item_id.expect_def_id()).or_insert_with(|| {
-                clean::TraitWithExtraInfo {
-                    trait_: *t.clone(),
-                    is_notable: item.attrs.has_doc_flag(sym::notable_trait),
-                }
-            });
+            self.cache.traits.entry(item.item_id.expect_def_id()).or_insert_with(|| (**t).clone());
         }
 
         // Collect all the implementors of traits.
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 8922bf37785..78b98431b19 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -13,6 +13,7 @@ use std::collections::VecDeque;
 use std::fmt::{Display, Write};
 
 use rustc_data_structures::fx::FxHashMap;
+use rustc_lexer::Cursor;
 use rustc_lexer::{LiteralKind, TokenKind};
 use rustc_span::edition::Edition;
 use rustc_span::symbol::Symbol;
@@ -408,15 +409,16 @@ enum Highlight<'a> {
 
 struct TokenIter<'a> {
     src: &'a str,
+    cursor: Cursor<'a>,
 }
 
 impl<'a> Iterator for TokenIter<'a> {
     type Item = (TokenKind, &'a str);
     fn next(&mut self) -> Option<(TokenKind, &'a str)> {
-        if self.src.is_empty() {
+        let token = self.cursor.advance_token();
+        if token.kind == TokenKind::Eof {
             return None;
         }
-        let token = rustc_lexer::first_token(self.src);
         let (text, rest) = self.src.split_at(token.len as usize);
         self.src = rest;
         Some((token.kind, text))
@@ -525,7 +527,7 @@ impl<'a> Classifier<'a> {
     /// Takes as argument the source code to HTML-ify, the rust edition to use and the source code
     /// file span which will be used later on by the `span_correspondance_map`.
     fn new(src: &str, file_span: Span, decoration_info: Option<DecorationInfo>) -> Classifier<'_> {
-        let tokens = PeekIter::new(TokenIter { src });
+        let tokens = PeekIter::new(TokenIter { src, cursor: Cursor::new(src) });
         let decorations = decoration_info.map(Decorations::new);
         Classifier {
             tokens,
@@ -850,6 +852,7 @@ impl<'a> Classifier<'a> {
                 Class::Ident(self.new_span(before, text))
             }
             TokenKind::Lifetime { .. } => Class::Lifetime,
+            TokenKind::Eof => panic!("Eof in advance"),
         };
         // Anything that didn't return above is the simple case where we the
         // class just spans a single token, so we can use the `string` method.
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 1c4e666cd94..aa9788fad2b 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1294,7 +1294,12 @@ fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
                 if let Some(trait_) = &impl_.trait_ {
                     let trait_did = trait_.def_id();
 
-                    if cx.cache().traits.get(&trait_did).map_or(false, |t| t.is_notable) {
+                    if cx
+                        .cache()
+                        .traits
+                        .get(&trait_did)
+                        .map_or(false, |t| t.is_notable_trait(cx.tcx()))
+                    {
                         if out.is_empty() {
                             write!(
                                 &mut out,
@@ -1598,7 +1603,7 @@ fn render_impl(
             link,
             render_mode,
             false,
-            trait_.map(|t| &t.trait_),
+            trait_,
             rendering_params,
         );
     }
@@ -1658,7 +1663,7 @@ fn render_impl(
                 &mut default_impl_items,
                 &mut impl_items,
                 cx,
-                &t.trait_,
+                t,
                 i.inner_impl(),
                 &i.impl_item,
                 parent,
@@ -1790,7 +1795,7 @@ pub(crate) fn render_impl_summary(
     write!(w, "<section id=\"{}\" class=\"impl has-srclink\"{}>", id, aliases);
     render_rightside(w, cx, &i.impl_item, containing_item, RenderMode::Normal);
     write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
-    write!(w, "<h3 class=\"code-header in-band\">");
+    write!(w, "<h3 class=\"code-header\">");
 
     if let Some(use_absolute) = use_absolute {
         write!(w, "{}", inner_impl.print(use_absolute, cx));
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 3e324bbb069..9f6b6b52536 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -716,7 +716,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
         document(&mut content, cx, m, Some(t), HeadingOffset::H5);
         let toggled = !content.is_empty();
         if toggled {
-            write!(w, "<details class=\"rustdoc-toggle\" open><summary>");
+            write!(w, "<details class=\"rustdoc-toggle method-toggle\" open><summary>");
         }
         write!(w, "<div id=\"{}\" class=\"method has-srclink\">", id);
         render_rightside(w, cx, m, t, RenderMode::Normal);
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index 2e2bee78b95..7ab65bff346 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -274,7 +274,7 @@ pub(crate) fn print_src(
 ) {
     let lines = s.lines().count();
     let mut line_numbers = Buffer::empty_from(buf);
-    line_numbers.write_str("<pre class=\"line-numbers\">");
+    line_numbers.write_str("<pre class=\"src-line-numbers\">");
     match source_context {
         SourceContext::Standalone => {
             for line in 1..=lines {
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 4136cb6cab3..e92e9137d64 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -132,12 +132,19 @@ h1, h2, h3, h4, h5, h6 {
 	font-weight: 500;
 }
 h1, h2, h3, h4 {
-	margin: 20px 0 15px 0;
+	margin: 25px 0 15px 0;
 	padding-bottom: 6px;
 }
 .docblock h3, .docblock h4, h5, h6 {
 	margin: 15px 0 5px 0;
 }
+.docblock > h2:first-child,
+.docblock > h3:first-child,
+.docblock > h4:first-child,
+.docblock > h5:first-child,
+.docblock > h6:first-child {
+	margin-top: 0;
+}
 h1.fqn {
 	margin: 0;
 	padding: 0;
@@ -176,8 +183,6 @@ h4.code-header {
 	border-bottom-style: none;
 	margin: 0;
 	padding: 0;
-	margin-top: 0.6em;
-	margin-bottom: 0.4em;
 }
 .impl,
 .impl-items .method,
@@ -189,10 +194,10 @@ h4.code-header {
 .impl-items .associatedtype,
 .methods .associatedtype {
 	flex-basis: 100%;
-	font-weight: 600;
 	position: relative;
 }
 
+#crate-search,
 h1, h2, h3, h4, h5, h6,
 .sidebar,
 .mobile-topbar,
@@ -257,7 +262,9 @@ pre.rust a,
 }
 
 .content span.fn, .content a.fn,
-.content .fnname {
+.content .fnname,
+.content span.method, .content a.method,
+.content span.tymethod, .content a.tymethod {
 	color: var(--function-link-color);
 }
 
@@ -292,6 +299,11 @@ p {
 	   https://www.w3.org/WAI/WCAG21/Understanding/visual-presentation.html */
 	margin: 0 0 .75em 0;
 }
+/* For the last child of a div, the margin will be taken care of
+	by the margin-top of the next item. */
+p:last-child {
+	margin: 0;
+}
 
 summary {
 	outline: none;
@@ -299,25 +311,6 @@ summary {
 
 /* Fix some style changes due to normalize.css 8 */
 
-td,
-th {
-	padding: 0;
-}
-
-table {
-	border-collapse: collapse;
-}
-
-button,
-input,
-optgroup,
-select,
-textarea {
-	color: inherit;
-	font: inherit;
-	margin: 0;
-}
-
 button {
 	/* Buttons on Safari have different default padding than other platforms. Make them the same. */
 	padding: 1px 6px;
@@ -574,11 +567,18 @@ h2.location a {
 
 .rustdoc .example-wrap {
 	display: flex;
-	margin-bottom: 10px;
 	position: relative;
 }
+.rustdoc .example-wrap {
+	margin-bottom: 10px;
+}
+/* For the last child of a div, the margin will be taken care of
+	by the margin-top of the next item. */
+.rustdoc .example-wrap:last-child {
+	margin-bottom: 0px;
+}
 
-.example-wrap > pre.line-number {
+pre.example-line-numbers {
 	overflow: initial;
 	border: 1px solid;
 	padding: 13px 8px;
@@ -591,15 +591,15 @@ h2.location a {
 	text-decoration: underline;
 }
 
-.line-numbers {
+.src-line-numbers {
 	text-align: right;
 }
-.rustdoc:not(.source) .example-wrap > pre:not(.line-number) {
+.rustdoc:not(.source) .example-wrap > pre:not(.example-line-numbers) {
 	width: 100%;
 	overflow-x: auto;
 }
 
-.rustdoc:not(.source) .example-wrap > pre.line-numbers {
+.rustdoc:not(.source) .example-wrap > pre.src-line-numbers {
 	width: auto;
 	overflow-x: visible;
 }
@@ -612,14 +612,14 @@ h2.location a {
 	text-align: center;
 }
 
-.content > .example-wrap pre.line-numbers {
+.content > .example-wrap pre.src-line-numbers {
 	position: relative;
 	-webkit-user-select: none;
 	-moz-user-select: none;
 	-ms-user-select: none;
 	user-select: none;
 }
-.line-numbers span {
+.src-line-numbers span {
 	cursor: pointer;
 }
 
@@ -658,18 +658,17 @@ h2.location a {
 	overflow-x: auto;
 }
 
-.content .out-of-band {
+.out-of-band {
 	flex-grow: 0;
 	font-size: 1.125rem;
 	font-weight: normal;
-	float: right;
 }
 
 .method > .code-header, .trait-impl > .code-header {
 	display: block;
 }
 
-.content .in-band {
+.in-band {
 	flex-grow: 1;
 	margin: 0px;
 	padding: 0px;
@@ -682,10 +681,6 @@ h2.location a {
 	background-color: var(--main-background-color);
 }
 
-.in-band > code, .in-band > .code-header {
-	display: inline-block;
-}
-
 .docblock code, .docblock-short code,
 pre, .rustdoc.source .example-wrap {
 	background-color: var(--code-block-background-color);
@@ -700,6 +695,7 @@ pre, .rustdoc.source .example-wrap {
 	width: calc(100% - 2px);
 	overflow-x: auto;
 	display: block;
+	border-collapse: collapse;
 }
 
 .docblock table td {
@@ -739,10 +735,6 @@ pre, .rustdoc.source .example-wrap {
 	margin-left: 24px;
 }
 
-.content .impl-items .docblock, .content .impl-items .item-info {
-	margin-bottom: .6em;
-}
-
 #main-content > .item-info {
 	margin-top: 0;
 	margin-left: 0;
@@ -892,6 +884,9 @@ table,
 	/* Removes default arrow from firefox */
 	text-indent: 0.01px;
 	background-color: var(--main-background-color);
+	color: inherit;
+	line-height: 1.5;
+	font-weight: 500;
 }
 /* cancel stylistic differences in padding in firefox
 for "appearance: none"-style (or equivalent) <select>s */
@@ -1032,8 +1027,6 @@ so that we can apply CSS-filters to change the arrow color in themes */
 	font-size: 1.125rem;
 }
 #help-button span.top {
-	text-align: center;
-	display: block;
 	margin: 10px 0;
 	border-bottom: 1px solid var(--border-color);
 	padding-bottom: 4px;
@@ -1043,9 +1036,6 @@ so that we can apply CSS-filters to change the arrow color in themes */
 	clear: both;
 	border-top: 1px solid var(--border-color);
 }
-.side-by-side {
-	text-align: initial;
-}
 .side-by-side > div {
 	width: 50%;
 	float: left;
@@ -1123,17 +1113,6 @@ so that we can apply CSS-filters to change the arrow color in themes */
 	color: var(--right-side-color);
 }
 
-
-.impl-items .srclink, .impl .srclink, .methods .srclink {
-	/* Override header settings otherwise it's too bold */
-	font-weight: normal;
-	font-size: 1rem;
-}
-
-.summary {
-	padding-right: 0px;
-}
-
 pre.rust .question-mark {
 	font-weight: bold;
 }
@@ -1384,6 +1363,8 @@ pre.rust {
 	border: 0;
 	border-top: 2px solid;
 	flex: 1;
+	line-height: 1.5;
+	color: inherit;
 }
 
 #titles > button > div.count {
@@ -1401,7 +1382,6 @@ pre.rust {
 	position: sticky;
 	top: 0;
 	left: 0;
-	font-weight: bold;
 	font-size: 1.25rem;
 	border-bottom: 1px solid;
 	display: flex;
@@ -1421,6 +1401,8 @@ pre.rust {
 	margin-bottom: 6px;
 }
 #sidebar-toggle > button {
+	font-size: inherit;
+	font-weight: bold;
 	background: none;
 	color: inherit;
 	cursor: pointer;
@@ -1449,6 +1431,7 @@ pre.rust {
 	border: 1px solid var(--border-color);
 	border-radius: 2px;
 	cursor: pointer;
+	line-height: 1.5;
 }
 
 #settings-menu > a, #help-button > button {
@@ -1549,6 +1532,16 @@ details.dir-entry a {
 	display: block;
 }
 
+/* We use CSS containment on the details elements because most sizeable elements
+	of the page are contained in one of these. This also makes re-rendering
+	faster on document changes (like closing and opening toggles).
+	Unfortunately we can't yet specify contain: content or contain: strict
+	because the [-]/[+] toggles extend past the boundaries of the <details>
+	https://developer.mozilla.org/en-US/docs/Web/CSS/contain */
+details.rustdoc-toggle {
+	contain: layout;
+}
+
 /* The hideme class is used on summary tags that contain a span with
 	placeholder text shown only when the toggle is closed. For instance,
 	"Expand description" or "Show methods". */
@@ -1735,13 +1728,13 @@ in storage.js plus the media query with (min-width: 701px)
 		flex-direction: column;
 	}
 
-	.content .out-of-band {
+	.out-of-band {
 		text-align: left;
 		margin-left: initial;
 		padding: initial;
 	}
 
-	.content .out-of-band .since::before {
+	.out-of-band .since::before {
 		content: "Since ";
 	}
 
@@ -1787,9 +1780,6 @@ in storage.js plus the media query with (min-width: 701px)
 	}
 
 	.rustdoc.source > .sidebar {
-		position: fixed;
-		margin: 0;
-		z-index: 11;
 		width: 0;
 	}
 
@@ -1901,7 +1891,6 @@ in storage.js plus the media query with (min-width: 701px)
 		border-top-right-radius: 3px;
 		border-bottom-right-radius: 3px;
 		cursor: pointer;
-		font-weight: bold;
 		border: 1px solid;
 		border-left: 0;
 	}
@@ -1917,10 +1906,6 @@ in storage.js plus the media query with (min-width: 701px)
 		border-bottom: 1px solid;
 	}
 
-	#main-content > .line-numbers {
-		margin-top: 0;
-	}
-
 	.notable-traits .notable-traits-tooltiptext {
 		left: 0;
 		top: 100%;
@@ -1977,7 +1962,7 @@ in storage.js plus the media query with (min-width: 701px)
 }
 
 @media print {
-	nav.sidebar, nav.sub, .content .out-of-band, a.srclink, #copy-path,
+	nav.sidebar, nav.sub, .out-of-band, a.srclink, #copy-path,
 	details.rustdoc-toggle[open] > summary::before, details.rustdoc-toggle > summary::before,
 	details.rustdoc-toggle.top-doc > summary {
 		display: none;
@@ -2029,21 +2014,22 @@ in storage.js plus the media query with (min-width: 701px)
 
 .method-toggle summary,
 .implementors-toggle summary,
-.impl {
+.impl,
+#implementors-list > .docblock {
 	margin-bottom: 0.75em;
 }
 
-.method-toggle[open] {
+.method-toggle[open]:not(:last-child) {
 	margin-bottom: 2em;
 }
 
-.implementors-toggle[open]  {
+.implementors-toggle[open]:not(:last-child) {
 	margin-bottom: 2em;
 }
 
-#trait-implementations-list .method-toggle,
-#synthetic-implementations-list .method-toggle,
-#blanket-implementations-list .method-toggle {
+#trait-implementations-list .method-toggle:not(:last-child),
+#synthetic-implementations-list .method-toggle:not(:last-child),
+#blanket-implementations-list .method-toggle:not(:last-child) {
 	margin-bottom: 1em;
 }
 
@@ -2080,7 +2066,7 @@ in storage.js plus the media query with (min-width: 701px)
 	padding-bottom: 0;
 }
 
-.scraped-example:not(.expanded) .code-wrapper pre.line-numbers {
+.scraped-example:not(.expanded) .code-wrapper pre.src-line-numbers {
 	overflow-x: hidden;
 }
 
@@ -2126,12 +2112,12 @@ in storage.js plus the media query with (min-width: 701px)
 	bottom: 0;
 }
 
-.scraped-example .code-wrapper .line-numbers {
+.scraped-example .code-wrapper .src-line-numbers {
 	margin: 0;
 	padding: 14px 0;
 }
 
-.scraped-example .code-wrapper .line-numbers span {
+.scraped-example .code-wrapper .src-line-numbers span {
 	padding: 0 14px;
 }
 
diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css
index e82ec042637..821c4e978e8 100644
--- a/src/librustdoc/html/static/css/settings.css
+++ b/src/librustdoc/html/static/css/settings.css
@@ -12,7 +12,8 @@
 	margin-right: 0.3em;
 	height: 1.2rem;
 	width: 1.2rem;
-	border: 1px solid;
+	color: inherit;
+	border: 1px solid currentColor;
 	outline: none;
 	-webkit-appearance: none;
 	cursor: pointer;
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index e7a898e9fa6..44238ca573d 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -93,8 +93,8 @@ pre, .rustdoc.source .example-wrap {
 	color: #ff7733;
 }
 
-.line-numbers span { color: #5c6773; }
-.line-numbers .line-highlighted {
+.src-line-numbers span { color: #5c6773; }
+.src-line-numbers .line-highlighted {
 	color: #708090;
 	background-color: rgba(255, 236, 164, 0.06);
 	padding-right: 4px;
@@ -171,7 +171,7 @@ details.rustdoc-toggle > summary::before {
 	color: #788797;
 }
 
-.line-numbers :target { background-color: transparent; }
+.src-line-numbers :target { background-color: transparent; }
 
 /* Code highlighting */
 pre.rust .number, pre.rust .string { color: #b8cc52; }
@@ -190,7 +190,7 @@ pre.rust .attribute {
 	color: #e6e1cf;
 }
 
-.example-wrap > pre.line-number {
+pre.example-line-numbers {
 	color: #5c67736e;
 	border: none;
 }
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
index 07a1ed8b7db..858d836c03d 100644
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -54,8 +54,8 @@ input:focus + .slider {
 	background: #444;
 }
 
-.line-numbers span { color: #3B91E2; }
-.line-numbers .line-highlighted {
+.src-line-numbers span { color: #3B91E2; }
+.src-line-numbers .line-highlighted {
 	background-color: #0a042f !important;
 }
 
@@ -141,7 +141,7 @@ details.rustdoc-toggle > summary::before {
 	background: none;
 }
 
-.line-numbers :target { background-color: transparent; }
+.src-line-numbers :target { background-color: transparent; }
 
 /* Code highlighting */
 pre.rust .kw { color: #ab8ac1; }
@@ -155,7 +155,7 @@ pre.rust .question-mark {
 	color: #ff9011;
 }
 
-.example-wrap > pre.line-number {
+pre.example-line-numbers {
 	border-color: #4a4949;
 }
 
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
index 64335f62928..6fbea6f6c7a 100644
--- a/src/librustdoc/html/static/css/themes/light.css
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -53,8 +53,8 @@ input:focus + .slider {
 	background-color: #fff;
 }
 
-.line-numbers span { color: #c67e2d; }
-.line-numbers .line-highlighted {
+.src-line-numbers span { color: #c67e2d; }
+.src-line-numbers .line-highlighted {
 	background-color: #FDFFD3 !important;
 }
 
@@ -125,7 +125,7 @@ body.source .example-wrap pre.rust a {
 .stab { background: #FFF5D6; border-color: #FFC600; }
 .stab.portability > code { background: none; }
 
-.line-numbers :target { background-color: transparent; }
+.src-line-numbers :target { background-color: transparent; }
 
 /* Code highlighting */
 pre.rust .kw { color: #8959A8; }
@@ -141,7 +141,7 @@ pre.rust .question-mark {
 	color: #ff9011;
 }
 
-.example-wrap > pre.line-number {
+pre.example-line-numbers {
 	border-color: #c7c7c7;
 }
 
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 5fbe540c320..bbaf6d3b507 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -555,7 +555,6 @@ function loadCss(cssFileName) {
                 const code = document.createElement("h3");
                 code.innerHTML = struct[TEXT_IDX];
                 addClass(code, "code-header");
-                addClass(code, "in-band");
 
                 onEachLazy(code.getElementsByTagName("a"), elem => {
                     const href = elem.getAttribute("href");
@@ -700,7 +699,7 @@ function loadCss(cssFileName) {
     window.rustdoc_add_line_numbers_to_examples = () => {
         onEachLazy(document.getElementsByClassName("rust-example-rendered"), x => {
             const parent = x.parentNode;
-            const line_numbers = parent.querySelectorAll(".line-number");
+            const line_numbers = parent.querySelectorAll(".example-line-numbers");
             if (line_numbers.length > 0) {
                 return;
             }
@@ -710,7 +709,7 @@ function loadCss(cssFileName) {
                 elems.push(i + 1);
             }
             const node = document.createElement("pre");
-            addClass(node, "line-number");
+            addClass(node, "example-line-numbers");
             node.innerHTML = elems.join("\n");
             parent.insertBefore(node, x);
         });
@@ -719,7 +718,7 @@ function loadCss(cssFileName) {
     window.rustdoc_remove_line_numbers_from_examples = () => {
         onEachLazy(document.getElementsByClassName("rust-example-rendered"), x => {
             const parent = x.parentNode;
-            const line_numbers = parent.querySelectorAll(".line-number");
+            const line_numbers = parent.querySelectorAll(".example-line-numbers");
             for (const node of line_numbers) {
                 parent.removeChild(node);
             }
diff --git a/src/librustdoc/html/static/js/scrape-examples.js b/src/librustdoc/html/static/js/scrape-examples.js
index fd7a1449763..d0fd115fd15 100644
--- a/src/librustdoc/html/static/js/scrape-examples.js
+++ b/src/librustdoc/html/static/js/scrape-examples.js
@@ -8,7 +8,7 @@
 
     // Scroll code block to the given code location
     function scrollToLoc(elt, loc) {
-        const lines = elt.querySelector(".line-numbers");
+        const lines = elt.querySelector(".src-line-numbers");
         let scrollOffset;
 
         // If the block is greater than the size of the viewer,
diff --git a/src/librustdoc/html/static/js/source-script.js b/src/librustdoc/html/static/js/source-script.js
index 06d15d9e5ff..8286e9201e6 100644
--- a/src/librustdoc/html/static/js/source-script.js
+++ b/src/librustdoc/html/static/js/source-script.js
@@ -183,7 +183,7 @@ function highlightSourceLines(match) {
     if (x) {
         x.scrollIntoView();
     }
-    onEachLazy(document.getElementsByClassName("line-numbers"), e => {
+    onEachLazy(document.getElementsByClassName("src-line-numbers"), e => {
         onEachLazy(e.getElementsByTagName("span"), i_e => {
             removeClass(i_e, "line-highlighted");
         });
@@ -245,7 +245,7 @@ window.addEventListener("hashchange", () => {
     }
 });
 
-onEachLazy(document.getElementsByClassName("line-numbers"), el => {
+onEachLazy(document.getElementsByClassName("src-line-numbers"), el => {
     el.addEventListener("click", handleSourceHighlight);
 });
 
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 49a31f5f1da..4170412caef 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -272,7 +272,12 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
         ConstantItem(c) => ItemEnum::Constant(c.into_tcx(tcx)),
         MacroItem(m) => ItemEnum::Macro(m.source),
         ProcMacroItem(m) => ItemEnum::ProcMacro(m.into_tcx(tcx)),
-        PrimitiveItem(p) => ItemEnum::PrimitiveType(p.as_sym().to_string()),
+        PrimitiveItem(p) => {
+            ItemEnum::Primitive(Primitive {
+                name: p.as_sym().to_string(),
+                impls: Vec::new(), // Added in JsonRenderer::item
+            })
+        }
         TyAssocConstItem(ty) => ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: None },
         AssocConstItem(ty, default) => {
             ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: Some(default.expr(tcx)) }
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index 5e8f5f6fe3e..d13efe6c113 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -108,7 +108,6 @@ impl<'tcx> JsonRenderer<'tcx> {
             .filter_map(|(&id, trait_item)| {
                 // only need to synthesize items for external traits
                 if !id.is_local() {
-                    let trait_item = &trait_item.trait_;
                     for item in &trait_item.items {
                         trace!("Adding subitem to {id:?}: {:?}", item.item_id);
                         self.item(item.clone()).unwrap();
@@ -219,12 +218,15 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
                     u.impls = self.get_impls(item_id.expect_def_id());
                     false
                 }
+                types::ItemEnum::Primitive(ref mut p) => {
+                    p.impls = self.get_impls(item_id.expect_def_id());
+                    false
+                }
 
                 types::ItemEnum::Method(_)
                 | types::ItemEnum::Module(_)
                 | types::ItemEnum::AssocConst { .. }
-                | types::ItemEnum::AssocType { .. }
-                | types::ItemEnum::PrimitiveType(_) => true,
+                | types::ItemEnum::AssocType { .. } => true,
                 types::ItemEnum::ExternCrate { .. }
                 | types::ItemEnum::Import(_)
                 | types::ItemEnum::StructField(_)
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 14d695582b0..ef01b854e5a 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -9,14 +9,12 @@
 #![feature(control_flow_enum)]
 #![feature(drain_filter)]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(test)]
 #![feature(never_type)]
 #![feature(once_cell)]
 #![feature(type_ascription)]
 #![feature(iter_intersperse)]
 #![feature(type_alias_impl_trait)]
-#![cfg_attr(bootstrap, feature(generic_associated_types))]
 #![recursion_limit = "256"]
 #![warn(rustc::internal)]
 #![allow(clippy::collapsible_if, clippy::collapsible_else_if)]
@@ -43,6 +41,7 @@ extern crate rustc_errors;
 extern crate rustc_expand;
 extern crate rustc_feature;
 extern crate rustc_hir;
+extern crate rustc_hir_analysis;
 extern crate rustc_hir_pretty;
 extern crate rustc_index;
 extern crate rustc_infer;
@@ -61,7 +60,6 @@ extern crate rustc_session;
 extern crate rustc_span;
 extern crate rustc_target;
 extern crate rustc_trait_selection;
-extern crate rustc_typeck;
 extern crate test;
 
 // See docs in https://github.com/rust-lang/rust/blob/master/compiler/rustc/src/main.rs
@@ -461,7 +459,7 @@ fn opts() -> Vec<RustcOptGroup> {
                 "human|json|short",
             )
         }),
-        unstable("diagnostic-width", |o| {
+        stable("diagnostic-width", |o| {
             o.optopt(
                 "",
                 "diagnostic-width",
diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs
index 765f7c61bd3..de3a4b33905 100644
--- a/src/librustdoc/passes/propagate_doc_cfg.rs
+++ b/src/librustdoc/passes/propagate_doc_cfg.rs
@@ -48,7 +48,7 @@ impl<'a, 'tcx> CfgPropagator<'a, 'tcx> {
             let expected_parent = hir.get_parent_item(hir_id);
             // If parents are different, it means that `item` is a reexport and we need
             // to compute the actual `cfg` by iterating through its "real" parents.
-            if self.parent == Some(expected_parent) {
+            if self.parent == Some(expected_parent.def_id) {
                 return;
             }
         }
diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs
index ca86ac89e85..dfa6ba38b88 100644
--- a/src/librustdoc/scrape_examples.rs
+++ b/src/librustdoc/scrape_examples.rs
@@ -143,14 +143,14 @@ where
         // then we need to exit before calling typeck (which will panic). See
         // test/run-make/rustdoc-scrape-examples-invalid-expr for an example.
         let hir = tcx.hir();
-        if hir.maybe_body_owned_by(ex.hir_id.owner).is_none() {
+        if hir.maybe_body_owned_by(ex.hir_id.owner.def_id).is_none() {
             return;
         }
 
         // Get type of function if expression is a function call
         let (ty, call_span, ident_span) = match ex.kind {
             hir::ExprKind::Call(f, _) => {
-                let types = tcx.typeck(ex.hir_id.owner);
+                let types = tcx.typeck(ex.hir_id.owner.def_id);
 
                 if let Some(ty) = types.node_type_opt(f.hir_id) {
                     (ty, ex.span, f.span)
@@ -160,7 +160,7 @@ where
                 }
             }
             hir::ExprKind::MethodCall(path, _, _, call_span) => {
-                let types = tcx.typeck(ex.hir_id.owner);
+                let types = tcx.typeck(ex.hir_id.owner.def_id);
                 let Some(def_id) = types.type_dependent_def_id(ex.hir_id) else {
                     trace!("type_dependent_def_id({}) = None", ex.hir_id);
                     return;
@@ -183,9 +183,8 @@ where
 
         // If the enclosing item has a span coming from a proc macro, then we also don't want to include
         // the example.
-        let enclosing_item_span = tcx
-            .hir()
-            .span_with_body(tcx.hir().local_def_id_to_hir_id(tcx.hir().get_parent_item(ex.hir_id)));
+        let enclosing_item_span =
+            tcx.hir().span_with_body(tcx.hir().get_parent_item(ex.hir_id).into());
         if enclosing_item_span.from_expansion() {
             trace!("Rejecting expr ({call_span:?}) from macro item: {enclosing_item_span:?}");
             return;
diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs
index c40274394f3..d29ceead4f3 100644
--- a/src/librustdoc/visit.rs
+++ b/src/librustdoc/visit.rs
@@ -65,7 +65,7 @@ pub(crate) trait DocVisitor: Sized {
         // FIXME: make this a simple by-ref for loop once external_traits is cleaned up
         let external_traits = { std::mem::take(&mut *c.external_traits.borrow_mut()) };
         for (k, v) in external_traits {
-            v.trait_.items.iter().for_each(|i| self.visit_item(i));
+            v.items.iter().for_each(|i| self.visit_item(i));
             c.external_traits.borrow_mut().insert(k, v);
         }
     }
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index fb183042670..7379b04ad16 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -9,7 +9,7 @@ use std::path::PathBuf;
 use serde::{Deserialize, Serialize};
 
 /// rustdoc format-version.
-pub const FORMAT_VERSION: u32 = 21;
+pub const FORMAT_VERSION: u32 = 22;
 
 /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
 /// about the language items in the local crate, as well as info about external items to allow
@@ -254,7 +254,7 @@ pub enum ItemEnum {
     Macro(String),
     ProcMacro(ProcMacro),
 
-    PrimitiveType(String),
+    Primitive(Primitive),
 
     AssocConst {
         #[serde(rename = "type")]
@@ -709,5 +709,11 @@ pub struct Static {
     pub expr: String,
 }
 
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct Primitive {
+    pub name: String,
+    pub impls: Vec<Id>,
+}
+
 #[cfg(test)]
 mod tests;
diff --git a/src/stage0.json b/src/stage0.json
index c4891a9858b..72308d50c8e 100644
--- a/src/stage0.json
+++ b/src/stage0.json
@@ -17,349 +17,349 @@
     "tool is executed."
   ],
   "compiler": {
-    "date": "2022-08-19",
+    "date": "2022-09-20",
     "version": "beta"
   },
   "rustfmt": {
-    "date": "2022-08-20",
+    "date": "2022-09-20",
     "version": "nightly"
   },
   "checksums_sha256": {
-    "dist/2022-08-19/cargo-beta-aarch64-apple-darwin.tar.gz": "79196736248e8e0f76a5d365a45fda39d5bdd815f0f2a8e4341acba31b183a22",
-    "dist/2022-08-19/cargo-beta-aarch64-apple-darwin.tar.xz": "2cad3b28e9ee50c01d031b9c0086f40ccc16845ff2496e91fb1adebc8560b1ec",
-    "dist/2022-08-19/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "c725c27d06a4201df716f50509651cf071708fc0860e2d482a8dcc7dc69011bc",
-    "dist/2022-08-19/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "f5e1c07a8043d5e94c0450e896069262f825fa534c7688465fb0e50424b052ab",
-    "dist/2022-08-19/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "4f07b76c98206ade5b18a89af56004adae0abd51be1c295f6725b6b24bd2dfa1",
-    "dist/2022-08-19/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "9ef70808f78032f2d2f60c529dd43354752df510e7eb9d7db09abc34898a0243",
-    "dist/2022-08-19/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "8c3fa219aad16a2c7a2858844bc3e9b39d2382907b5a145a21d88001d082b510",
-    "dist/2022-08-19/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "60f18159e805894e5504d84999a33396cb27d32d2827ee6b903ed9efab5ae3e7",
-    "dist/2022-08-19/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "66ae9ea36d30e5e027e452b5e4e76e7deaa0d5f7c601b781c02559a99e5a888b",
-    "dist/2022-08-19/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "61c00674f1a33234f0622e7f2b770d641b8202d1e79ce231ad372c0c5e8a0cb2",
-    "dist/2022-08-19/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "298e096659bf1a3903073f3c59bec22f763a2a8f8a9ee91f94589b8e9361bbc1",
-    "dist/2022-08-19/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "dc57c0aea0ae45d781d9a000a36b9df66532b5434024cc6c4d99d8007a0bef8f",
-    "dist/2022-08-19/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "cd21f821f8e6ff9e0b0c3d3e841192fb81a6fecb6ebffd09fa880ac07c9fe677",
-    "dist/2022-08-19/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "8757bc726950c5e8507ad0d9ae518504a9467e8cfabe590b458714be3b6fc1bf",
-    "dist/2022-08-19/cargo-beta-i686-pc-windows-gnu.tar.gz": "4c3c891c19ab8990a892fc98ee5e1546b5a8626ebd769b1b6c26cfcc636f12b4",
-    "dist/2022-08-19/cargo-beta-i686-pc-windows-gnu.tar.xz": "2da6fa16707edccedc3fb37782ae2cbee1330cc89e646a16fbb288c07fe2502d",
-    "dist/2022-08-19/cargo-beta-i686-pc-windows-msvc.tar.gz": "76c4f8be3abfff215a9a565e378fe8e5853b164e2c1ea5f91c4791851457840b",
-    "dist/2022-08-19/cargo-beta-i686-pc-windows-msvc.tar.xz": "8f49f0ca8542ca72bfc05f4928a97ccc9e825a3b7f00dc7fadc58ba184169d07",
-    "dist/2022-08-19/cargo-beta-i686-unknown-linux-gnu.tar.gz": "51b48101522af0cae055e01d025ca657fd7284fb4e3cf81839774fdef97d6c21",
-    "dist/2022-08-19/cargo-beta-i686-unknown-linux-gnu.tar.xz": "63e34d3e51a99eac167f7567002026f63b830defcff364b3029d8819ccd4abb5",
-    "dist/2022-08-19/cargo-beta-mips-unknown-linux-gnu.tar.gz": "2888d73ea48e9ca5ffb6f2db7d1ce665413229d38454e625cad4d4d9e2111feb",
-    "dist/2022-08-19/cargo-beta-mips-unknown-linux-gnu.tar.xz": "cc361abd32f693e2b0d44d718c9d14cf4f4e9333eb965a888013abc1abf2e81d",
-    "dist/2022-08-19/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "7c180166f2ab5c91ed218d2f9fa2ad552e47818a268347bf5be48cad36f14858",
-    "dist/2022-08-19/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "1e5895d5ccd86c5fe13362d8763e9a75ec46909e7c4840dcc84286aa7bf4b367",
-    "dist/2022-08-19/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "6890940f4e02979b6bb8496faf7e71d75c317be563b35c44fdaebdfe11b62cd1",
-    "dist/2022-08-19/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "37bf3bed41ed98d1517d5e925ca22ca39c6d51ab1e65b2e7fd9e8f082364d258",
-    "dist/2022-08-19/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "aaaef89dd7ef0cf07a400cecdd70851be23d066b0522d2e89f94358ea196ebeb",
-    "dist/2022-08-19/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "17c883e6c59a892a4eceee482f27eef60a020f417e06e9c1282992fc085b6106",
-    "dist/2022-08-19/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "722efeb58b8d6802ecc52bfc686b4a1a24fd7b9494e93ed7cb8e4ac974e5c161",
-    "dist/2022-08-19/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "26b3572b77ff7faaf40c06204852683408fda2aa4256167611ac1d0c177789de",
-    "dist/2022-08-19/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "93c504cbade48dc07b4e839d85fa6f477f28ab140c894e8f9acec6477f21e7db",
-    "dist/2022-08-19/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "72354c21c154868a9b1c420047cf2a9eb5aaae20e93dde41f8283ad6e441a744",
-    "dist/2022-08-19/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "ba4c589975b4ca7ae10c98d07c02bae50b7c5d0bcaded77f1ccfefbf555d4116",
-    "dist/2022-08-19/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "fe9e8e7cbb9a1b00871e11b54ae3f64bc35dc4cc80ca49e59b4d8daf5fbdeea4",
-    "dist/2022-08-19/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "287e7a014a6d8e650124c71c87bbd9655785564f4ee1f179a9226ce371e8d78c",
-    "dist/2022-08-19/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "4e35f5a198bbcc06842569e2fda1985e77794425f2e85f1948d7a7664125099b",
-    "dist/2022-08-19/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "05e091a433009843f0dcc295b5b53b46ba2f55a37f7057c777a9cd92c094cba3",
-    "dist/2022-08-19/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "54202c092c265bff6be7f598ce1f6e96a84a5ba4c354d9bbd4986475cf0b809d",
-    "dist/2022-08-19/cargo-beta-x86_64-apple-darwin.tar.gz": "0ae9a6dde1693d33ff774f435bba3e18b67e2d8ce757df5e26ac3b757733cb29",
-    "dist/2022-08-19/cargo-beta-x86_64-apple-darwin.tar.xz": "d67c4c748443be773016d27a74e859428b404a7fb06e651b1fdbc205ea08c03b",
-    "dist/2022-08-19/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "fd617b76eb4d9d951ca9757a31fe92c8cfeb76b093e09262728c7737aa9d2970",
-    "dist/2022-08-19/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "14f263241b90e91fc40a75361e4b8de23165cf8b7c973bc7016a9bf337381ec0",
-    "dist/2022-08-19/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "c5440958cc976526109ef17b4883e27394d6ce087d90653956371837de5a7f8f",
-    "dist/2022-08-19/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "8e3c28a0e593651b530bed0fb5216ca8f04ebc54e98b8cb83cfae3ea13c1c8a1",
-    "dist/2022-08-19/cargo-beta-x86_64-unknown-freebsd.tar.gz": "c80991b59c39129fce5f775c5f1b530592d04060bfee7f7a7a443da698efc50f",
-    "dist/2022-08-19/cargo-beta-x86_64-unknown-freebsd.tar.xz": "81fe7a26762f503c04000f954986c25be1acbaa6687389b70a48e4230901fdfe",
-    "dist/2022-08-19/cargo-beta-x86_64-unknown-illumos.tar.gz": "8b08d6c4c41c3ab05ea3310d44943a3453254c96df92b5f25cc888c4fb7d31fe",
-    "dist/2022-08-19/cargo-beta-x86_64-unknown-illumos.tar.xz": "eb4705ba79bc9b7d2a3969748d966c7faf305ab196bd002856fe5a0499c11989",
-    "dist/2022-08-19/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "b0f14a0bfa064b4511dc34a71039af3c69b006b51906f9087bc7929014b9db76",
-    "dist/2022-08-19/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "3d8cdbc3679550a374e29b4a363b30048e2d65d3d4b9c9dbaeb0a907606afee3",
-    "dist/2022-08-19/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "2f564886b29fece08e8ccf4fdaf6035b5819d03fc963ce46cd6225a79e2d4da0",
-    "dist/2022-08-19/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "78f7ed8eb7e8d147113472f6402688e0127a41a1a26679c19c9e558bf39e8df7",
-    "dist/2022-08-19/cargo-beta-x86_64-unknown-netbsd.tar.gz": "3edff35d00c5af406b72db5e2ee33340c05d24a4bdf4658f172b7d74994825ff",
-    "dist/2022-08-19/cargo-beta-x86_64-unknown-netbsd.tar.xz": "96b290796ea1781fb5a69838f969591b70e5e193efeab85f4e7c45dfb2c698f2",
-    "dist/2022-08-19/rust-std-beta-aarch64-apple-darwin.tar.gz": "c7b09f59bdd2cf91a9aaf771257a474655ed5905f5455f9a3b47bb832d1f124c",
-    "dist/2022-08-19/rust-std-beta-aarch64-apple-darwin.tar.xz": "b82c8c4a454f59218b22eb04a346b78215c10269c001e28395080abefaa9e6f4",
-    "dist/2022-08-19/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "cbccc251b16f41383845d5d1d6196f33d2769df7455f308c096e0af46b43d14c",
-    "dist/2022-08-19/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "99be53158e3ee2b467d75d26d461e7aa4330301c6dba74c048331b16e09188c5",
-    "dist/2022-08-19/rust-std-beta-aarch64-apple-ios.tar.gz": "bf94ccc4bc6a4c171cd60d7a62c34d32e09b242a7029b69feef6159cf4c22fee",
-    "dist/2022-08-19/rust-std-beta-aarch64-apple-ios.tar.xz": "6a9a910573ea80de9618c7bf46e21e93341db652e4d82bee06e73544b92805f4",
-    "dist/2022-08-19/rust-std-beta-aarch64-fuchsia.tar.gz": "27693e376c29e561844e43ef21d006942e44263076ab4144643827b671ea3339",
-    "dist/2022-08-19/rust-std-beta-aarch64-fuchsia.tar.xz": "81d00752188815a7747f89ba76610d91d276459543e6c4362f1f86ecacc28f2d",
-    "dist/2022-08-19/rust-std-beta-aarch64-linux-android.tar.gz": "6f076bd4565d9af83003e1165e24fb912eca0adaf40a40f1d87956ff8dff535a",
-    "dist/2022-08-19/rust-std-beta-aarch64-linux-android.tar.xz": "a0f528910137d9b7e0e6dd371dad181f7d48d270e8ae289d8b7996440bef101b",
-    "dist/2022-08-19/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "6ac6afb78d0c3e55cffc6cc52bba51259fe83aac35075cebdb6940ad3d147b60",
-    "dist/2022-08-19/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "f1043c1fa0d0d75f8001d854967f2ec8be6def5845662505048742e6472ebb87",
-    "dist/2022-08-19/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "d3390a8cb0617551cdce7bb9348fc39a304c877bf5c5ce02ec9cdf636a69571d",
-    "dist/2022-08-19/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "81da17399275e43ec9b15983faa9828df2a8dbc72ea15d16671d0c31d4d0795c",
-    "dist/2022-08-19/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "3deca6def0ebb3476898e1ee7368592a034867d73948e51f24ad92445c6275b6",
-    "dist/2022-08-19/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "23bc4165841199f110293a627735624a2a37bc6d92019e9cb1533e006933f9d5",
-    "dist/2022-08-19/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "3360ea38f8d8bc84f2419b4ca90bfca7a9709a6fbec2ba209fe335090a534c0e",
-    "dist/2022-08-19/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "ce7643548eb6f797b7823795e27b748aaa09cd02baffaeee44bdc3c00ed796e3",
-    "dist/2022-08-19/rust-std-beta-aarch64-unknown-none.tar.gz": "5f6cd59b283ac76709e7c76c89f352e92b6818b1606b585332f36ba3c4b6a87b",
-    "dist/2022-08-19/rust-std-beta-aarch64-unknown-none.tar.xz": "60d00cacbd24576b0b247f2b12d6a63e9451912d874385b50165a312da080762",
-    "dist/2022-08-19/rust-std-beta-arm-linux-androideabi.tar.gz": "15494aade74e5e29bb0d881d243da37d3b929bd98baab7c6b0345e0a6a0ed803",
-    "dist/2022-08-19/rust-std-beta-arm-linux-androideabi.tar.xz": "d62cdfc5d0a41749ea90d6cabaa77f4f45630061a04dd3be9611cd5f0ea868d5",
-    "dist/2022-08-19/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "40e532cd37262e7280a7c0bdd54808815adba533a911bd46a1d9b76d0446b958",
-    "dist/2022-08-19/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "bb08d0ca767f257fb13f6a946e7c725dc877055f94d324128eab521d43cc552b",
-    "dist/2022-08-19/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "2f22a08cee234574c48e5022e0c5b1641c2ad01fad69537b03eb9f247e7877dd",
-    "dist/2022-08-19/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "8cb10237d87a4fcf2100b5aec0623ab04c2f1d976a0f30a1a89357cb41ce6d4e",
-    "dist/2022-08-19/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "811c691d678f08627758bba341e3ac06a2d465da78d819c49de494e0602073e6",
-    "dist/2022-08-19/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "50063b02901983e3ce37e98e57e664521cb5c99ab9a1015bb949a53dfda9b49c",
-    "dist/2022-08-19/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "2ca7a740767463e432b22b846f81ab9983751279b65b4488d07202b77e378afc",
-    "dist/2022-08-19/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "8b56365bd261fb6a4c2984b51dce14d8e2c996667ba4af866153042855043916",
-    "dist/2022-08-19/rust-std-beta-armebv7r-none-eabi.tar.gz": "83ece7e0db0e1ddd44b104d52def00ce06fea37dd8c90b1c0a840d0561a76d54",
-    "dist/2022-08-19/rust-std-beta-armebv7r-none-eabi.tar.xz": "e3a343fa5f35372ace7f23e6775c8c01b9803fca9e1b686d3db695c2f754db5b",
-    "dist/2022-08-19/rust-std-beta-armebv7r-none-eabihf.tar.gz": "874dec1039af060488f34be26ba54615a12ee4cb64f3a871932936e4e736fd76",
-    "dist/2022-08-19/rust-std-beta-armebv7r-none-eabihf.tar.xz": "cdc6b9a375a40847ee4938f3609f8c49f3368394b46fa9dccf1b5b16468852f7",
-    "dist/2022-08-19/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "28e72dd4c24716224b663d341d6f784f2b0deebbf52721709fb396240e327854",
-    "dist/2022-08-19/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "5c8cf5b47b567b8bc41c3ce831f34d076396179d050bf982e1949bef74a2b2fb",
-    "dist/2022-08-19/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "dcfd76d646b17521f5a7daf94a0617a731d914612368ff112345a03a2a5b5939",
-    "dist/2022-08-19/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "7d43dfef571dc4c2e883bdf92e05dd3465b9233c30f34bf282b57826339e9e96",
-    "dist/2022-08-19/rust-std-beta-armv7-linux-androideabi.tar.gz": "4bb1f0110629b7af1fbe09a6eb8387de9aa800a95053ef7177bba30a2d1b430c",
-    "dist/2022-08-19/rust-std-beta-armv7-linux-androideabi.tar.xz": "55f97c5a16e8d65dcfa13adf989039ffcafc5a4a09aec92083d00d7e2786def9",
-    "dist/2022-08-19/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "e7fb4da36908d6cc0c13a93ec3f4b01ea1b2c515213005479da45712614c0a69",
-    "dist/2022-08-19/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "c727568116de82658335c3be93d51a7e2850cc2824b9818a166594649dd5b3ce",
-    "dist/2022-08-19/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "1a186dab35dba7fcf4982e717a1ac6d1d846b87e50e6815ac0f9b2c40e44f4d2",
-    "dist/2022-08-19/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "7f5d3c66c57ba75d3c91328f3ceccddeeebdc08f015e762e26af770a968ab14d",
-    "dist/2022-08-19/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "c0108882d6f80cb82a9fa016adfdca2478b4966c72c6d6d240c94c56fa668166",
-    "dist/2022-08-19/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "4f30e1114c7c4ca187f9a2e4b2ffdd4fa66cd2346534c80ff5a7278a846f2c8c",
-    "dist/2022-08-19/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "a69c55803776f8ccfc1685181209463ebbbd82252ba2cd47387d6ce8f8f09afb",
-    "dist/2022-08-19/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "c12d6e9f9cec1aee0dcad3ac95a33dea0522a0e00c88e1d1e5ea4a0d98119128",
-    "dist/2022-08-19/rust-std-beta-armv7a-none-eabi.tar.gz": "91cb7d15d30bea14c3f7b9ad19ccc3cf58b69abf8ff7ec2ebaf1ed60cab4940d",
-    "dist/2022-08-19/rust-std-beta-armv7a-none-eabi.tar.xz": "887aad7c712055aca460a840bb1f5b69caf4fe11a458032df73038af94285abe",
-    "dist/2022-08-19/rust-std-beta-armv7r-none-eabi.tar.gz": "54a4f38e30039211e0199bc25733572d24dd5ad9eb6fec524146c1dc08b745d4",
-    "dist/2022-08-19/rust-std-beta-armv7r-none-eabi.tar.xz": "0b6b366e0380df3513f36eac4341d5562520eff0fc995280179c6424fcc4f5db",
-    "dist/2022-08-19/rust-std-beta-armv7r-none-eabihf.tar.gz": "76f33e20c3800f2a7cc53db4552a44b5269aa8678c7f3de970071ed0f3c66dfe",
-    "dist/2022-08-19/rust-std-beta-armv7r-none-eabihf.tar.xz": "e71d8e8a2144cd4ca220cb25218aaeca7d0ba776ef10d2adebd8745bc1fdf988",
-    "dist/2022-08-19/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "50ba543bcfe3d1ca5d5606e7ea656968f70930ce074fb0110e65658e9cab9810",
-    "dist/2022-08-19/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "b2498657da8c27464213afbbad1ff95db637236a9e0f88d2c9bf0c6940a0c583",
-    "dist/2022-08-19/rust-std-beta-i586-pc-windows-msvc.tar.gz": "8275136f11ddad506a9569d3e6d1ad4b48688a1e7e498e22566ff3453675ff4b",
-    "dist/2022-08-19/rust-std-beta-i586-pc-windows-msvc.tar.xz": "8c5fae3775152a3dd3d1bc47e1ab1861efa60b51f8087fb2a63da0eb45185a79",
-    "dist/2022-08-19/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "628a29ee30489dc9bb6877a2aaccb4f5de05a5a58ef154be875643ce393776d4",
-    "dist/2022-08-19/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "ff4f7ade08cb2337d20fbaa8a6e74f662b805cb2bf142a584e10b4aae66139a9",
-    "dist/2022-08-19/rust-std-beta-i586-unknown-linux-musl.tar.gz": "3f7859c372943096d3f6a258561584cee28adb9cfeff5b98036dd7cab74dab7d",
-    "dist/2022-08-19/rust-std-beta-i586-unknown-linux-musl.tar.xz": "40323fdb61ae453d42525ea13c41b5dedd322d859f9993315a798a87634ee386",
-    "dist/2022-08-19/rust-std-beta-i686-linux-android.tar.gz": "b103802c800524bc1dc6f3d996ad47d2c03fe03b236588f8a9de3fc763ba2eff",
-    "dist/2022-08-19/rust-std-beta-i686-linux-android.tar.xz": "ecb631362408d708e63093a0bec0b735b1cdc6bb7c0509ab5852e572f796812e",
-    "dist/2022-08-19/rust-std-beta-i686-pc-windows-gnu.tar.gz": "3b7af769cb25b75fc5a657e4f3dd489e6745df2d383c5e78cc033fb46345d72e",
-    "dist/2022-08-19/rust-std-beta-i686-pc-windows-gnu.tar.xz": "f1a65b9607cd153e421f27891b5ebcdc1e4a1571613ecead7402d8794eff3330",
-    "dist/2022-08-19/rust-std-beta-i686-pc-windows-msvc.tar.gz": "e5214f670f981c7b95e690c8487323dc2a564d34f5ad4f589d2862ee11225b83",
-    "dist/2022-08-19/rust-std-beta-i686-pc-windows-msvc.tar.xz": "efe17356f42fa47949151ebfdb75ee10d14cc5a279eb4361c79f36c5c322d9cb",
-    "dist/2022-08-19/rust-std-beta-i686-unknown-freebsd.tar.gz": "35a3dcfd6df77ac71cd01bec57814d9153d1358409cab11e206b98e86e14c701",
-    "dist/2022-08-19/rust-std-beta-i686-unknown-freebsd.tar.xz": "4dbeea93b2aa61076de0c84c2d5833474eec7adb66a96e90372b074e6c7790c7",
-    "dist/2022-08-19/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "e07c47100a8719e54176bb2465ae62d1156a4264695739039b901c6ad16e5bd9",
-    "dist/2022-08-19/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "2dab5f2fbc8c5900b0b4f35ffde00d0e6777c823b67a4632fddd19a3c3b5e20f",
-    "dist/2022-08-19/rust-std-beta-i686-unknown-linux-musl.tar.gz": "8b8131f8644c4cbf13003266dcfd5ff82f7b72aa8fdd14a27ff8281821ea6a5f",
-    "dist/2022-08-19/rust-std-beta-i686-unknown-linux-musl.tar.xz": "b47f1cd70533ab2a59a8ee8c218e7d94406a552df5d23061f9cea714301d973b",
-    "dist/2022-08-19/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "415d22301e698a355fbc1a32181b02a72b7ff36fe1779460d6f380fde1608500",
-    "dist/2022-08-19/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "2f3524f5908f0570b843304dc11eb8d1f7285eab7cda18581043321f65e2a1dd",
-    "dist/2022-08-19/rust-std-beta-mips-unknown-linux-musl.tar.gz": "6f25a53edc32d423752557cb65daf64f9e3a622ba5a6fdf3f07f95024b2348b6",
-    "dist/2022-08-19/rust-std-beta-mips-unknown-linux-musl.tar.xz": "a6223971aa5679e3db6df2afbdd31db05b58563347d01ae8682f37236ef2c402",
-    "dist/2022-08-19/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "756c7cd706d57fb766c0e255c9a10146f4d8c2bef0118196706f268a5b1ac65e",
-    "dist/2022-08-19/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "b54706a7faa146e4144e7c66d0f19289bebb155bc0adfaba3c4356866514e830",
-    "dist/2022-08-19/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "23fc1e3e7fd1b0f1ad210273090494246e45cf43d4c30076afd28925575a9447",
-    "dist/2022-08-19/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "ada4af591dbac60a137d00c4030e240eca53874604b2a306db1fe8af10bf0332",
-    "dist/2022-08-19/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "b9180c5bf936713c89f6f0f5f6a637810f72194a7742fdcbbf8fe6e4a6bfd358",
-    "dist/2022-08-19/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "1c2940139107d3aa8f6616e90f68fa42e62fd965f9e22cc264655ad5935971b6",
-    "dist/2022-08-19/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "3dee776bf2aa9bdaaa38235d88a1ca98f0418adc10ceb3d0e3d8999339925bb2",
-    "dist/2022-08-19/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "85f16418e4edc3b2d087104c51e4de61d7d9cf5631ee48065eaef9d796f662f7",
-    "dist/2022-08-19/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "ba374a6acaa1eee5beb9c234d2aa6e46b8b1fc7be65e0ffe8d55d9ff85cc4ff1",
-    "dist/2022-08-19/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "70621189ef43a8034d9f96765e35c43b17b16e077f143d3994e5e6cfc089e14e",
-    "dist/2022-08-19/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "143ab6fc7b3e57d551ada1d8335fdd77c4577d303d37663c4e7ce4b24557a752",
-    "dist/2022-08-19/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "a81db30558c46f43ef4c8cbf3480407af54bb6ad1813f0e912bab6ab0baef8b6",
-    "dist/2022-08-19/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "7def94fc92ad2ac6921d90efc821f37aa69bf59b6b6c8cddf958a7bc6e90ab51",
-    "dist/2022-08-19/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "c39b30a1dbb8c6a828b860f4b0685a3c0498a65dfde880df21e505c7b4ab545d",
-    "dist/2022-08-19/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "184441ee82c9578b62f905e0e1fae2e27d63cc0729ddc4a58797905341a18c30",
-    "dist/2022-08-19/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "b7677f219cb8158ce4a9dc64dafffb63f5bda0752d14390ba52c609bac629fd7",
-    "dist/2022-08-19/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "e295a74c453bf003d02d0aab07aa4b8c609878975cea9795ef467150b01f3b62",
-    "dist/2022-08-19/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "5c45723e1047a502718365252f66aa376e1ba7702fbf1453dee3a288367b3208",
-    "dist/2022-08-19/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "c348be9b8846b158b21cd73542dcfb891401421ad5fd4e0a8eacdb49e56cdb4c",
-    "dist/2022-08-19/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "f6036cb2c1fdb232016eb99f908a198c06bae44ac4d6d7536d3ebf42ba0b6db3",
-    "dist/2022-08-19/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "766ebdbc735cca0906a23683c5da5ada8a6e455dc12e49c7b34f71e66922f60a",
-    "dist/2022-08-19/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "83dc6727a20ac37273ad8b3ce043f005d5f2be7dab1d5d0c9658fe5897ee9ce2",
-    "dist/2022-08-19/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "5f059405fde4d25ff250c7219a5b7d8c009a69672f4255867d23ebd50539515e",
-    "dist/2022-08-19/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "2aad029aa8eaed74e95ac82d471bc750955323b2ef12066b5257e9779cdb9f79",
-    "dist/2022-08-19/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "734e92db50a3793eefba0378dfe2daceb37b6c06f5a6ed1692b83553406060ef",
-    "dist/2022-08-19/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "f2278a4aa83e2cba6ccf32744c3ae8b55fd44f77bdc31f08bff36105b945d2b8",
-    "dist/2022-08-19/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "4ce4d1659cd7ae70705c8f4808226814df18bfdedc079c44484fe1ce0dc06f00",
-    "dist/2022-08-19/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "77e5962551433593e6ee3a2b1ab6766706acdb9c364f5adc8c5b99e84338d3a0",
-    "dist/2022-08-19/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "6a85f89c5211fc18f86cdea8874ce4ee4d5cf15299b3884dca207003715bb54d",
-    "dist/2022-08-19/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "cfe8149d98fa1e6d1b406a5f4133ff6bcc9fe3cc5cdb006eebd354537efa55db",
-    "dist/2022-08-19/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "45c5918df046c2ac5fdce3025eba539eac759d09fd1a134d51272647b829b3ba",
-    "dist/2022-08-19/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "42d01adaa0a222270a303c10fe5b44e61817f317494595f09ab3101ab859e764",
-    "dist/2022-08-19/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "09ca832cd73a5f995a76ce9e6c330095417d8802d2b3afdcf3c42f646dc9346b",
-    "dist/2022-08-19/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "293fdda30521323f1cafe3cc0db92d80bca7fb25ec73a2b2e0c2cdcb48cc9564",
-    "dist/2022-08-19/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "f74c4dd7526251aeab43172f5bf043bdd70b8819c899866086a98c45f7895583",
-    "dist/2022-08-19/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "0de08e4670a7b5c3a4efd4b00ab6da6d2b3ceb37664d3adcc1050274b66f6a00",
-    "dist/2022-08-19/rust-std-beta-sparcv9-sun-solaris.tar.gz": "4b88e96c15cbcdc66f200fd216715c73ad26e0cdd5920105a15ba44cc02d9a50",
-    "dist/2022-08-19/rust-std-beta-sparcv9-sun-solaris.tar.xz": "819275f203ecff1bb37628dc0589b28a0667085f3e5115c3fcd26c4536b235aa",
-    "dist/2022-08-19/rust-std-beta-thumbv6m-none-eabi.tar.gz": "579d425d60bcb229cb61291caa8fcc99ea8a759b66c61b4f1c796d207ec08274",
-    "dist/2022-08-19/rust-std-beta-thumbv6m-none-eabi.tar.xz": "d2ebf00fda10f4f2e8476b5bcfce2be358f046f60a413b6e71aef4e76c6b55da",
-    "dist/2022-08-19/rust-std-beta-thumbv7em-none-eabi.tar.gz": "c898ca80eca184ed57125d8b463ca7bc60293bdedb6a3980a2c8da0d222f1869",
-    "dist/2022-08-19/rust-std-beta-thumbv7em-none-eabi.tar.xz": "01a73cb52d6fadb848eb672c567eedac339a6ebd432756c2a9e42c7273c4e9f4",
-    "dist/2022-08-19/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "cdb64f9439964310c7a35edcb36596fb68b5925b7bd2c89a048dbbd5cbbdd434",
-    "dist/2022-08-19/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "3f90031df2e3de1d423c327764cf7c83ff9b422414bceaeb8f4ca7786a17b6cd",
-    "dist/2022-08-19/rust-std-beta-thumbv7m-none-eabi.tar.gz": "626d6e503c6f72766d211faebb88cb8d8bba95775e8536eb181bd76e9a26434a",
-    "dist/2022-08-19/rust-std-beta-thumbv7m-none-eabi.tar.xz": "5bcd4b052b2699798c14bc2b50b40c9e538c24ed00bc7fc1f9c812816f47a965",
-    "dist/2022-08-19/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "90196536e30d2ae5e59ab0bceac283a1934170484c98c4672a86f8a3198307e5",
-    "dist/2022-08-19/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "8dbf82b8f8c9f5b054c5281bcb5429503d7e7f916aec7fbdd4e1422db6ccbee1",
-    "dist/2022-08-19/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "45010646984aa7d942288d74e60052a4da6a57312e56ec812ba34ee66ee32709",
-    "dist/2022-08-19/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "c2ced97a849a6600163ef798adcb8aa9f9b0800bc8554c02b635ce0c26b9dc16",
-    "dist/2022-08-19/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "3d4f2fc427971a1bfb7de12c876a03e553e8741887568fa8895996da84d96fd3",
-    "dist/2022-08-19/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "2f81f4c2168dae4a76f2705b88eead61dcdf805d6f3796c9f8fb4a0f8ace21c3",
-    "dist/2022-08-19/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "f045bb0963aeb3e4d4b08da616c4ef298f1916d7491ee624f334c21427e26e9e",
-    "dist/2022-08-19/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "b963e0af4532cba9611c9cfa62d816c45b9cac75e3d390772dcee1bbc0111408",
-    "dist/2022-08-19/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "133a35f0ff672356dab8413aa7958fe70e1987eb95c7adfd2362e1f77fa1a17f",
-    "dist/2022-08-19/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "70ef699fe52f695bedce35910eb85527d492c8f663ce926e111522d3c70c62d2",
-    "dist/2022-08-19/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "386900d6fe52f807c20aa607cc76864406e096bc6282185bce4e1fe6c2e95350",
-    "dist/2022-08-19/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "7c40bb5d55bd01c865de037695ed088671318b2a1a5d7c1aeeb9fccdfce666bd",
-    "dist/2022-08-19/rust-std-beta-wasm32-unknown-unknown.tar.gz": "41a606a2e9148e288baa8548312c993bd82f8b288d558472ba6cc84938a2f61a",
-    "dist/2022-08-19/rust-std-beta-wasm32-unknown-unknown.tar.xz": "bceb44ce91d28547ac123d17f10788268c27c9af8c8da463260dd7c574a30de7",
-    "dist/2022-08-19/rust-std-beta-wasm32-wasi.tar.gz": "1bd60b74b2e1555c669e273687b84db1da3818ef6c9b0dbe8168852c3e8810db",
-    "dist/2022-08-19/rust-std-beta-wasm32-wasi.tar.xz": "d98e83775d0340d27f2deb0cb17a05250bca53f00c2c1039ae34f412dc1249c7",
-    "dist/2022-08-19/rust-std-beta-x86_64-apple-darwin.tar.gz": "476760a9a396adbcf5312afc135f2eeb97c04da8654188726a63734ad8f88725",
-    "dist/2022-08-19/rust-std-beta-x86_64-apple-darwin.tar.xz": "caccc07d4fff2d394f5aefbea589ade137a3154eba0a2562f7a1a036928fc8c4",
-    "dist/2022-08-19/rust-std-beta-x86_64-apple-ios.tar.gz": "3fb5384aa267a2f4495483cf2857f7b33f7d1df0409539bc0735f78f5e8fa1a4",
-    "dist/2022-08-19/rust-std-beta-x86_64-apple-ios.tar.xz": "e2383658b0dfc4bbdcea69eb42a9c75686d578c0f15adce039f46aa0f25297f4",
-    "dist/2022-08-19/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "6cc9433de637d2156ede6bd9620ab7a6895894d8ec848563620df131e30e79c5",
-    "dist/2022-08-19/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "408d1d1ceccc78df145f804bdd848d4b595274ff2e5a32c76e979134aadba2f8",
-    "dist/2022-08-19/rust-std-beta-x86_64-fuchsia.tar.gz": "6ee5d79ba87acfa1f2093c1e9cfa26eb2851db48bec86d4f25654c40f9980900",
-    "dist/2022-08-19/rust-std-beta-x86_64-fuchsia.tar.xz": "eb3e2e365edc084594666862345d903165630034e4c6fe97e206be68920d1657",
-    "dist/2022-08-19/rust-std-beta-x86_64-linux-android.tar.gz": "1713831fd1675c317d7d6059a27181591b51d094b6c39978e1d52cc92fff4ba9",
-    "dist/2022-08-19/rust-std-beta-x86_64-linux-android.tar.xz": "864c4f5edf3602ae629fe77f6d08d8ed49d354ce88bc5ea034858b77aebb2c1d",
-    "dist/2022-08-19/rust-std-beta-x86_64-pc-solaris.tar.gz": "683bc54f134507fef80665397c3e2aff1b854d08cc8130b8cef2aa6e5b573561",
-    "dist/2022-08-19/rust-std-beta-x86_64-pc-solaris.tar.xz": "86f037d022446e277dc92c007ed531da9e0ec5013b7c757f0810f1abaa7376be",
-    "dist/2022-08-19/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "312db623e7d4711eb965d4826c19986019194fdd8528086aed6a08d3f6457b5c",
-    "dist/2022-08-19/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "1581eaf570f86f49189b4f8f51cf84e535a2bc3cb41fbd8043719d0dcf5185eb",
-    "dist/2022-08-19/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "0cd8dc6a60623bc64410cac94e89abbddcc7b3cba1b89f8fb2fa56ccea4493c1",
-    "dist/2022-08-19/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "1831ca7a6ed59064a201cae8f2fe919e74c05e825ff67c671d57393506e95edc",
-    "dist/2022-08-19/rust-std-beta-x86_64-sun-solaris.tar.gz": "9845a9ac85f716ab46d186696fc44993e701de7d89c2c5aad188d7b0fe1761a1",
-    "dist/2022-08-19/rust-std-beta-x86_64-sun-solaris.tar.xz": "16fa497ccd7fd94a6f7ab03ba975d00c63b60f1786fe2da1a7eedca3da62642c",
-    "dist/2022-08-19/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "3c3e24897193e3feb947a387d09059d2ee495b642dd5a160cfd1ae61eb1ae155",
-    "dist/2022-08-19/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "2ffd051693a8e831ede8e93285da11b0fef127473d95fcdcc40b4e6ef811ae5b",
-    "dist/2022-08-19/rust-std-beta-x86_64-unknown-illumos.tar.gz": "4d32d311dc0c3350c329d2aff147529db13e537f8405ae0bf317b8a85e9242a4",
-    "dist/2022-08-19/rust-std-beta-x86_64-unknown-illumos.tar.xz": "fb9d10ef315f2555a0374903d66695078d5f483167c4df2c680d48af4312d109",
-    "dist/2022-08-19/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "67fa67de6bb7d34ca870a52346dc410084702705b1f9f9adf92d9b71afe11d1b",
-    "dist/2022-08-19/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "b8df9d518bf30a87633745430f41172d10fd833ee94d6331a73de3649866b62d",
-    "dist/2022-08-19/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "42f03a9aeff106f40f3d2ada7a02b1e91135adfc98be1acda0f9ebd63b388097",
-    "dist/2022-08-19/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "da4f0915a71736b3d3c2479440f8a9728250eb50234b39aedbc17d9d1b390651",
-    "dist/2022-08-19/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "06d00f30c2332d68a924b50e42e813f2f8479d568b74c5edf51b7fbdf57b66d5",
-    "dist/2022-08-19/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "1e3b5a879ddd2e4fdc31c3853783cbe8a5a4183250b909198553a4d95f1a7cd5",
-    "dist/2022-08-19/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "cc4e9cb8e856ee173eb028746487604f0436347223f163294aa1ad34c0d740a3",
-    "dist/2022-08-19/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "02a2ef7754af534e1fe6be3a04ef4446dc6abb6e6c57326ca460a5ba6c96f9d2",
-    "dist/2022-08-19/rust-std-beta-x86_64-unknown-none.tar.gz": "62d55c2a36afbf210d0b9947ef2f05104e7da71bb7958509119b0336874f0f92",
-    "dist/2022-08-19/rust-std-beta-x86_64-unknown-none.tar.xz": "86270ba78b8d74d0f3ac6c2f9a38906d25ec888a8ab604b0c593e99ba5128eed",
-    "dist/2022-08-19/rust-std-beta-x86_64-unknown-redox.tar.gz": "194a933992ab2596af7966e1b10900b1a4627bfef99b0ff1fc87bdf0a4e2ca17",
-    "dist/2022-08-19/rust-std-beta-x86_64-unknown-redox.tar.xz": "1a2137c628946d1cb1a84e24abe3a44758425a7470ed4a48555f9c6dca8e7013",
-    "dist/2022-08-19/rustc-beta-aarch64-apple-darwin.tar.gz": "b4a4752c96d439c2977a148a40b63864041f903e5733419faacd96c5839bc8e5",
-    "dist/2022-08-19/rustc-beta-aarch64-apple-darwin.tar.xz": "f3f83489cd6890aed11a75f4b60d3edf2b32dfac023c93faa8cf1604a9e8fad3",
-    "dist/2022-08-19/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "5d012c23083429116ffb171923343169380559f3ee90fbaee0989f77da878487",
-    "dist/2022-08-19/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "15f3534ff3b881709eebaf55e55359d700686429bf55eb4b1c7292ad1a13ff54",
-    "dist/2022-08-19/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "d3aa46b9f2f052b080222a13e598ffa96227ec271c9db2efd2ddbeb0b1fef2ed",
-    "dist/2022-08-19/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "932d89e503d2b4fad90241c014c4b4f892ab8054d9555590819422abb51a999e",
-    "dist/2022-08-19/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "5c006e8324bc8a5b9039da7b61d1147575d0383a18deca3b75d01ebe684c7850",
-    "dist/2022-08-19/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "0d03091ccefff702877e2c38d131932125f0b2d25c8a94e260601c277a3e494f",
-    "dist/2022-08-19/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "373650c44db5568d8d2889b6002d3b5948acd0079773f257d9dc0e380de8c026",
-    "dist/2022-08-19/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "0cbd356980688e816baf4c88b7c8963e4c4b009cdf3e9bac057a3fedccf0c552",
-    "dist/2022-08-19/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "de83386be1885fad366b0b3379f41a8c9e30ca6cfcc5752a0bd917ec635954ba",
-    "dist/2022-08-19/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "a605234a11f44a65b80554bbfd10b6fe83c20a2a62102aaa46f0febc5ad846b9",
-    "dist/2022-08-19/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "22c323b69a4786bee149402c7c64d85795540e2143e0da1e48739b2dbb1a869a",
-    "dist/2022-08-19/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "f9daad394d53aa405f783d9013916610b014d930a355fdb88757b47469619cf3",
-    "dist/2022-08-19/rustc-beta-i686-pc-windows-gnu.tar.gz": "275d21aafcc272b18bdefdd6adf28116a493beb053eb214b6ab842ccd31e9cbb",
-    "dist/2022-08-19/rustc-beta-i686-pc-windows-gnu.tar.xz": "5a032ea14e3845de2f39305a4fb5b9a4415939f6bd0ff79a0e527c4ebd9af669",
-    "dist/2022-08-19/rustc-beta-i686-pc-windows-msvc.tar.gz": "d892ad811e831b6f1cedf8d352dc71f9f86a26089fe4fce4d22b4f77482094eb",
-    "dist/2022-08-19/rustc-beta-i686-pc-windows-msvc.tar.xz": "ca16e42ea493c869b53031ea80b52c66c5771fc25531fb13529931d0740ec92a",
-    "dist/2022-08-19/rustc-beta-i686-unknown-linux-gnu.tar.gz": "d3aa43cb3bef265d6d2fdb17c6962e906ff021c4ca0d638eba6a98f09324d942",
-    "dist/2022-08-19/rustc-beta-i686-unknown-linux-gnu.tar.xz": "9dbd9e4a20535c8e19d9cee1218f2b3e0d3289d118b840b27e12aab3e48c80d8",
-    "dist/2022-08-19/rustc-beta-mips-unknown-linux-gnu.tar.gz": "5c17afb542d3661dc31cd3d334de66706de956f45959404494f90cf73e6f6d21",
-    "dist/2022-08-19/rustc-beta-mips-unknown-linux-gnu.tar.xz": "68fc729c47c290c09a14fe450ab0b82eba568a4e687554e0f87d095fe64d056f",
-    "dist/2022-08-19/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "64e77868b050b0d237eae46f33a723daa2cac8c8736e3787664315e13d879629",
-    "dist/2022-08-19/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "c3c339f17752f334dacf18c75837578d8bcd1020a59a8a21ad0b3cca0e58e49b",
-    "dist/2022-08-19/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "45e586abdfb8a46f126b2327e64e115f8acfa861d183a276ef3688c148e99d46",
-    "dist/2022-08-19/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "7be6e24c013bc03ae28d494d78e767488c38f7487557d5debd5a42eceaa49e34",
-    "dist/2022-08-19/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "a3af91bc8d8179bd06d51615ee2ccbda0c838f99c2b30fb91c52c76304ce46e0",
-    "dist/2022-08-19/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "948b7598e5c7648b02c39757e50ad9550f78fda4943b578b4d19831c2496e86c",
-    "dist/2022-08-19/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "1f01de1fb0274b98424867fba7eef93e00485624a5fb6e21657d6591607d9f50",
-    "dist/2022-08-19/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "879bf1abc548a1dee7fc6c26c0b0881fab064be58a1540b67730b8d3643f8ddd",
-    "dist/2022-08-19/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "3303c7dcbdd1a38a8e32e4b96071be4afd191bb6403d6fbf17fbc65087b1f15b",
-    "dist/2022-08-19/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "cf8693715e3d58e016c2dbe0bf77a3933765ea5fe0a65091cc427b694a490d60",
-    "dist/2022-08-19/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "4ad0221a3df7e223d3bdf271f28f0a694aef8184cd377cae530fbca5c12d82d6",
-    "dist/2022-08-19/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "ad1390820e4fcc426a27d18f97fc8f952c9e949327d8d6b60e6853e4dc9e2c04",
-    "dist/2022-08-19/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "c9232ad8c52060c40ef35eae32e79585d550e2abc011d2b6562edb1b02244966",
-    "dist/2022-08-19/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "3e937985bbf7ef5af05e96e82114fec6ee17bc04f784c3e7472224dae1ebb148",
-    "dist/2022-08-19/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "f4dfa226259ce0d9f8fb9295f82a18a130470f11479811717ddb0f5064a9eb81",
-    "dist/2022-08-19/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "919dd5fbfc80c77f270e1eefee8dbe1c76ed7cc94cc11dff34f54ee05fd415de",
-    "dist/2022-08-19/rustc-beta-x86_64-apple-darwin.tar.gz": "482c51eef00cc238872b5002f12c351259a666e8b1380b08f5536fb87b046f4a",
-    "dist/2022-08-19/rustc-beta-x86_64-apple-darwin.tar.xz": "3b78a63fb9d27e7960ea35d8bef3734789bd48d80ed1605ddb9f547859977260",
-    "dist/2022-08-19/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "4c7ec47ced7a7cbd9e6b038ac0f57d0e705801f42375011eac42a708808d75c5",
-    "dist/2022-08-19/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "6935fbe4de2b5712fe15c865ef2eb4c41959267b03afe4f276f8fcc6eee992bd",
-    "dist/2022-08-19/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "30b78a0ac0852bbb3aecea5d4f61f4e1737b5d4910e07a59c64e7cdfeb3da215",
-    "dist/2022-08-19/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "73d15af622a7accb4a04bd596acc95cd0856545fe6a386df18905cd221107fee",
-    "dist/2022-08-19/rustc-beta-x86_64-unknown-freebsd.tar.gz": "dc00c8c6f6121ac1ba112120b82215ce811a4c518025cdc4d1202c53db88f65e",
-    "dist/2022-08-19/rustc-beta-x86_64-unknown-freebsd.tar.xz": "e827aa07bff90fb978b1055826d9e672e1e40056caab3d8a182afa3c371f0f4f",
-    "dist/2022-08-19/rustc-beta-x86_64-unknown-illumos.tar.gz": "05f6a99d63847d910e05a93d78944014c775c5b6e8b8bd742f2c74c39f7cd883",
-    "dist/2022-08-19/rustc-beta-x86_64-unknown-illumos.tar.xz": "86cde423efde88155ce35514399897fcb2248ddac9f77244827ba4e10189038a",
-    "dist/2022-08-19/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "e2dea522d946db96791f651fdbb098bcf7285bdb0182e14c573f87826f6d99b2",
-    "dist/2022-08-19/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "399847ea81239d666acdd890b4407bf2f62f3a527a60515fa38fdfd3ff61d0d0",
-    "dist/2022-08-19/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "9e1511eb0704962ad3932578821bcfca877826cb18f14e4b7defbc08aaa9f0d8",
-    "dist/2022-08-19/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "1e0eb9eb917a1db99764b374844ab3ed2cbc83495c50b28f3dcf9512edcb035f",
-    "dist/2022-08-19/rustc-beta-x86_64-unknown-netbsd.tar.gz": "28651213923b8009c6317b59a2a15f6f202108efa0b604a590b735b0cd031202",
-    "dist/2022-08-19/rustc-beta-x86_64-unknown-netbsd.tar.xz": "36591aefa17e1a4cb55625632bc97931db6f3c4252d457963353bbfa5e997a32",
-    "dist/2022-08-20/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "3f90dbf1c64d8b4cddd1fcb589b85e4b76fae6c3fed88483210bf5bddecd2bf6",
-    "dist/2022-08-20/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "1f850ef1e1a6ee89cbb862ec986cc3b5de2b4654db625a5da0906f3eff3e834c",
-    "dist/2022-08-20/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "3b1a7f2e5d380b58bd02fd1f28212869f9feeb2fbb971694425cb837f99f8f0f",
-    "dist/2022-08-20/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "f24153076383ad22da9cefd9073c1e6dc227c582ef7fb92c73cdfbd4cef6c295",
-    "dist/2022-08-20/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "e409988fc3bd50f2120d3f5828e8f5a5494fa0bc5296a97f1c26294fb2e1ade7",
-    "dist/2022-08-20/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "854e275ecd011e12606203f4b9737c373a678821b7f11df6bc08b774d670ada7",
-    "dist/2022-08-20/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "31bb41173b63d3aaae977b0ab48b0302d1ba2b7f6470fbd7b0206557e2dca2f3",
-    "dist/2022-08-20/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "7f4e356dca11bfc4bcfc9ffa588640cd9321cd73bc70c16d55901f04a119ca2d",
-    "dist/2022-08-20/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "1a8a63027aeaca5c9981567c862222b9c2d0de0456c4534213f5686862507890",
-    "dist/2022-08-20/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "2d217c695886cd59bf7bf40091813d427eb302323650d3641439f050308b2660",
-    "dist/2022-08-20/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "bc257cce6466ef7bfd30eb9790db3e72cc425ce78f763954861b28232dfe1d55",
-    "dist/2022-08-20/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "3326acc5adcf63dde12937d1ad9be4eb8c01ed3f24b07e1df28d194754506a77",
-    "dist/2022-08-20/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "14dc0a6e21cd6e7294995bf7c14238c97cccaf37910765602ca37292267060b0",
-    "dist/2022-08-20/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "93628b8ea58d6484423ff58666520701702f36eab86846a19b205a9c8d737313",
-    "dist/2022-08-20/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "199dfdf436b9ae97aa7a4a081d6a88b29e825e0e3e24409a008531dc3ea3ae5b",
-    "dist/2022-08-20/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "cbce925e5bc323d970d7df1c714b31b693208eae0a00eb43a616da3ba499cca2",
-    "dist/2022-08-20/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "0c899e9273fb04c73c3abbd9483e74cf0312aa61d0818acbd2737a515432cb1c",
-    "dist/2022-08-20/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "bc3d2e850d77f13b563ce3b286fd781f49abc6ac17f046aea7397655c3955194",
-    "dist/2022-08-20/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "8940d2f6219a956521ef3c3c43001843cc5bd65706853e7b506848bf11c785d1",
-    "dist/2022-08-20/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "bee2d0136087693ed3328b8264f4c652f843a18128bfbf3d679b6ce426b44d07",
-    "dist/2022-08-20/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "37f383823d76b2f88fe7c7950b96aad73b94ffe5bf74f7af05d0bbe18c492f66",
-    "dist/2022-08-20/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "832d60d4dad18f729638c5cea3b5a3a8577b1875977b8bf2110537a4b17a71e2",
-    "dist/2022-08-20/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "e060d1a8925f9b7f670244718fc0d84519a590cc630e832b27a0bd8149c009af",
-    "dist/2022-08-20/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "3743c798e26306d3f55afcf989221ade32e5174132e939bd4d3f0a2f1fd7523e",
-    "dist/2022-08-20/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "723509d619bb3f2c5423267afdbe082b426678d5d1df850b7e0d51cbcad99491",
-    "dist/2022-08-20/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "da258b293fa651db38348eee14239171010b230e390074a65f5975bfd9a990f2",
-    "dist/2022-08-20/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "6ad271d28309c92a76bdef40052c624b8d9e62e389ab14c8df372a6d0cfb8883",
-    "dist/2022-08-20/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "b3e71cedf9df9ce72bdd9b559197fd3989e4d108cd71ff30806b75541c072c34",
-    "dist/2022-08-20/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "82e7f9cd8409e9eeb89166c8ff047910e24a45d65712cc4bef883bb5ccbeb51d",
-    "dist/2022-08-20/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "9e0da808f7a3c03b10b309b2a1d934e447bef877adbe78b8d5f9485b2464bb32",
-    "dist/2022-08-20/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "31841de97f5f7fef456205ab14b7cb568b7edd202f31fc8a4465105ab59ed413",
-    "dist/2022-08-20/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "bc55f15780a850f2fa19fa26d39edce194745235d6f209d21b86a2ab7924c4dd",
-    "dist/2022-08-20/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "bdb86ba6b1dfe3359823aa2be3ff1b945d7a34c21383fb2b2ec6f06122ef5587",
-    "dist/2022-08-20/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "1df7664bd1f32e1a9b5d37a4eaaaac54ca7b71853edfed4b0ece2e256f17290b",
-    "dist/2022-08-20/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "67727084e37de55a4cfa4ad2c1f3a834ef49379f949b50440aeb53d65c6dfc36",
-    "dist/2022-08-20/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "820fdce7d561b7e0118b25093cf639eab304ed29852921286f0cbda62e3e8752",
-    "dist/2022-08-20/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "8cf01738cb6e7450753000737c6b33acf7d433d32b28f6b278d6efb9513c4464",
-    "dist/2022-08-20/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "3bb194f2d770934580d063b7f0939cea231dbd280a4df062f0309c3dcbcd1d32",
-    "dist/2022-08-20/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "95a42b3a88d411d7c2567f8532bf86d3bd8ee57ff2a5254c147f08502f5488a9",
-    "dist/2022-08-20/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "ed885440a7a03d81dfc6ba206c37afdcd4480368a11143805ca12d8df583172d",
-    "dist/2022-08-20/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "2d6aa369242b820621cddc095f833eb5bf9dda9127dbcea179d730b2e1fc0d09",
-    "dist/2022-08-20/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "49291adffb00f8f25e9dadfb8e8f530d6a151479e8024de4b0b42c52c7a21f7e",
-    "dist/2022-08-20/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "a61ebb7b049b8a8c8440acc7e8698896a3143c0e1f8b1c29084f680e12087d9b",
-    "dist/2022-08-20/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "8bde3268496729d1f5178863859fdad77fa94f85887b0c129e0517226e3bdfb4",
-    "dist/2022-08-20/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "08f4bcd90bc01fea5e0c6238d40fb59bd1160e6635b401f908c046e6446d2183",
-    "dist/2022-08-20/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "a13ad331d827666d8631b4b30a51b1b69de0a90e9cfecc1e8bfb559d52144353",
-    "dist/2022-08-20/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "2c7c0607392a0d2cf517cc4fcb726f443c85c26b7deca0f10cbc555de56d20d3",
-    "dist/2022-08-20/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "bbd31f2bd64b4cc2e11c0936787bb44d792d20ec303e3b55efd53e0bd8efe88c",
-    "dist/2022-08-20/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "27703699164e10526a32a6920eb8d0b71e3572d423defecd81cd6b24c2c5134a",
-    "dist/2022-08-20/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "e4d388af9bdfee7bb6470a4467e7743a9b7827cd9d4219174fd424c18204a6b6",
-    "dist/2022-08-20/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "e090c6410f3ded22065097b5839a80d1ca6c80a7657ca28b88244fe119977371",
-    "dist/2022-08-20/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "a00a785d87e64660165b56489f6709c0d0280ae728782356a3274e8c0be48c36",
-    "dist/2022-08-20/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "ab9736c80331f0febe42a0e1f29d758327c4c8035954111370ff2c568c784fe4",
-    "dist/2022-08-20/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "ca8127aeae4e84a208ce9a5cdd04c497894e62c226c8bccd00713c1a41f99ddd"
+    "dist/2022-09-20/cargo-beta-aarch64-apple-darwin.tar.gz": "3186f69cc7efaf3f933ad77798ddf58bf11c0719dc1dec53fadc502a236ef753",
+    "dist/2022-09-20/cargo-beta-aarch64-apple-darwin.tar.xz": "5ad195346a21a80c700ca08223060ea66298fe8e4cbac19148d14b92a9319b01",
+    "dist/2022-09-20/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "6a7647d761ce3adba9d4ceff2e6c1929e9d96d767961a7a062f41ec09a1abb85",
+    "dist/2022-09-20/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "13566a68dd2000fb33a990c21b62b82e77d1bd1f3384152f439cf96318f07f3e",
+    "dist/2022-09-20/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "cc698fe69e27a077c6d2aa8dc7319847b1ecd78ad4e3519161957c7cab90c592",
+    "dist/2022-09-20/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "1cd369b8ab90e85da78784cf08a92aee87f0804b448676637ee48cb3409dc026",
+    "dist/2022-09-20/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "856170acebfd7900448fe02bd835d633b2930e2401c4211d72e5dd8c38943606",
+    "dist/2022-09-20/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "5bbc32a426071c84d39395c64e1f9cfe0db29ab10c255c2a8a8f748b624cdb7a",
+    "dist/2022-09-20/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "50518c889d2408a7edf524c0340c8ff6881fd14f505dca0d419deefdb94c3afb",
+    "dist/2022-09-20/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "8143057e446c169e614c153ffbe2428e94404af96d06b1d3103028f695388211",
+    "dist/2022-09-20/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "987064edfdb30dde07ef9b2cbd072f66ca042bf95ae724909cafbc13bcf69885",
+    "dist/2022-09-20/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "253161f50a399818a77360f97443ef818dfca3d384e86048655b08c8a799bafc",
+    "dist/2022-09-20/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "7b9a0feee8f3e1e3c58df38f947904d76006c938a2395650e094337ede9918e9",
+    "dist/2022-09-20/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "2194b642b8ed595b8534ded204a72f910215c8f42482ac64644f784a3b2ae8b3",
+    "dist/2022-09-20/cargo-beta-i686-pc-windows-gnu.tar.gz": "7cc2c490988dd1ae095198664317cb0b5c8071fc31bf49aed1eca21eb2766cd8",
+    "dist/2022-09-20/cargo-beta-i686-pc-windows-gnu.tar.xz": "32641252e12cdadf0a232b43103fc56af621a48056864ff2ee9a034dd2da8f1f",
+    "dist/2022-09-20/cargo-beta-i686-pc-windows-msvc.tar.gz": "32581e6bf22e7d2c7a147a87158161e3fa07f46ec0252e632a3bafb824382a28",
+    "dist/2022-09-20/cargo-beta-i686-pc-windows-msvc.tar.xz": "a9a68905a4540389d28e40cc2137cf2fcca77c425089cd99072a34ba15e3ab6a",
+    "dist/2022-09-20/cargo-beta-i686-unknown-linux-gnu.tar.gz": "b5d9ecd7be4ab25919cd0731bb28a2612965943c5ccedf35ac09c169ed2c97db",
+    "dist/2022-09-20/cargo-beta-i686-unknown-linux-gnu.tar.xz": "387f7d95d04503293f708f65821f55878449eb5a0efe3344005dca18b84e6563",
+    "dist/2022-09-20/cargo-beta-mips-unknown-linux-gnu.tar.gz": "f8fbf21aac677276cdf246748d59d183e566bfcacabcd3eab6f19d6c857193ef",
+    "dist/2022-09-20/cargo-beta-mips-unknown-linux-gnu.tar.xz": "70e561d77632d1463839a8ea9cb72ff49afb61dbba95fa321bdba74be384b21f",
+    "dist/2022-09-20/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "e81b5a5fc70a1f7ed5920a3860b1259a2cecd9a1d981f2a564cd936de53ecf8a",
+    "dist/2022-09-20/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "ef9de44d1d37812bfeb67b353f1e308bf46d62c9fe191980de3a62fbfe5167a4",
+    "dist/2022-09-20/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "68c1cd309775626f19431f7dbb73789b17ee629b588e05bf0231313913cb6a8a",
+    "dist/2022-09-20/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "db290a98987c8bd527f1efe9ff09055fdce8eea0673d2c5eba0640649396b8d0",
+    "dist/2022-09-20/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "f4a7da60f164c03bd274f8c98b58a524d7a73476c726e2ef5695f2be950421c7",
+    "dist/2022-09-20/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "8fc46e05ba0830eec88e1d764b02fb9a4836883fd180800a8edd3a4cf0acbdae",
+    "dist/2022-09-20/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "5f528af9436bfa31d559544220fcb59001a90bff18363390f7fab82f259defde",
+    "dist/2022-09-20/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "502d6da5158075cd997833314f9ca7a527aecc8e28c9e26ee9796c2e9ac91cf5",
+    "dist/2022-09-20/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "16a7b922fa6c6019541e859386dbd38e64507d951376c847f83c6b983c72b417",
+    "dist/2022-09-20/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "7f3e361f9bfcdb5fd765f86ed372e00df62af4ae5714d9a2b3324f3929518677",
+    "dist/2022-09-20/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "f38265c64d6ac34d4632f38368d910bd9471aaf8736595623126cb53e810e307",
+    "dist/2022-09-20/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "99e7f3795aea0abb019b80b1f35aa8e1638fee35e548424ca52fd23c5bf82c71",
+    "dist/2022-09-20/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "bb9e89b65fca9a1fad5293e8a52b27331f08e9660237c0b1e7f750064d45ab1d",
+    "dist/2022-09-20/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "ea81188084da2f2771a1d9414c20065a19544b1af0e56dc71eae7ca00ff72708",
+    "dist/2022-09-20/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "745577c8c52065d84cedd32608ca0e17f1a46bb86b4d619cd01785486dc99480",
+    "dist/2022-09-20/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "85944275d5d05943c89ebf8e487bee35ed8586aa9f1903f83490c12ba74ad8cf",
+    "dist/2022-09-20/cargo-beta-x86_64-apple-darwin.tar.gz": "6c3f841c718404d4917353c7fefee7491df62d7456633bfb99dc850a49aab285",
+    "dist/2022-09-20/cargo-beta-x86_64-apple-darwin.tar.xz": "0c5a5c3ceec9fcf3b8dbb9fd10172251622e873671049b042b55ede34b8797a8",
+    "dist/2022-09-20/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "385a01c7a11a5f51253e8182d82763295037d625e7bcf27d54b5f0349cea488c",
+    "dist/2022-09-20/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "fe498e30198a43586be82c6fbd794093299eddba51fd668d81aed88bef0471ae",
+    "dist/2022-09-20/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "3ee6926fd5f491eecf574aba631d09d97a9332b936eb7bb0ab348ac3fa02db02",
+    "dist/2022-09-20/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "d15a8c24d04b308b91d9114b583087e2a13e75920a1837a78fe330cf6892ce4e",
+    "dist/2022-09-20/cargo-beta-x86_64-unknown-freebsd.tar.gz": "89368ca5eae65a569ae98e66834e93b240ef43a007e02e768ae9bbd5de4a4cf6",
+    "dist/2022-09-20/cargo-beta-x86_64-unknown-freebsd.tar.xz": "20b46e126c900892d576e972e39409c9009bafa4b3c159e624179d77afa912a9",
+    "dist/2022-09-20/cargo-beta-x86_64-unknown-illumos.tar.gz": "1712fd404274c993b95aa44dea6b9ff3b0f9857d8d1646e0cbf454d3386f5e32",
+    "dist/2022-09-20/cargo-beta-x86_64-unknown-illumos.tar.xz": "bd3f848d22bfa19060d459167b6154cc79070e0066f8da79587390fb92404288",
+    "dist/2022-09-20/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "0e5869b406dbaab0ef123459a93d4d6a34e85e9bd72d8a206bef69aac9e84d5c",
+    "dist/2022-09-20/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "5b0b255fb82d0e751187c6cc6b64298ca014ef86782984ef9e57a0b2ab373f24",
+    "dist/2022-09-20/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "09dcaeb783d7c57aa8c708295cf46bdcb3873a20ca30794b3c1a8797b2cc9476",
+    "dist/2022-09-20/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "918ca6c81e9e19f9d84d80e508af0050f2ec2ce2d0d0aa40cd3afd524d69917b",
+    "dist/2022-09-20/cargo-beta-x86_64-unknown-netbsd.tar.gz": "e66e3ecf93bad48573cf34ed44d508908370a8cc0c2764001cddbef022fb6e73",
+    "dist/2022-09-20/cargo-beta-x86_64-unknown-netbsd.tar.xz": "03514df0f9f2193824e227c19b84f282d7cb90145206bcfa21cf4f8223047462",
+    "dist/2022-09-20/rust-std-beta-aarch64-apple-darwin.tar.gz": "7a6a03adcf6481d90d39e929f99a50ed170e98fe61c3fae5264c3aa4d99530ca",
+    "dist/2022-09-20/rust-std-beta-aarch64-apple-darwin.tar.xz": "ccc8d4fb07a0a9c57b60d05bcf6d076a8b3cdb397930182ebfe99a2e5cd629da",
+    "dist/2022-09-20/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "3e70853d9fbc3dab4a39303b2281ad63d36a9ae2fd8d6bb7d96f184644e20531",
+    "dist/2022-09-20/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "59bb5bb6cd8d7269bfd29a952cd26280f5091fb24af4e7bf10cd59b80323d85a",
+    "dist/2022-09-20/rust-std-beta-aarch64-apple-ios.tar.gz": "da321d56c24e6c2aa326cc082912498c27231f0f0fea27ab925807108d6f329e",
+    "dist/2022-09-20/rust-std-beta-aarch64-apple-ios.tar.xz": "21e78983abd4523ac9efb0405734ebfd6c8c09b9cc89b9d052b1a58bb7ab798c",
+    "dist/2022-09-20/rust-std-beta-aarch64-fuchsia.tar.gz": "dd64a476c35b1a6aefed6bcc756cb4562a60ec0277e5661241018678d7a04268",
+    "dist/2022-09-20/rust-std-beta-aarch64-fuchsia.tar.xz": "bcbb6f3457c9b6e1c9109094536445ff208e78b5a24485af6de580ba7e279861",
+    "dist/2022-09-20/rust-std-beta-aarch64-linux-android.tar.gz": "63ab6db951f5cefbd1ab1661ffbac9749fec8d4165047dfbcb76b7dcb1468e48",
+    "dist/2022-09-20/rust-std-beta-aarch64-linux-android.tar.xz": "f3e89fe21779ecd8373280f38e29db8941c0836cba7314414d854ba685e075e4",
+    "dist/2022-09-20/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "fa187421633e7ca45948258e804fd4a8177070b9a4b964ac95231018cd5e724c",
+    "dist/2022-09-20/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "af981f04545aca6d3fe301a22773ff38077e8c8d437b862a3d7f1e8040bfaebc",
+    "dist/2022-09-20/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "22fb1351c35e4d5b12d043cdf1de51a13176fc60518fa89226f3af9dc2e727b6",
+    "dist/2022-09-20/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "690a7880a563138bbd583b537ddb80bd738d8fceb4cab083bc8bbd1fa1ee2f99",
+    "dist/2022-09-20/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "2d5135344f76decf74633d95e2fc98c416093ca962cac608564abf600ff117bc",
+    "dist/2022-09-20/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "8f63623f1e0cae99c5d1c4bb1c636fb773ed06dc1d33a251c9253278f7bc1300",
+    "dist/2022-09-20/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "105123c48c7e0946872b8ca0fcc897c2a1fcccb9b71b1805eca01e713a509c0e",
+    "dist/2022-09-20/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "9c9ec824e1db607bfac14ce8a5d1e73aeb8670e655acb4577a8f6ee783202aeb",
+    "dist/2022-09-20/rust-std-beta-aarch64-unknown-none.tar.gz": "b25fb3d1c41e193b724469898efe9d0f5d282de06d5224ae573c8870ccb5ed4d",
+    "dist/2022-09-20/rust-std-beta-aarch64-unknown-none.tar.xz": "4f87a8fc869f80072ad2a07896e50ee97b3412badeb69bb37f67ef47ff0d00d5",
+    "dist/2022-09-20/rust-std-beta-arm-linux-androideabi.tar.gz": "9ee992110e4bcf9a00bec8635cbe5bbeb241d2fb6b567060fa0507406708c8dd",
+    "dist/2022-09-20/rust-std-beta-arm-linux-androideabi.tar.xz": "aa5981a138a103843462a5a6987fcf0c7c335a5896517505d2e54fb288d7af1e",
+    "dist/2022-09-20/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "854d0d7c9932d4533d642e663ffa465741a3d0ec400a2c4b74324debaa0da27f",
+    "dist/2022-09-20/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "83b7b2dc823608777dc0e2f290fb5a2f8e6e35f4930ce2170309c14a54f136b3",
+    "dist/2022-09-20/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "9c84cc8ff79098be62011d572cd928faa4cf76c9c3e94060babc042073f3b7a1",
+    "dist/2022-09-20/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "b34a7bdd0ddac9e8b4ea8e1db8d86389c623a6629edbbd0052f890df75465fa6",
+    "dist/2022-09-20/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "49ddce546458f47683928fe341f5eacaec11c3c5a378ce8802c4b97425100905",
+    "dist/2022-09-20/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "e64130a854017b921a086749550fe92339cef0890ee645acbe23a30f5169a8ad",
+    "dist/2022-09-20/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "770bab36bd3bbc07739f0cc89c09689189edf7518e740f794be9aa7aed0917f5",
+    "dist/2022-09-20/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "b390f1111f5566b37d3f9384126a6d3dd0cdf9468dea19747394cdaae1c87c7c",
+    "dist/2022-09-20/rust-std-beta-armebv7r-none-eabi.tar.gz": "de22ffe26c7ef21d316933618b37c832353a7e5a1fb8b84af7bca98626fbc78e",
+    "dist/2022-09-20/rust-std-beta-armebv7r-none-eabi.tar.xz": "82b77c48fdb685b63bea0d40437d5dcee41500cec0360e393511b2c69d2c7381",
+    "dist/2022-09-20/rust-std-beta-armebv7r-none-eabihf.tar.gz": "94d427c65134e1e208f662acb3eb65a455016e3bed162bc4fcea9c6455e0474e",
+    "dist/2022-09-20/rust-std-beta-armebv7r-none-eabihf.tar.xz": "cdd71383ec150dbb2514a48300344a8547d7fee2c797e693cd7803354c5fca13",
+    "dist/2022-09-20/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "0241f8f9ffd00c02860158da46e20290d2ba563f93e8fa22324da2b87c347a0d",
+    "dist/2022-09-20/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "a780eb139416f2383f16fa63e72e56f0a77c67d2ac2f10f803802660e8ca30bc",
+    "dist/2022-09-20/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "1628e0c7a8cd8fb2b90db0e3d30f0d36768dbdeca640af967a14b9031d2d4c3f",
+    "dist/2022-09-20/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "4b06bbd8a0ae240bb19c93b54bd9da3bfe6c3f37a70d2b73dfcc9d1eff8fdaae",
+    "dist/2022-09-20/rust-std-beta-armv7-linux-androideabi.tar.gz": "9aaeffdd99e9dedb2bffa79adef2096ef29b48ffd2681ede2ea8d63179082f89",
+    "dist/2022-09-20/rust-std-beta-armv7-linux-androideabi.tar.xz": "d1d0ae4718eb43d4759cbe14a90b422edf0f451c8cb8624368800eff0f05c13e",
+    "dist/2022-09-20/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "5cf573ce6729200cc211924e45796a9aaf85001272a8690803944dbc91b5a2fb",
+    "dist/2022-09-20/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "51cecc72479f18c94620b2b022b89403e8ba519e36cb7a6f8c208a9ab6adb17c",
+    "dist/2022-09-20/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "c6e6962438e0a8ebdc7a7c74712d75642acfeb8c4b0753354a7d3b64da6948cc",
+    "dist/2022-09-20/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "4b812cfa63c380448b0e2ca2e03cfad73ba9951080eff1f76feaee25f67bdf39",
+    "dist/2022-09-20/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "89cdaf10019fc3ddb83ca1848adf8ac3411820a9095dc337b9a962f1e58be058",
+    "dist/2022-09-20/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "e21ac9106eae28b25270f6c1ce70e2c94273919c9c72d22f0fe3ad0b8f0a57f0",
+    "dist/2022-09-20/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "e218b7e7d148379411502023d6ede2831d76e29d5d2427d030f916a0c14c8ffa",
+    "dist/2022-09-20/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "2797698cf0f218c17eb22f43f806663723f9c89084fdc08d40adbbcde5a79f88",
+    "dist/2022-09-20/rust-std-beta-armv7a-none-eabi.tar.gz": "1d5c29d803cb8ef005baf44ca6a0b1fccc4227ab3585046f0d69cbf153be10d7",
+    "dist/2022-09-20/rust-std-beta-armv7a-none-eabi.tar.xz": "50259e9b9672baf54e176c252e9068cf020c4a79a825bafc5ee21fb46b9af815",
+    "dist/2022-09-20/rust-std-beta-armv7r-none-eabi.tar.gz": "805fc5ae72249f27ddbdd8afdc188b4f67dfe51822eb813e681259da51dbc75c",
+    "dist/2022-09-20/rust-std-beta-armv7r-none-eabi.tar.xz": "75151349dc9b6fd3b3a78d38827e517adc6935356bae0c5bc93bae62e1759db8",
+    "dist/2022-09-20/rust-std-beta-armv7r-none-eabihf.tar.gz": "ad4e0347c3e9b3f4936f26798ae2a8c502a4599c3357baf0b0a4cc3516c471bf",
+    "dist/2022-09-20/rust-std-beta-armv7r-none-eabihf.tar.xz": "4de3e5a729597473759b2db1f7e2ab633c98bb1d8125de6f458fe3bd0ee7d8c7",
+    "dist/2022-09-20/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "0b3c92539f3aec14501e09db3aa02854ef98fb4dc89721306798ea163041e669",
+    "dist/2022-09-20/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "26deacf11e62187673718ea8805b23dc2dd352efdedc11b396e117637a96ceae",
+    "dist/2022-09-20/rust-std-beta-i586-pc-windows-msvc.tar.gz": "a11ca7a7f67e225365423a704d7139d3c9193699493f1f193d579c126d492475",
+    "dist/2022-09-20/rust-std-beta-i586-pc-windows-msvc.tar.xz": "08d8aad1d608d2ff626f4e7e4300a31fc3f96c0ef1e5bd0ec179b98d4194fca9",
+    "dist/2022-09-20/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "3524e1ba92b9ccd1fcfd40a6018efa697d63177cc0a8c9cd016be833aff371f4",
+    "dist/2022-09-20/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "a6df83285ba5732eca9adf3f39d0a4087249b29cd0c33ee2272f68930df43191",
+    "dist/2022-09-20/rust-std-beta-i586-unknown-linux-musl.tar.gz": "6951d7aecd555a0dc485f57ad16703af65315c464aebcf73171bbda2273dba0a",
+    "dist/2022-09-20/rust-std-beta-i586-unknown-linux-musl.tar.xz": "f07c4a267740e46a4013b130e9d1e10492e45dc0226a08f5c909076ade466737",
+    "dist/2022-09-20/rust-std-beta-i686-linux-android.tar.gz": "dd47fbd29b3b025388352fafe693f25e43c1287f69c2185fecfb0d60e13a7fc3",
+    "dist/2022-09-20/rust-std-beta-i686-linux-android.tar.xz": "0eebd41330762a4bad438c40f134601e59a7b73043952b2e090a801adff41727",
+    "dist/2022-09-20/rust-std-beta-i686-pc-windows-gnu.tar.gz": "58cd47de74c201bfed62a8980c2447f97e7c129726d3d28c2140d880fa6d7975",
+    "dist/2022-09-20/rust-std-beta-i686-pc-windows-gnu.tar.xz": "7fd68f0f9eea4d8256132af2f2c269c58a278b757888e591716a553b87ffcf8c",
+    "dist/2022-09-20/rust-std-beta-i686-pc-windows-msvc.tar.gz": "816ef343a7ed908706d8f4e7cb915787a4e27c2390cc7c3f6e2210f3ad7c4cda",
+    "dist/2022-09-20/rust-std-beta-i686-pc-windows-msvc.tar.xz": "2475326f3d32e8ae309750c1639cdc6cce3474fb5d4820b31b46c9c12401b63e",
+    "dist/2022-09-20/rust-std-beta-i686-unknown-freebsd.tar.gz": "24a897b9916bcd4ad775d96f9751b06663eed599086d0665b83dd4c16af871ab",
+    "dist/2022-09-20/rust-std-beta-i686-unknown-freebsd.tar.xz": "959725ac2f49d1944c53846d920ab4e8769976d4025bc32bc63e5372b751a8de",
+    "dist/2022-09-20/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "35eb28ff2d3b383ac1b34bf6eded87f824ef93eb2c2d12c300b136c7c735ced7",
+    "dist/2022-09-20/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "31085015fbfa608e6d0828a367d84b48679c6a33d55ae32affe37307818b1086",
+    "dist/2022-09-20/rust-std-beta-i686-unknown-linux-musl.tar.gz": "ef294d01caeba013cc3173b5fab5daac4f0c64e57410f778f2891dff03f23875",
+    "dist/2022-09-20/rust-std-beta-i686-unknown-linux-musl.tar.xz": "4ad7915a9e54f7d911864adbc097941a9c051e0c97c8eee1c04158a5755e4e4a",
+    "dist/2022-09-20/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "cd8e8fe2af17def5bf19a8a0993317af5c33833de850a489ef2dee54c61dbca7",
+    "dist/2022-09-20/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "f2f95555e3564f7b16bcde9ae4c6a30752900519fba68304c4f74b7e508bacc3",
+    "dist/2022-09-20/rust-std-beta-mips-unknown-linux-musl.tar.gz": "7d42b6d7f028c637f7f9a2f0c14fde880e00098bf4141289620232a263fa8eb0",
+    "dist/2022-09-20/rust-std-beta-mips-unknown-linux-musl.tar.xz": "50dc97ba9ce28d4252f03f78e23bc05a702d5c1c5ad67b70a358406419f25721",
+    "dist/2022-09-20/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "7c14decb2404c616319c99415f65c1383264151f3802ffedfdff4962db310828",
+    "dist/2022-09-20/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "230849a3b6dff89671bf94c73391eee43107c81ff65c795eb1c9f30b9bb52176",
+    "dist/2022-09-20/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "0a63c8f568d9ef12b75b9bcd53faf727bc029b4a1268c53fef913e58be94eff7",
+    "dist/2022-09-20/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "5b1020d65f651cd1778448618bca55906eef981842b73c18be1b5ec785d6bf06",
+    "dist/2022-09-20/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "3f747d83397942c88ad79a7bde1f98a57d0b416620f08ab57edb64f3b101f493",
+    "dist/2022-09-20/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "babdc0c87bdc8146fc6645da34776be98575019eacb95529c00060f8afcbb1f4",
+    "dist/2022-09-20/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "f0bc0b5fddf7ff8251fefa4068fdb623b47bbd1e81c2c732ce2304e4ce78bb20",
+    "dist/2022-09-20/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "33e3cc3766f941f3668a93240d627c7357b22a13facff5937821d92a21afe444",
+    "dist/2022-09-20/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "33ae5fdfab257ddb004eb80ff1a8d0351675df06b97951d5c47071ac8b18ba9a",
+    "dist/2022-09-20/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "9f16e21c54944afe83a5e1a3e489a2dcad947f367cbb17c6ffcfd2c503e03f25",
+    "dist/2022-09-20/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "065f8929bef2ff2ec0067c788fe64e0a08af0f5e11ac5d67e29e5225557d6d9a",
+    "dist/2022-09-20/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "c3c54ba9dfee447e33d76ba8060bb9b6081103fa6809ad77c3221ea064ed3fc8",
+    "dist/2022-09-20/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "5627e25a24792131e8c0a1c605908bd56ab5a55614b8e17c23233fdc14d25e81",
+    "dist/2022-09-20/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "3ee1b5228665f2d5d7ac500d6fa6a2d0fd771eaafb5c393419713a11bf8d0875",
+    "dist/2022-09-20/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "cbf922bba400e798cd32e5404a804400f79ed03ba5cc433173eac96ba9e06976",
+    "dist/2022-09-20/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "bc573b0012568f0bf397870660f7527697b1c65e1a7387d2419c6f63ba001bdd",
+    "dist/2022-09-20/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "917b948988edd4e5c5e441102f55b1541318d47c0cd5d958a69ddc6fbfda84d1",
+    "dist/2022-09-20/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "23e45711ce82b6baf9d27d909d8fe4bc6a5f32c91dfbc280708abfe5c362bc89",
+    "dist/2022-09-20/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "448710ce6f3e72d0831ae882fa37196685a28dacb6f0f499370fc2882427044f",
+    "dist/2022-09-20/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "831bc2bcb21ab9fe82fc64eb377d6d80b47198dc82677b7bd630d89819914e20",
+    "dist/2022-09-20/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "14a61cc3d6740a9033c6570264e6c9356120235f42e5ded8ebec1d592f17b47f",
+    "dist/2022-09-20/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "c73aa37081b4248324a459b48378b4a412a3561a12bad3ae064c8336ec862dd6",
+    "dist/2022-09-20/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "f78a367b9977471dae06fffd6049f03585e826fe648a2d1d8ee20ff19dfc913f",
+    "dist/2022-09-20/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "e8ef0dfd9d7df08fcdb7136619d8b9cd31435e0de130f87c799117dba9614a54",
+    "dist/2022-09-20/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "a7cd118c91f4de3a1e1c5d9326080bf39661f708c675272cf697ab9675001705",
+    "dist/2022-09-20/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "58023f2bd169455d97537aca228749e9a980e18d72f67ae8c0caff4ad2d4fd64",
+    "dist/2022-09-20/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "726efb0f7cbac9d13deac41d0937ce5f707d8e858b3bf9096c40fd41b2663d4a",
+    "dist/2022-09-20/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "73395ddaa22a91a1de120704f22d86b0624de52af773755046ec809b76b88954",
+    "dist/2022-09-20/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "2504e53a04ab1360309dd9e733798a94fa3a92cc575148073dc4870bb26367e9",
+    "dist/2022-09-20/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "f182ac3b6222a333d73f3f612fb31f9d19d4e03456e16b0967cb55d1292ec05a",
+    "dist/2022-09-20/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "9612105b0d40225d54f6b02bcf75e0d7d232331fa22a24de4895f97519dfd6a6",
+    "dist/2022-09-20/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "448b0cd5cc35096e0fd51a7cb1948e87b7c46eafe665dbfda802a4947e08665a",
+    "dist/2022-09-20/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "72459d840371f7203e15622a82ccb5e3559db52934445943fc41b11a58b07302",
+    "dist/2022-09-20/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "39ca5b49d6e909c81deb8c7391e01da9ef51cabea55fa55dc16cf654abb089a1",
+    "dist/2022-09-20/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "ff74af39ca1446f06f891beb22f1e24fb0b450d97c889dc2e27e0f53fc19b26f",
+    "dist/2022-09-20/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "f56aa4d390eb4b25aa51685ee773b589ebc87bbed7495a07d8af0d3b3cc7c715",
+    "dist/2022-09-20/rust-std-beta-sparcv9-sun-solaris.tar.gz": "df727ef09f0549051ff5b4fcd04cb22d4244cea85f97e43880e563c45b558cd6",
+    "dist/2022-09-20/rust-std-beta-sparcv9-sun-solaris.tar.xz": "f575d16acc0a8cc5b96e038d828ac023c302e38efed271d5101a885d3af35cfc",
+    "dist/2022-09-20/rust-std-beta-thumbv6m-none-eabi.tar.gz": "838be75f56d84d88ab01b0897d9b166b6ea26c527705df2d2a7368968439505f",
+    "dist/2022-09-20/rust-std-beta-thumbv6m-none-eabi.tar.xz": "b5b33e2de72e71ef5024fb50f0f6e91f32b4747f666aa7069e695b15119a1963",
+    "dist/2022-09-20/rust-std-beta-thumbv7em-none-eabi.tar.gz": "dbaffcc17215c4342a40c049a9538be44837bcf86a7d65fb2c877f831beca337",
+    "dist/2022-09-20/rust-std-beta-thumbv7em-none-eabi.tar.xz": "14fabdf3f4cda3bdb3ac139c95d31c2a20e3a88cd9f83e803f9c9bd6e3f9f83a",
+    "dist/2022-09-20/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "3acc833a086a9b46db81cbf03fcf2dc366a4b3d32eaeedcc2deee8ceea31449a",
+    "dist/2022-09-20/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "f6cf227b6da03855f1624bb325bd802b8ae6b15d7bbfbfbf8b9de1a74aedb6fe",
+    "dist/2022-09-20/rust-std-beta-thumbv7m-none-eabi.tar.gz": "e5054ca1e295709654b214847691f4fa9f031104725632dc056853382e74e733",
+    "dist/2022-09-20/rust-std-beta-thumbv7m-none-eabi.tar.xz": "b44f0462a5f44e762653fecd816dcd5ba5a2f9d8dd3efcec259b250f3af5237d",
+    "dist/2022-09-20/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "4fb8000ce077d346d85005343284f56ae936eac334c72cb8c170dbe810aad740",
+    "dist/2022-09-20/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "77955483882897980f4365bdc71fca9f39d675ff210519702b9cf3f2a6bcc2a8",
+    "dist/2022-09-20/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "566b9ea01182e6c7e3844911ed08fe5eb1d848c3de89d4f123d80fd70ff37ddd",
+    "dist/2022-09-20/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "33cc9c12d909bd4166be8570e27da8c1884ac1ce82d9548e16d926d9885ff62d",
+    "dist/2022-09-20/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "62a345ea2aa55b1a02053e7c49988c5f14d6b90d487b9c4916e40ad31957d1f5",
+    "dist/2022-09-20/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "37fd80af2188d837e870d3c8399767be15070344fc87d2b37b5126095252afc5",
+    "dist/2022-09-20/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "32a10d7eaaf2189d74700187fbc8c2ebde08b5efa06440c2b4f65fb85eac3ecc",
+    "dist/2022-09-20/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "dae8d6deecc5277be729803ed55dc134c1ef5bae49fa0fe7ea4f0eee9d7d19fb",
+    "dist/2022-09-20/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "44457f84d46ccd201771cdae9520caebf813d3283b08f73fabab59b52b485a98",
+    "dist/2022-09-20/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "1e5bcc82a403c1c4c5fa41fa78de9aa4378a2901e3170d9542eb3b21d130e36a",
+    "dist/2022-09-20/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "b7d31d0ec6fd1355d1323555ec8d1cb4b9f30bab32a75d0d8efaf465ab2aedcc",
+    "dist/2022-09-20/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "a25b5c180ca97d074d563c6fe1d826db23eba9212d12cb3d60d39b7841a5618d",
+    "dist/2022-09-20/rust-std-beta-wasm32-unknown-unknown.tar.gz": "31aeed83d12732c40e51cf59a3dd8dd1fe7ba2ed047cab65f8bfca8c72d158ed",
+    "dist/2022-09-20/rust-std-beta-wasm32-unknown-unknown.tar.xz": "28757fc2c5304b3110b2358d252fb4aaa8d811999bd9881e118bc71b0e6b01a3",
+    "dist/2022-09-20/rust-std-beta-wasm32-wasi.tar.gz": "b69ecad8480c2d33b854ba3387a0563df53546b8a2b55639fa20d1c104f35050",
+    "dist/2022-09-20/rust-std-beta-wasm32-wasi.tar.xz": "a09185a76891928cc65e4139373df6f22fd0060388ccc4530cc0be5310f8aaa7",
+    "dist/2022-09-20/rust-std-beta-x86_64-apple-darwin.tar.gz": "97f5a3dd01a7b5efe44662f2376826c184d212754c730bfaa21cd03235676142",
+    "dist/2022-09-20/rust-std-beta-x86_64-apple-darwin.tar.xz": "131b37e9d3c2335fb51427a7e0ab43362efccf90a4e001ef52e54aa221634eb8",
+    "dist/2022-09-20/rust-std-beta-x86_64-apple-ios.tar.gz": "d900fc396731c95a57d43519a109202cd2ed8e574df300cd6124c6390d1584a3",
+    "dist/2022-09-20/rust-std-beta-x86_64-apple-ios.tar.xz": "694dc51239481fe8f5ec2291b62435e0a7622591f2709ea4709749c7d8c01db3",
+    "dist/2022-09-20/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "c2fad6b25e33e4e52fab6d20b6e1bbf78f230e9b387f260b48f940bff67386f5",
+    "dist/2022-09-20/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "c3fe305a1082cbf1f5bbdaab5a94c0ad88037a4f99e556cf06ff1270a806f437",
+    "dist/2022-09-20/rust-std-beta-x86_64-fuchsia.tar.gz": "75b5aaf5206953d16a418c83f6e6d21a0adcbb0c81b5c1a8f467f3e5aa33c038",
+    "dist/2022-09-20/rust-std-beta-x86_64-fuchsia.tar.xz": "7fc38dbfb7833e9b6336f4aa38706a92e1922231ee875100e16274c571110757",
+    "dist/2022-09-20/rust-std-beta-x86_64-linux-android.tar.gz": "bc4a42ffc51bc3be27907a73de98fe4c8cf3b205fd1e7c75a9cb3bd30bcc5fbb",
+    "dist/2022-09-20/rust-std-beta-x86_64-linux-android.tar.xz": "68e02875090c7d382e8b21d0102712e7c9d583d657b6c51b4f939e3a9b7f884c",
+    "dist/2022-09-20/rust-std-beta-x86_64-pc-solaris.tar.gz": "11edbb1de67f00263f31635bdf006966143aa18423f574cb64ef966301a0fe3a",
+    "dist/2022-09-20/rust-std-beta-x86_64-pc-solaris.tar.xz": "44743e8f113e3e5bc7ce66902533f6ac59538f8f61fa6ab6c311bbf2ebe75e43",
+    "dist/2022-09-20/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "a705945830b23a25f272600470d687a1a9f5d4f8a01c5fed9e495a444b2aa9ee",
+    "dist/2022-09-20/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "9e4a045a2e0f754ec6afd897f1bcb66bccfc2b5bb91f141fa8d3d47723eb6090",
+    "dist/2022-09-20/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "910de4547c1112170b0981fecfc926cff4c47cc622648b83fea9f79c171cb05a",
+    "dist/2022-09-20/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "f9be82ac8c5f64c17cfbf0270b8f71ec71e6b3ba7c9521980a73d6f848f6014c",
+    "dist/2022-09-20/rust-std-beta-x86_64-sun-solaris.tar.gz": "e1097c0bd31baa61902be4a8a47a674faa15466ce9352213cf7808f50d5854ff",
+    "dist/2022-09-20/rust-std-beta-x86_64-sun-solaris.tar.xz": "82866dc52808549acd683d5b7c47fe97c992ea70cb6fff941007960a25f3b645",
+    "dist/2022-09-20/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "2b7c60a6b830d557a6df8865bc8dd658c84037a5893b11db8e11dadb527b5d6f",
+    "dist/2022-09-20/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "14787b285c55ab885d1360897849882eac861f36029cc72ec9819d035998ee9f",
+    "dist/2022-09-20/rust-std-beta-x86_64-unknown-illumos.tar.gz": "4bfdf27eb12af6c4df132603a111ae26f4d06846af366a38e594e66c092373d5",
+    "dist/2022-09-20/rust-std-beta-x86_64-unknown-illumos.tar.xz": "66b602046eaa83cf2b69bc75af4dd11dbc5d0c6878537d0af451d17121fdbbe9",
+    "dist/2022-09-20/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "78d12361e71630978928896a63e6cf7e3e866c09de761029b4e8e959850ac025",
+    "dist/2022-09-20/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "d55f9cb4a8c47fc5d0123cedf622b94b33f57a59022129e31f451e1b80f1815e",
+    "dist/2022-09-20/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "74bbecb0f35ad8a1aae65fb09ef21e38bfbe6d5b4c6b1d741832eb8f40eb4b1f",
+    "dist/2022-09-20/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "135f19e88ac0fb7ed02072c82a17f0d12abaf40055efd0a6b43bbbbc9c4445cd",
+    "dist/2022-09-20/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "0b3abb866d7b82bc5add9fa01d59b9223d2124d69dfd78a13a4dfcc17196f510",
+    "dist/2022-09-20/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "ec5989076c015e5b7d1a307ecb19f2ed12df7b5e2836d3b410f3743f9066683d",
+    "dist/2022-09-20/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "1e236c2ad7aa296aa389751ce64d1cecf86053d23126e1211da71674603e6900",
+    "dist/2022-09-20/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "de43876b381f7b91f7a8e1d1df5b92a3d60b22a62333f9a645f3e6055e91be3b",
+    "dist/2022-09-20/rust-std-beta-x86_64-unknown-none.tar.gz": "568e95b842c3d8f9f733fc3b5b59a8c673d200b4d16d5db36ce24ee355e18c1d",
+    "dist/2022-09-20/rust-std-beta-x86_64-unknown-none.tar.xz": "557727f83c7998b9349bb2c05f5ac5fcb2f0bef28e55f27b165fb7a2d9347396",
+    "dist/2022-09-20/rust-std-beta-x86_64-unknown-redox.tar.gz": "e3c00ab70a0a69a9567bc525cc283318186521a6d57ccf4a42e2eb640ed50ce6",
+    "dist/2022-09-20/rust-std-beta-x86_64-unknown-redox.tar.xz": "757f2208edb49f23adf702a34b093551f0e193f6a6cd8c24b2cf4f199f77b2dd",
+    "dist/2022-09-20/rustc-beta-aarch64-apple-darwin.tar.gz": "a036bf0b4d0c8ab907ef2cb8cf8eacff41f7b82d519a2988a529c3d926539ee8",
+    "dist/2022-09-20/rustc-beta-aarch64-apple-darwin.tar.xz": "3c49210d4b867cefb4050507104b2672fc70e15f42615ced22469831b34b3267",
+    "dist/2022-09-20/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "21fefdaa0b70d7f4839751926ce102e19164a373e4d310c0f0b3655f3adbff47",
+    "dist/2022-09-20/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "7c88775b4efbb2416deb2b0d9ba86d5178d34059b18165b276658973f29d5971",
+    "dist/2022-09-20/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "99e30eb1612fd18b42a1b89602f448788ddcbbac2430577fc963a2c0c4708c55",
+    "dist/2022-09-20/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "385eaeb8f260a187ef828904e5267551062210543614dbf98d1c1e392853b913",
+    "dist/2022-09-20/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "8f3b377a74c586cc8f7cc165eac0794bec560e04c885ae552af4e5cf42490a1b",
+    "dist/2022-09-20/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "2fb2add792a9377cbe86aaedec389d023c35343ef801a97a2392f323e92c386f",
+    "dist/2022-09-20/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "658ec925f51b2a5da9ab8cb193c33c05cc294915d8c0c5a2e93f9ade383375df",
+    "dist/2022-09-20/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "75d19b64530691739654763b89468a7101457d638da04e25f549078594b67b68",
+    "dist/2022-09-20/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "c167fb9f352fed99d427094a5c2b96da0486f30ccb4188756def7c232083319a",
+    "dist/2022-09-20/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "ec1c19536b6fc3020ccfff727bddc934f89da0592797d49bf7149e96f7175451",
+    "dist/2022-09-20/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "05c5e668d5b40db5cd18b21192d8f0f1401d2304f715eff08ff49c3c97d740dc",
+    "dist/2022-09-20/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "ad620c5de3ae9a0b30b3c49dc89bfcd08a061da01f004a724ad5400efd4a7189",
+    "dist/2022-09-20/rustc-beta-i686-pc-windows-gnu.tar.gz": "2be9e0f5fe27b7085f65d32cb20875392bdcb177c582c58d1df842b316dcb9c5",
+    "dist/2022-09-20/rustc-beta-i686-pc-windows-gnu.tar.xz": "5841c0f4558d24ccd0c4e6996e399fe3ff13d5d1ffb2bda38bab6d60020fa649",
+    "dist/2022-09-20/rustc-beta-i686-pc-windows-msvc.tar.gz": "a19c5330c111ad4b19a724b22dc3381eb9f05a85bf9299dd13eefabbf6499504",
+    "dist/2022-09-20/rustc-beta-i686-pc-windows-msvc.tar.xz": "902811dec71e36989af12c8dc15b79759e5cf4e2250841bad2b9db2eb94195a1",
+    "dist/2022-09-20/rustc-beta-i686-unknown-linux-gnu.tar.gz": "36474bb89e67bc867cb7a4a5101d00be221d7a8b6a625535a5b2a74f505d5af4",
+    "dist/2022-09-20/rustc-beta-i686-unknown-linux-gnu.tar.xz": "4329562f89817b02e3eac219ad3051d9de5fab89e0678d91378c02a90fea7d59",
+    "dist/2022-09-20/rustc-beta-mips-unknown-linux-gnu.tar.gz": "bb7f5c8abc99d07a337eaeb3c1dc3861a4f148c364f58b039886f43abf6a7d01",
+    "dist/2022-09-20/rustc-beta-mips-unknown-linux-gnu.tar.xz": "0b02a4d1aac7c9d4b38fd760937020975e5de209ad23b7285cceae7992449d47",
+    "dist/2022-09-20/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "7ceae3da1fb1f865df3315ca450ec3cb4657086dd61c7a47879f98188aa38100",
+    "dist/2022-09-20/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "5a5273ed85d3012b8067dbc3e93f1af105e4cd80ed8055daade24f43dfb41977",
+    "dist/2022-09-20/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "dbd12a141765f29be2a602531db7f9a02bc32617635448f602befc90f1a574c3",
+    "dist/2022-09-20/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "e3abf34a09040149f8725ed1fca6e9c412c4cf290f9424541a819f0e2aa363b2",
+    "dist/2022-09-20/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "e13b7057525302dc3585a71461aa022ea0c059c0b0069fec44f86549eea94d18",
+    "dist/2022-09-20/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "b7bedce1d0ce44b4014e10122201c10443c0e8ced80084a6ebf1add1dbd3236f",
+    "dist/2022-09-20/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "fa738ae0d068e85044d2fce10f6a8bebe7b608630b9b7a822b2d7b84c6c59002",
+    "dist/2022-09-20/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "b53d773465368d9484cd36063d7ff202c1ca8d18422b4f6727cba54beb88f4bf",
+    "dist/2022-09-20/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "9fad6a7ae30e5ccb4f0779ffdd117f6cb30e6c5f6efd5247c208f9ee3296a27f",
+    "dist/2022-09-20/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "e8a92259aa371d350dc29171467c3e99fc178b636343ca82188c7b602a39ab58",
+    "dist/2022-09-20/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "5b64e0924a705e267177c8d80970f510487de350dda47cbc9bb758ec1b212a17",
+    "dist/2022-09-20/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "f6ca5a88f0ea25521e1135100cc7404547ffbbc4422b3c9a06177c94d7871ef4",
+    "dist/2022-09-20/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "8db27ac2a1b8322f529428ee7278347263a9ff71101d37bfb04056137f63de78",
+    "dist/2022-09-20/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "2475866ff4afe38755a27ffde9c09302066d0c936a4778883fee9a37c1b59f31",
+    "dist/2022-09-20/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "4cd81c652fd3e59cbdd42872f2e37bdcc1fa61a550eb8ffed7783e7ad3350577",
+    "dist/2022-09-20/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "1f8529e51192433d1a281484072f94d910ff81161efef230e6a2be82765f6f26",
+    "dist/2022-09-20/rustc-beta-x86_64-apple-darwin.tar.gz": "430311100511fe9fe176f01030b78fa8160840bf4d9b4ed798a2a7fe089b4f7c",
+    "dist/2022-09-20/rustc-beta-x86_64-apple-darwin.tar.xz": "57be1bb1dc7d7d0f0479d11e36d6315a9d19eb0102610b7f1dbd5151fe6ff5c2",
+    "dist/2022-09-20/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "826f3f6839c4e18e6d58a32de8f067bb57be2fb2c6cdf74f55d55ef76f5c5e21",
+    "dist/2022-09-20/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "5f8b9704071e6b372a5c67a29bcb9ba5978ffdedd62e057680aaba17dfc91ba1",
+    "dist/2022-09-20/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "06a29a85bfce9981504f1630c5f3ea86171948080a93d8dadb4a306dd678af80",
+    "dist/2022-09-20/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "36c2944aa3db18dfa1632c7b52c67e6bad9effb03960af8cbf82fdf32924019b",
+    "dist/2022-09-20/rustc-beta-x86_64-unknown-freebsd.tar.gz": "c20829efb9888d8097c9f5f472598b06868bf918a9d033d4b6fd031323878492",
+    "dist/2022-09-20/rustc-beta-x86_64-unknown-freebsd.tar.xz": "515b35360865016b7efe6f973730ce4c66021df0edeed8eb490b69f4bf50006d",
+    "dist/2022-09-20/rustc-beta-x86_64-unknown-illumos.tar.gz": "e63231ee48425687c97c654faba961a1b12379696459f284b6a4ea7ea52fb2af",
+    "dist/2022-09-20/rustc-beta-x86_64-unknown-illumos.tar.xz": "fae9048709741bcd21f4dc2ad8119576ba8dbe6b6442e79a443c207a4c52cc47",
+    "dist/2022-09-20/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "3785a8837c6fdf230b79992e4a3fd6a8b6faa269461bf908e427ffbd59728adb",
+    "dist/2022-09-20/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "a238209d54c2f9fea99a18bf43c4c0ae9bbc9cb10075e63d77af131728d64892",
+    "dist/2022-09-20/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "520ba16bf1b892f5c3d3fd6c1ba695ff48e0babd4ed5be97615887589e60c204",
+    "dist/2022-09-20/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "4251abe5dde29e9d2ffd7560e7f8eeb5c1b4ad6078b27896f63fcad5db6dabeb",
+    "dist/2022-09-20/rustc-beta-x86_64-unknown-netbsd.tar.gz": "ccdde196a376d8f06d3457a1b6d85b4b3692acc9e4bd055fb93dcb217ecd4494",
+    "dist/2022-09-20/rustc-beta-x86_64-unknown-netbsd.tar.xz": "22f5defadc7b4b4231315b420b6ee102c188a03381580feb7e22b75e16661017",
+    "dist/2022-09-20/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "8fead022ff05d4112e4cf7e637a459651dc793d9c38f1e823437f6c0c1bf6791",
+    "dist/2022-09-20/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "5e5f06c2c7a0567bb096b676ecde4bc87cd56c1a60d5e99feb0ac0b679280e1a",
+    "dist/2022-09-20/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "f365e910e58e962526bc2ffc01b47ea7b99b2be199baeed82e3bb0609147994b",
+    "dist/2022-09-20/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "3e8a10a285b3c248691e20090d2805d0aabdfc0555a5463bc472899fba085759",
+    "dist/2022-09-20/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "4316414f83c30535f0c46efba5fd011755f4afa6cc3440b39e8ec154ae451b69",
+    "dist/2022-09-20/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "f3bf1d0198db6efb751fd61d096615d09dec94a2732b028728d74a3513e9bc47",
+    "dist/2022-09-20/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "d0f4c30d1ed5144ce0a2931290cb730efa5616375ff846692faba0f04b2fed4a",
+    "dist/2022-09-20/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "3c20a791400f994ea5ae681700e9bd1773b9203821a5458448a038b70fe98794",
+    "dist/2022-09-20/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "587eabfb4ab41ec7fc1f344f8d8674feb1787cb402dbc10754c43eb9352233f6",
+    "dist/2022-09-20/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "0f5c05ce846c42f4afd9127fa5bc0af070e7a03911ed93630177d6304ec66fe9",
+    "dist/2022-09-20/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "dfcab7b0d9b93e1ce639a7a1b9774a41e1e70b67fb91814393531476e7ff6d97",
+    "dist/2022-09-20/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "aa66edb8208b73e3dc939ce82afb78b9104022427fc2278a50ca004c54b1fd5e",
+    "dist/2022-09-20/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "9d31be70cf5aa67219bf85e303651b928e89f54831a14ad004ef606291206991",
+    "dist/2022-09-20/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "8b1249489bbf015af1865ddeb83560fbbc52ca84937e14a2ae928eb4fa854322",
+    "dist/2022-09-20/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "4154363e7fc7888088ba020c7454a2e0ea75a64e01532ccc709dba3a16c48d78",
+    "dist/2022-09-20/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "48ba35bdfe87b78428fde9b7ff6fbd7682d7f94113b874e8308bd3c5e734154c",
+    "dist/2022-09-20/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "bf42294f1c3053b8ff6dcf13219056a5e83fb0680e5e53621c626f825f2f11c6",
+    "dist/2022-09-20/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "a08b27ac0b47af60618f07d884320e80665eab550536e19828b5fe139a59499d",
+    "dist/2022-09-20/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "748c42c63c3363d820b132a96bd95cd5203c5f808fb4885710065b9c609ae183",
+    "dist/2022-09-20/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "a2bfe3e12d0ecb5881a749a3d11652d45efcd9ee3647ea7c6b6cbc94071e34e4",
+    "dist/2022-09-20/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "a26f46c9d777ca55db8ef595219aea45c3ff7547ee7cfe07d01b9535dc00e1dd",
+    "dist/2022-09-20/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "d3ba043430fb0177023d4028c90a797d9b469d4c2fb2c539bb52e2dd070723cb",
+    "dist/2022-09-20/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "1f7b83d238dcd63de150d5fe457b8c04347626a583f049cac7989644787c2432",
+    "dist/2022-09-20/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "25f682b00e0362c16cb8d9879854d0a9781dd7a1e0f980a0c5064fad3764e8ef",
+    "dist/2022-09-20/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "09aaccf92485ad1d69623410f947b264835236d20472f974e348015bb8d2353f",
+    "dist/2022-09-20/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "cff865ff4979885f158af7b437ebe67ea2645489a6067abd97eeaa97b57041d8",
+    "dist/2022-09-20/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "1ca400758f5e44fa8ed01d8fc6d5622259cde42597fe80dc5e0e1b4129270c77",
+    "dist/2022-09-20/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "bd71382043ea4e934640a60660169d8785af453415d88945066bd6b8a42b0099",
+    "dist/2022-09-20/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "86feeca2cb543476419583bc1b10dbf8d91afd25ac77a9f04f789aff4f34e3e6",
+    "dist/2022-09-20/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "2ce655da2899200f9e4a331a45f005f4faea11cfdf5b74397a68d376dab88bf9",
+    "dist/2022-09-20/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "ed7e14c85bb1dd2900991775e812c56a76891a70dbea013bff06f73e7d1beaba",
+    "dist/2022-09-20/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "09710d4622fd7a9695d3907be6433c69f2ff590415fab776a05ba74ea5be63a9",
+    "dist/2022-09-20/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "02da320a5aac0eaffa83cd49b37d0cbcecab7686cef166f30dd5ed02fa9cb023",
+    "dist/2022-09-20/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "1f4465079a5493ec23f433cae4af3f633885b38f6ba7693387ccd355010b955e",
+    "dist/2022-09-20/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "a9a3bdba43897b0ab44c54537ce80fc969c378480348af715e293403b55b83be",
+    "dist/2022-09-20/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "2d58863182dac199cde47e12d3d92a64b5d068afc7e97e1047ae8b369fbe6df9",
+    "dist/2022-09-20/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "002667d802f1ff1224318c2090caaa3eefd18dabd1bcd40ad957b0c09acd047a",
+    "dist/2022-09-20/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "a34aa6451cf5faf985967ec5df78a41b21ae317bba7f8836e09f87571a7f9c16",
+    "dist/2022-09-20/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "8950773a8433fcc68f16c1e07210c3cf07c9e9240df92b0a90c67ca285d932f8",
+    "dist/2022-09-20/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "1ce5bb4a0a3490f95037a1512f4b5539c65bfdc5d7f6d42005019345bedb71e8",
+    "dist/2022-09-20/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "cdbef502285d5eec5788299354f391a2263858d630466cd1cc6d48748aefb1af",
+    "dist/2022-09-20/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "d5e04d0abda5e8ec429794a58f6404a6b95cc66cb218a52299c3bfaf1ec35485",
+    "dist/2022-09-20/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "d1ec51e70918e4f50463839eb86528582424d69eecc6af5cd07987621acc713e",
+    "dist/2022-09-20/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "64a108e60c1ff0e1c004d63e13a8180e5b266382e8434aa94eaff3c654158e51",
+    "dist/2022-09-20/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "d439ce2780177b3123de9a4c6727ea19831a215d19363d12b0bcc3bc19fc5074",
+    "dist/2022-09-20/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "851adf8da102068b4195a78ba587e168b7c4471b5a2e66451385a503362d091d",
+    "dist/2022-09-20/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "7bad988696f60f49c0ab1929f8cfe843effaa455ab1d20b002dadd1e10bc4ded",
+    "dist/2022-09-20/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "8bee32774f9af0b6f382640592b65d4187401a59bd3bea4a139e2dc43471bc0c",
+    "dist/2022-09-20/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "16a3ff01a6bc471da2195c7e8d0a6623b911d956db388b66e39096a7c81ae1d4",
+    "dist/2022-09-20/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "721115ea0ec7902f74d203eaadc71c79c4489caf9a23b0a81c513fddce5fb9b2",
+    "dist/2022-09-20/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "9042aba5f18ef575cff2e106c34b707d8fe013f4140e4a066ce80f2103563809",
+    "dist/2022-09-20/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "9106ee07a9f173ae845ae2b5ce30798e15deffd46149430ec5aacceaed7848b8",
+    "dist/2022-09-20/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "9acb78526c40efdfa0087373d802b30b75238e4c46e0bb18262e16416be49b4b",
+    "dist/2022-09-20/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "c7a73c5b9034417998800dabb08ba71e12713a299457381a4437ea454cead1bd"
   }
 }
diff --git a/src/test/codegen/stack-probes-call.rs b/src/test/codegen/stack-probes-call.rs
new file mode 100644
index 00000000000..56b02fdecad
--- /dev/null
+++ b/src/test/codegen/stack-probes-call.rs
@@ -0,0 +1,22 @@
+// Check the "probe-stack" attribute for targets with `StackProbeType::Call`,
+// or `StackProbeType::InlineOrCall` when running on older LLVM.
+
+// compile-flags: -C no-prepopulate-passes
+// revisions: i686 x86_64
+//[i686] compile-flags: --target i686-unknown-linux-gnu
+//[i686] needs-llvm-components: x86
+//[x86_64] compile-flags: --target x86_64-unknown-linux-gnu
+//[x86_64] needs-llvm-components: x86
+
+#![crate_type = "rlib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[no_mangle]
+pub fn foo() {
+// CHECK: @foo() unnamed_addr #0
+// CHECK: attributes #0 = { {{.*}}"probe-stack"="__rust_probestack"{{.*}} }
+}
diff --git a/src/test/codegen/stack-probes-inline.rs b/src/test/codegen/stack-probes-inline.rs
new file mode 100644
index 00000000000..837a1610810
--- /dev/null
+++ b/src/test/codegen/stack-probes-inline.rs
@@ -0,0 +1,26 @@
+// Check the "probe-stack" attribute for targets with `StackProbeType::Inline`,
+// or `StackProbeType::InlineOrCall` when running on newer LLVM.
+
+// compile-flags: -C no-prepopulate-passes
+// revisions: powerpc powerpc64 powerpc64le s390x
+//[powerpc] compile-flags: --target powerpc-unknown-linux-gnu
+//[powerpc] needs-llvm-components: powerpc
+//[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu
+//[powerpc64] needs-llvm-components: powerpc
+//[powerpc64le] compile-flags: --target powerpc64le-unknown-linux-gnu
+//[powerpc64le] needs-llvm-components: powerpc
+//[s390x] compile-flags: --target s390x-unknown-linux-gnu
+//[s390x] needs-llvm-components: systemz
+
+#![crate_type = "rlib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[no_mangle]
+pub fn foo() {
+// CHECK: @foo() unnamed_addr #0
+// CHECK: attributes #0 = { {{.*}}"probe-stack"="inline-asm"{{.*}} }
+}
diff --git a/src/test/codegen/stack-probes.rs b/src/test/codegen/stack-probes.rs
deleted file mode 100644
index 9bd351df3ea..00000000000
--- a/src/test/codegen/stack-probes.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-// ignore-arm
-// ignore-aarch64
-// ignore-mips
-// ignore-mips64
-// ignore-powerpc
-// ignore-powerpc64
-// ignore-powerpc64le
-// ignore-riscv64
-// ignore-s390x
-// ignore-sparc
-// ignore-sparc64
-// ignore-wasm
-// ignore-emscripten
-// ignore-windows
-// compile-flags: -C no-prepopulate-passes
-
-#![crate_type = "lib"]
-
-#[no_mangle]
-pub fn foo() {
-// CHECK: @foo() unnamed_addr #0
-}
diff --git a/src/test/incremental/spans_significant_w_panic.rs b/src/test/incremental/spans_significant_w_panic.rs
index e9e35791aa1..6f51c9729e3 100644
--- a/src/test/incremental/spans_significant_w_panic.rs
+++ b/src/test/incremental/spans_significant_w_panic.rs
@@ -8,7 +8,6 @@
 // compile-flags: -C overflow-checks=on -Z query-dep-graph
 
 #![feature(rustc_attrs)]
-#![feature(bench_black_box)]
 #![rustc_partition_codegened(module = "spans_significant_w_panic", cfg = "rpass2")]
 #![rustc_partition_codegened(module = "spans_significant_w_panic", cfg = "rpass4")]
 
diff --git a/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff b/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff
index bde2f04fac9..6f01553eef6 100644
--- a/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff
+++ b/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff
@@ -24,7 +24,7 @@
           _2 = <T as Clone>::clone(move _3) -> bb1; // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
                                            // mir::Constant
                                            // + span: $DIR/combine_clone_of_primitives.rs:8:5: 8:9
-                                           // + literal: Const { ty: for<'r> fn(&'r T) -> T {<T as Clone>::clone}, val: Value(<ZST>) }
+                                           // + literal: Const { ty: for<'a> fn(&'a T) -> T {<T as Clone>::clone}, val: Value(<ZST>) }
       }
   
       bb1: {
@@ -37,7 +37,7 @@
 -         _5 = <u64 as Clone>::clone(move _6) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
 -                                          // mir::Constant
 -                                          // + span: $DIR/combine_clone_of_primitives.rs:9:5: 9:11
--                                          // + literal: Const { ty: for<'r> fn(&'r u64) -> u64 {<u64 as Clone>::clone}, val: Value(<ZST>) }
+-                                          // + literal: Const { ty: for<'a> fn(&'a u64) -> u64 {<u64 as Clone>::clone}, val: Value(<ZST>) }
 +         _6 = _7;                         // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
 +         _5 = (*_6);                      // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
 +         goto -> bb2;                     // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
@@ -53,7 +53,7 @@
 -         _8 = <[f32; 3] as Clone>::clone(move _9) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
 -                                          // mir::Constant
 -                                          // + span: $DIR/combine_clone_of_primitives.rs:10:5: 10:16
--                                          // + literal: Const { ty: for<'r> fn(&'r [f32; 3]) -> [f32; 3] {<[f32; 3] as Clone>::clone}, val: Value(<ZST>) }
+-                                          // + literal: Const { ty: for<'a> fn(&'a [f32; 3]) -> [f32; 3] {<[f32; 3] as Clone>::clone}, val: Value(<ZST>) }
 +         _9 = _10;                        // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
 +         _8 = (*_9);                      // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
 +         goto -> bb3;                     // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
diff --git a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff
index 248abb8fd0e..f8a7c687e12 100644
--- a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff
+++ b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff
@@ -33,7 +33,7 @@
           _0 = core::slice::<impl [&i32]>::as_ptr(move _1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:44
                                            // mir::Constant
                                            // + span: $DIR/const-promotion-extern-static.rs:9:36: 9:42
-                                           // + literal: Const { ty: for<'r> fn(&'r [&i32]) -> *const &i32 {core::slice::<impl [&i32]>::as_ptr}, val: Value(<ZST>) }
+                                           // + literal: Const { ty: for<'a> fn(&'a [&i32]) -> *const &i32 {core::slice::<impl [&i32]>::as_ptr}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
index 8ce895fe72b..e938ca28af5 100644
--- a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
+++ b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
@@ -35,7 +35,7 @@
           _0 = core::slice::<impl [&i32]>::as_ptr(move _1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:55
                                            // mir::Constant
                                            // + span: $DIR/const-promotion-extern-static.rs:13:47: 13:53
-                                           // + literal: Const { ty: for<'r> fn(&'r [&i32]) -> *const &i32 {core::slice::<impl [&i32]>::as_ptr}, val: Value(<ZST>) }
+                                           // + literal: Const { ty: for<'a> fn(&'a [&i32]) -> *const &i32 {core::slice::<impl [&i32]>::as_ptr}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff b/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff
index 53f977de5d6..995611f0e96 100644
--- a/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff
+++ b/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff
@@ -20,7 +20,7 @@
           _2 = core::str::<impl str>::as_bytes(move _3) -> bb1; // scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23
                                            // mir::Constant
                                            // + span: $DIR/deduplicate_blocks.rs:5:13: 5:21
-                                           // + literal: Const { ty: for<'r> fn(&'r str) -> &'r [u8] {core::str::<impl str>::as_bytes}, val: Value(<ZST>) }
+                                           // + literal: Const { ty: for<'a> fn(&'a str) -> &'a [u8] {core::str::<impl str>::as_bytes}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/derefer_complex_case.main.Derefer.diff b/src/test/mir-opt/derefer_complex_case.main.Derefer.diff
index 1e1c80aad34..713d56c3836 100644
--- a/src/test/mir-opt/derefer_complex_case.main.Derefer.diff
+++ b/src/test/mir-opt/derefer_complex_case.main.Derefer.diff
@@ -56,7 +56,7 @@
           _7 = <std::slice::Iter<'_, i32> as Iterator>::next(move _8) -> bb3; // scope 1 at $DIR/derefer_complex_case.rs:+1:17: +1:26
                                            // mir::Constant
                                            // + span: $DIR/derefer_complex_case.rs:6:17: 6:26
-                                           // + literal: Const { ty: for<'r> fn(&'r mut std::slice::Iter<'_, i32>) -> Option<<std::slice::Iter<'_, i32> as Iterator>::Item> {<std::slice::Iter<'_, i32> as Iterator>::next}, val: Value(<ZST>) }
+                                           // + literal: Const { ty: for<'a> fn(&'a mut std::slice::Iter<'_, i32>) -> Option<<std::slice::Iter<'_, i32> as Iterator>::Item> {<std::slice::Iter<'_, i32> as Iterator>::next}, val: Value(<ZST>) }
       }
   
       bb3: {
diff --git a/src/test/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.diff
index a20a172af1b..80b09ed5f8d 100644
--- a/src/test/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.diff
+++ b/src/test/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.diff
@@ -1,12 +1,12 @@
 - // MIR for `nrvo` before DestinationPropagation
 + // MIR for `nrvo` after DestinationPropagation
   
-  fn nrvo(_1: for<'r> fn(&'r mut [u8; 1024])) -> [u8; 1024] {
+  fn nrvo(_1: for<'a> fn(&'a mut [u8; 1024])) -> [u8; 1024] {
       debug init => _1;                    // in scope 0 at $DIR/simple.rs:+0:9: +0:13
       let mut _0: [u8; 1024];              // return place in scope 0 at $DIR/simple.rs:+0:39: +0:49
       let mut _2: [u8; 1024];              // in scope 0 at $DIR/simple.rs:+1:9: +1:16
       let _3: ();                          // in scope 0 at $DIR/simple.rs:+2:5: +2:19
-      let mut _4: for<'r> fn(&'r mut [u8; 1024]); // in scope 0 at $DIR/simple.rs:+2:5: +2:9
+      let mut _4: for<'a> fn(&'a mut [u8; 1024]); // in scope 0 at $DIR/simple.rs:+2:5: +2:9
       let mut _5: &mut [u8; 1024];         // in scope 0 at $DIR/simple.rs:+2:10: +2:18
       let mut _6: &mut [u8; 1024];         // in scope 0 at $DIR/simple.rs:+2:10: +2:18
       scope 1 {
diff --git a/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff b/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff
index b789ae22974..e83a358b725 100644
--- a/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff
+++ b/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff
@@ -41,7 +41,7 @@
           _4 = Formatter::<'_>::sign_plus(move _5) -> bb1; // scope 0 at $DIR/funky_arms.rs:+4:22: +4:37
                                            // mir::Constant
                                            // + span: $DIR/funky_arms.rs:15:26: 15:35
-                                           // + literal: Const { ty: for<'r> fn(&'r Formatter<'_>) -> bool {Formatter::<'_>::sign_plus}, val: Value(<ZST>) }
+                                           // + literal: Const { ty: for<'a> fn(&'a Formatter<'_>) -> bool {Formatter::<'_>::sign_plus}, val: Value(<ZST>) }
       }
   
       bb1: {
@@ -69,7 +69,7 @@
           _7 = Formatter::<'_>::precision(move _8) -> bb5; // scope 3 at $DIR/funky_arms.rs:+13:30: +13:45
                                            // mir::Constant
                                            // + span: $DIR/funky_arms.rs:24:34: 24:43
-                                           // + literal: Const { ty: for<'r> fn(&'r Formatter<'_>) -> Option<usize> {Formatter::<'_>::precision}, val: Value(<ZST>) }
+                                           // + literal: Const { ty: for<'a> fn(&'a Formatter<'_>) -> Option<usize> {Formatter::<'_>::precision}, val: Value(<ZST>) }
       }
   
       bb5: {
@@ -100,7 +100,7 @@
           _0 = float_to_exponential_common_exact::<T>(move _11, move _12, move _13, move _14, move _17) -> bb7; // scope 3 at $DIR/funky_arms.rs:+15:9: +15:87
                                            // mir::Constant
                                            // + span: $DIR/funky_arms.rs:26:9: 26:42
-                                           // + literal: Const { ty: for<'r, 's, 't0> fn(&'r mut Formatter<'s>, &'t0 T, Sign, u32, bool) -> Result<(), std::fmt::Error> {float_to_exponential_common_exact::<T>}, val: Value(<ZST>) }
+                                           // + literal: Const { ty: for<'a, 'b, 'c> fn(&'a mut Formatter<'b>, &'c T, Sign, u32, bool) -> Result<(), std::fmt::Error> {float_to_exponential_common_exact::<T>}, val: Value(<ZST>) }
       }
   
       bb7: {
@@ -125,7 +125,7 @@
           _0 = float_to_exponential_common_shortest::<T>(move _18, move _19, move _20, move _21) -> bb9; // scope 2 at $DIR/funky_arms.rs:+17:9: +17:68
                                            // mir::Constant
                                            // + span: $DIR/funky_arms.rs:28:9: 28:45
-                                           // + literal: Const { ty: for<'r, 's, 't0> fn(&'r mut Formatter<'s>, &'t0 T, Sign, bool) -> Result<(), std::fmt::Error> {float_to_exponential_common_shortest::<T>}, val: Value(<ZST>) }
+                                           // + literal: Const { ty: for<'a, 'b, 'c> fn(&'a mut Formatter<'b>, &'c T, Sign, bool) -> Result<(), std::fmt::Error> {float_to_exponential_common_shortest::<T>}, val: Value(<ZST>) }
       }
   
       bb9: {
diff --git a/src/test/mir-opt/inline/cycle.f.Inline.diff b/src/test/mir-opt/inline/cycle.f.Inline.diff
index 40fdd1cdb19..75ea69a42eb 100644
--- a/src/test/mir-opt/inline/cycle.f.Inline.diff
+++ b/src/test/mir-opt/inline/cycle.f.Inline.diff
@@ -17,7 +17,7 @@
           _2 = <impl Fn() as Fn<()>>::call(move _3, move _4) -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/cycle.rs:+1:5: +1:8
                                            // mir::Constant
                                            // + span: $DIR/cycle.rs:6:5: 6:6
-                                           // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl Fn(), ()) -> <impl Fn() as FnOnce<()>>::Output {<impl Fn() as Fn<()>>::call}, val: Value(<ZST>) }
+                                           // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a impl Fn(), ()) -> <impl Fn() as FnOnce<()>>::Output {<impl Fn() as Fn<()>>::call}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff b/src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff
index 4b50ba9501c..1e95b5b29ff 100644
--- a/src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff
+++ b/src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff
@@ -28,7 +28,7 @@
                                            // mir::Constant
                                            // + span: $DIR/dyn-trait.rs:33:13: 33:21
                                            // + user_ty: UserType(0)
-                                           // + literal: Const { ty: for<'r> fn(&'r T) -> &'r <Q as Query>::C {<Q as Query>::cache::<T>}, val: Value(<ZST>) }
+                                           // + literal: Const { ty: for<'a> fn(&'a T) -> &'a <Q as Query>::C {<Q as Query>::cache::<T>}, val: Value(<ZST>) }
       }
   
       bb1: {
@@ -46,9 +46,9 @@
 +         _0 = <dyn Cache<V = <Q as Query>::V> as Cache>::store_nocache(move _7) -> bb2; // scope 3 at $DIR/dyn-trait.rs:21:5: 21:22
                                            // mir::Constant
 -                                          // + span: $DIR/dyn-trait.rs:34:5: 34:22
--                                          // + literal: Const { ty: for<'r> fn(&'r <Q as Query>::C) {try_execute_query::<<Q as Query>::C>}, val: Value(<ZST>) }
+-                                          // + literal: Const { ty: for<'a> fn(&'a <Q as Query>::C) {try_execute_query::<<Q as Query>::C>}, val: Value(<ZST>) }
 +                                          // + span: $DIR/dyn-trait.rs:21:7: 21:20
-+                                          // + literal: Const { ty: for<'r> fn(&'r dyn Cache<V = <Q as Query>::V>) {<dyn Cache<V = <Q as Query>::V> as Cache>::store_nocache}, val: Value(<ZST>) }
++                                          // + literal: Const { ty: for<'a> fn(&'a dyn Cache<V = <Q as Query>::V>) {<dyn Cache<V = <Q as Query>::V> as Cache>::store_nocache}, val: Value(<ZST>) }
       }
   
       bb2: {
diff --git a/src/test/mir-opt/inline/dyn_trait.mk_cycle.Inline.diff b/src/test/mir-opt/inline/dyn_trait.mk_cycle.Inline.diff
index 994930ef4cf..7421db4d063 100644
--- a/src/test/mir-opt/inline/dyn_trait.mk_cycle.Inline.diff
+++ b/src/test/mir-opt/inline/dyn_trait.mk_cycle.Inline.diff
@@ -12,7 +12,7 @@
           _0 = <dyn Cache<V = V> as Cache>::store_nocache(move _2) -> bb1; // scope 0 at $DIR/dyn-trait.rs:+1:5: +1:22
                                            // mir::Constant
                                            // + span: $DIR/dyn-trait.rs:21:7: 21:20
-                                           // + literal: Const { ty: for<'r> fn(&'r dyn Cache<V = V>) {<dyn Cache<V = V> as Cache>::store_nocache}, val: Value(<ZST>) }
+                                           // + literal: Const { ty: for<'a> fn(&'a dyn Cache<V = V>) {<dyn Cache<V = V> as Cache>::store_nocache}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff b/src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff
index 58c05b9f564..e6e78374422 100644
--- a/src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff
+++ b/src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff
@@ -23,9 +23,9 @@
 +         _0 = <dyn Cache<V = <C as Cache>::V> as Cache>::store_nocache(move _4) -> bb1; // scope 1 at $DIR/dyn-trait.rs:21:5: 21:22
                                            // mir::Constant
 -                                          // + span: $DIR/dyn-trait.rs:27:5: 27:13
--                                          // + literal: Const { ty: for<'r> fn(&'r (dyn Cache<V = <C as Cache>::V> + 'r)) {mk_cycle::<<C as Cache>::V>}, val: Value(<ZST>) }
+-                                          // + literal: Const { ty: for<'a> fn(&'a (dyn Cache<V = <C as Cache>::V> + 'a)) {mk_cycle::<<C as Cache>::V>}, val: Value(<ZST>) }
 +                                          // + span: $DIR/dyn-trait.rs:21:7: 21:20
-+                                          // + literal: Const { ty: for<'r> fn(&'r dyn Cache<V = <C as Cache>::V>) {<dyn Cache<V = <C as Cache>::V> as Cache>::store_nocache}, val: Value(<ZST>) }
++                                          // + literal: Const { ty: for<'a> fn(&'a dyn Cache<V = <C as Cache>::V>) {<dyn Cache<V = <C as Cache>::V> as Cache>::store_nocache}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/inline/inline_generator.main.Inline.diff b/src/test/mir-opt/inline/inline_generator.main.Inline.diff
index 0b992e3c32a..3fd8aad7238 100644
--- a/src/test/mir-opt/inline/inline_generator.main.Inline.diff
+++ b/src/test/mir-opt/inline/inline_generator.main.Inline.diff
@@ -70,7 +70,7 @@
 -         _1 = <[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator<bool>>::resume(move _2, const false) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:+1:14: +1:46
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline-generator.rs:9:33: 9:39
--                                          // + literal: Const { ty: for<'r> fn(Pin<&'r mut [generator@$DIR/inline-generator.rs:15:5: 15:8]>, bool) -> GeneratorState<<[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator<bool>>::Yield, <[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator<bool>>::Return> {<[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator<bool>>::resume}, val: Value(<ZST>) }
+-                                          // + literal: Const { ty: for<'a> fn(Pin<&'a mut [generator@$DIR/inline-generator.rs:15:5: 15:8]>, bool) -> GeneratorState<<[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator<bool>>::Yield, <[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator<bool>>::Return> {<[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator<bool>>::resume}, val: Value(<ZST>) }
 +         StorageLive(_7);                 // scope 0 at $DIR/inline-generator.rs:+1:14: +1:46
 +         _7 = const false;                // scope 0 at $DIR/inline-generator.rs:+1:14: +1:46
 +         StorageLive(_10);                // scope 0 at $DIR/inline-generator.rs:+1:14: +1:46
diff --git a/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir b/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir
index cabc1a92024..169e7f5c5d9 100644
--- a/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir
@@ -2,8 +2,8 @@
 
 fn bar() -> bool {
     let mut _0: bool;                    // return place in scope 0 at $DIR/inline-retag.rs:+0:13: +0:17
-    let _1: for<'r, 's> fn(&'r i32, &'s i32) -> bool {foo}; // in scope 0 at $DIR/inline-retag.rs:+1:9: +1:10
-    let mut _2: for<'r, 's> fn(&'r i32, &'s i32) -> bool {foo}; // in scope 0 at $DIR/inline-retag.rs:+2:5: +2:6
+    let _1: for<'a, 'b> fn(&'a i32, &'b i32) -> bool {foo}; // in scope 0 at $DIR/inline-retag.rs:+1:9: +1:10
+    let mut _2: for<'a, 'b> fn(&'a i32, &'b i32) -> bool {foo}; // in scope 0 at $DIR/inline-retag.rs:+2:5: +2:6
     let mut _3: &i32;                    // in scope 0 at $DIR/inline-retag.rs:+2:7: +2:9
     let _4: &i32;                        // in scope 0 at $DIR/inline-retag.rs:+2:7: +2:9
     let _5: i32;                         // in scope 0 at $DIR/inline-retag.rs:+2:8: +2:9
@@ -27,7 +27,7 @@ fn bar() -> bool {
         _1 = foo;                        // scope 0 at $DIR/inline-retag.rs:+1:13: +1:16
                                          // mir::Constant
                                          // + span: $DIR/inline-retag.rs:11:13: 11:16
-                                         // + literal: Const { ty: for<'r, 's> fn(&'r i32, &'s i32) -> bool {foo}, val: Value(<ZST>) }
+                                         // + literal: Const { ty: for<'a, 'b> fn(&'a i32, &'b i32) -> bool {foo}, val: Value(<ZST>) }
         StorageLive(_2);                 // scope 1 at $DIR/inline-retag.rs:+2:5: +2:6
         _2 = _1;                         // scope 1 at $DIR/inline-retag.rs:+2:5: +2:6
         StorageLive(_3);                 // scope 1 at $DIR/inline-retag.rs:+2:7: +2:9
diff --git a/src/test/mir-opt/inline/inline_shims.clone.Inline.diff b/src/test/mir-opt/inline/inline_shims.clone.Inline.diff
index 25ca05893b2..d691e90b7da 100644
--- a/src/test/mir-opt/inline/inline_shims.clone.Inline.diff
+++ b/src/test/mir-opt/inline/inline_shims.clone.Inline.diff
@@ -14,7 +14,7 @@
 -         _0 = <fn(A, B) as Clone>::clone(move _2) -> bb1; // scope 0 at $DIR/inline-shims.rs:+1:5: +1:14
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline-shims.rs:6:7: 6:12
--                                          // + literal: Const { ty: for<'r> fn(&'r fn(A, B)) -> fn(A, B) {<fn(A, B) as Clone>::clone}, val: Value(<ZST>) }
+-                                          // + literal: Const { ty: for<'a> fn(&'a fn(A, B)) -> fn(A, B) {<fn(A, B) as Clone>::clone}, val: Value(<ZST>) }
 -     }
 - 
 -     bb1: {
diff --git a/src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir b/src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir
index ed95edd16ce..89eefc29269 100644
--- a/src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir
@@ -11,7 +11,7 @@ fn test(_1: &dyn X) -> u32 {
         _0 = <dyn X as X>::y(move _2) -> bb1; // scope 0 at $DIR/inline-trait-method.rs:+1:5: +1:10
                                          // mir::Constant
                                          // + span: $DIR/inline-trait-method.rs:9:7: 9:8
-                                         // + literal: Const { ty: for<'r> fn(&'r dyn X) -> u32 {<dyn X as X>::y}, val: Value(<ZST>) }
+                                         // + literal: Const { ty: for<'a> fn(&'a dyn X) -> u32 {<dyn X as X>::y}, val: Value(<ZST>) }
     }
 
     bb1: {
diff --git a/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir b/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir
index b8896430d22..3d05869fa51 100644
--- a/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir
@@ -21,7 +21,7 @@ fn test2(_1: &dyn X) -> bool {
         _0 = <dyn X as X>::y(move _4) -> bb1; // scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:10
                                          // mir::Constant
                                          // + span: $DIR/inline-trait-method_2.rs:10:7: 10:8
-                                         // + literal: Const { ty: for<'r> fn(&'r dyn X) -> bool {<dyn X as X>::y}, val: Value(<ZST>) }
+                                         // + literal: Const { ty: for<'a> fn(&'a dyn X) -> bool {<dyn X as X>::y}, val: Value(<ZST>) }
     }
 
     bb1: {
diff --git a/src/test/mir-opt/inline/issue_78442.bar.Inline.diff b/src/test/mir-opt/inline/issue_78442.bar.Inline.diff
index c16dfdf395e..4186650dfab 100644
--- a/src/test/mir-opt/inline/issue_78442.bar.Inline.diff
+++ b/src/test/mir-opt/inline/issue_78442.bar.Inline.diff
@@ -29,7 +29,7 @@
 -         _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17
 -                                          // mir::Constant
 -                                          // + span: $DIR/issue-78442.rs:11:5: 11:15
--                                          // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r fn() {foo}, ()) -> <fn() {foo} as FnOnce<()>>::Output {<fn() {foo} as Fn<()>>::call}, val: Value(<ZST>) }
+-                                          // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() {foo}, ()) -> <fn() {foo} as FnOnce<()>>::Output {<fn() {foo} as Fn<()>>::call}, val: Value(<ZST>) }
 +         _2 = move (*_3)() -> [return: bb5, unwind: bb3]; // scope 1 at $SRC_DIR/core/src/ops/function.rs:LL:COL
       }
   
diff --git a/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff b/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff
index 0faa522cbaa..24e9a3df15a 100644
--- a/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff
+++ b/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff
@@ -29,8 +29,8 @@
 +         _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17
                                            // mir::Constant
                                            // + span: $DIR/issue-78442.rs:11:5: 11:15
--                                          // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl Fn(), ()) -> <impl Fn() as FnOnce<()>>::Output {<impl Fn() as Fn<()>>::call}, val: Value(<ZST>) }
-+                                          // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r fn() {foo}, ()) -> <fn() {foo} as FnOnce<()>>::Output {<fn() {foo} as Fn<()>>::call}, val: Value(<ZST>) }
+-                                          // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a impl Fn(), ()) -> <impl Fn() as FnOnce<()>>::Output {<impl Fn() as Fn<()>>::call}, val: Value(<ZST>) }
++                                          // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() {foo}, ()) -> <fn() {foo} as FnOnce<()>>::Output {<fn() {foo} as Fn<()>>::call}, val: Value(<ZST>) }
       }
   
       bb2: {
diff --git a/src/test/mir-opt/issue-101867.rs b/src/test/mir-opt/issue-101867.rs
index 931396e2171..8a357eb7995 100644
--- a/src/test/mir-opt/issue-101867.rs
+++ b/src/test/mir-opt/issue-101867.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(bootstrap, feature(let_else))]
-
 // EMIT_MIR issue_101867.main.mir_map.0.mir
 fn main() {
     let x: Option<u8> = Some(1);
diff --git a/src/test/mir-opt/issue_101867.main.mir_map.0.mir b/src/test/mir-opt/issue_101867.main.mir_map.0.mir
index 98501ac8c9d..42a9e558760 100644
--- a/src/test/mir-opt/issue_101867.main.mir_map.0.mir
+++ b/src/test/mir-opt/issue_101867.main.mir_map.0.mir
@@ -1,8 +1,8 @@
 // MIR for `main` 0 mir_map
 
 | User Type Annotations
-| 0: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(std::option::Option<u8>) }, span: $DIR/issue-101867.rs:5:12: 5:22, inferred_ty: std::option::Option<u8>
-| 1: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(std::option::Option<u8>) }, span: $DIR/issue-101867.rs:5:12: 5:22, inferred_ty: std::option::Option<u8>
+| 0: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(std::option::Option<u8>) }, span: $DIR/issue-101867.rs:3:12: 3:22, inferred_ty: std::option::Option<u8>
+| 1: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(std::option::Option<u8>) }, span: $DIR/issue-101867.rs:3:12: 3:22, inferred_ty: std::option::Option<u8>
 |
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/issue-101867.rs:+0:11: +0:11
diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff
index 533907e7040..269e4e32617 100644
--- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff
+++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff
@@ -139,7 +139,7 @@
           _21 = core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _23, move _25, move _27); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(<ZST>) }
+                                           // + literal: Const { ty: for<'a, 'b, 'c> fn(core::panicking::AssertKind, &'a i32, &'b i32, Option<Arguments<'c>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(<ZST>) }
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) }
diff --git a/src/test/mir-opt/issue_91633.bar.mir_map.0.mir b/src/test/mir-opt/issue_91633.bar.mir_map.0.mir
index f5092d2ac92..625f6c7361a 100644
--- a/src/test/mir-opt/issue_91633.bar.mir_map.0.mir
+++ b/src/test/mir-opt/issue_91633.bar.mir_map.0.mir
@@ -15,7 +15,7 @@ fn bar(_1: Box<[T]>) -> () {
         _2 = <[T] as Index<usize>>::index(move _3, const 0_usize) -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-91633.rs:+4:14: +4:19
                                          // mir::Constant
                                          // + span: $DIR/issue-91633.rs:15:14: 15:19
-                                         // + literal: Const { ty: for<'r> fn(&'r [T], usize) -> &'r <[T] as Index<usize>>::Output {<[T] as Index<usize>>::index}, val: Value(<ZST>) }
+                                         // + literal: Const { ty: for<'a> fn(&'a [T], usize) -> &'a <[T] as Index<usize>>::Output {<[T] as Index<usize>>::index}, val: Value(<ZST>) }
     }
 
     bb1: {
diff --git a/src/test/mir-opt/issue_91633.foo.mir_map.0.mir b/src/test/mir-opt/issue_91633.foo.mir_map.0.mir
index 2e8b0feedd3..9903e203a23 100644
--- a/src/test/mir-opt/issue_91633.foo.mir_map.0.mir
+++ b/src/test/mir-opt/issue_91633.foo.mir_map.0.mir
@@ -27,7 +27,7 @@ fn foo(_1: Box<[T]>) -> T {
         _2 = <T as Clone>::clone(move _3) -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/issue-91633.rs:+2:14: +2:27
                                          // mir::Constant
                                          // + span: $DIR/issue-91633.rs:28:20: 28:25
-                                         // + literal: Const { ty: for<'r> fn(&'r T) -> T {<T as Clone>::clone}, val: Value(<ZST>) }
+                                         // + literal: Const { ty: for<'a> fn(&'a T) -> T {<T as Clone>::clone}, val: Value(<ZST>) }
     }
 
     bb2: {
diff --git a/src/test/mir-opt/issue_91633.hey.mir_map.0.mir b/src/test/mir-opt/issue_91633.hey.mir_map.0.mir
index 74f4a5a9761..37c3b3fcaca 100644
--- a/src/test/mir-opt/issue_91633.hey.mir_map.0.mir
+++ b/src/test/mir-opt/issue_91633.hey.mir_map.0.mir
@@ -17,7 +17,7 @@ fn hey(_1: &[T]) -> () {
         _3 = <[T] as Index<usize>>::index(move _4, const 0_usize) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/issue-91633.rs:+4:15: +4:20
                                          // mir::Constant
                                          // + span: $DIR/issue-91633.rs:7:15: 7:20
-                                         // + literal: Const { ty: for<'r> fn(&'r [T], usize) -> &'r <[T] as Index<usize>>::Output {<[T] as Index<usize>>::index}, val: Value(<ZST>) }
+                                         // + literal: Const { ty: for<'a> fn(&'a [T], usize) -> &'a <[T] as Index<usize>>::Output {<[T] as Index<usize>>::index}, val: Value(<ZST>) }
     }
 
     bb1: {
diff --git a/src/test/mir-opt/issue_99325.main.mir_map.0.mir b/src/test/mir-opt/issue_99325.main.mir_map.0.mir
index 6f58bb1b47f..165efa9df41 100644
--- a/src/test/mir-opt/issue_99325.main.mir_map.0.mir
+++ b/src/test/mir-opt/issue_99325.main.mir_map.0.mir
@@ -101,7 +101,7 @@ fn main() -> () {
         _11 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _12, move _13) -> [return: bb2, unwind: bb19]; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                          // mir::Constant
                                          // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                         // + literal: Const { ty: for<'r, 's> fn(&'r &[u8], &'s &[u8; 4]) -> bool {<&[u8] as PartialEq<&[u8; 4]>>::eq}, val: Value(<ZST>) }
+                                         // + literal: Const { ty: for<'a, 'b> fn(&'a &[u8], &'b &[u8; 4]) -> bool {<&[u8] as PartialEq<&[u8; 4]>>::eq}, val: Value(<ZST>) }
     }
 
     bb2: {
@@ -132,7 +132,7 @@ fn main() -> () {
         _16 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _17, move _18, move _20, move _22) -> bb19; // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                          // mir::Constant
                                          // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                         // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r &[u8], &'s &[u8; 4], Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<&[u8], &[u8; 4]>}, val: Value(<ZST>) }
+                                         // + literal: Const { ty: for<'a, 'b, 'c> fn(core::panicking::AssertKind, &'a &[u8], &'b &[u8; 4], Option<Arguments<'c>>) -> ! {core::panicking::assert_failed::<&[u8], &[u8; 4]>}, val: Value(<ZST>) }
     }
 
     bb4: {
@@ -210,7 +210,7 @@ fn main() -> () {
         _32 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _33, move _34) -> [return: bb11, unwind: bb19]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                          // mir::Constant
                                          // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                         // + literal: Const { ty: for<'r, 's> fn(&'r &[u8], &'s &[u8; 4]) -> bool {<&[u8] as PartialEq<&[u8; 4]>>::eq}, val: Value(<ZST>) }
+                                         // + literal: Const { ty: for<'a, 'b> fn(&'a &[u8], &'b &[u8; 4]) -> bool {<&[u8] as PartialEq<&[u8; 4]>>::eq}, val: Value(<ZST>) }
     }
 
     bb11: {
@@ -241,7 +241,7 @@ fn main() -> () {
         _37 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _38, move _39, move _41, move _43) -> bb19; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                          // mir::Constant
                                          // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                         // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r &[u8], &'s &[u8; 4], Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<&[u8], &[u8; 4]>}, val: Value(<ZST>) }
+                                         // + literal: Const { ty: for<'a, 'b, 'c> fn(core::panicking::AssertKind, &'a &[u8], &'b &[u8; 4], Option<Arguments<'c>>) -> ! {core::panicking::assert_failed::<&[u8], &[u8; 4]>}, val: Value(<ZST>) }
     }
 
     bb13: {
diff --git a/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff
index a648e5d672d..d962ef8cb12 100644
--- a/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff
+++ b/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff
@@ -32,7 +32,7 @@
 -         _2 = discriminant_value::<T>(move _3) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:49:5: 49:41
--                                          // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r T) -> <T as DiscriminantKind>::Discriminant {discriminant_value::<T>}, val: Value(<ZST>) }
+-                                          // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a T) -> <T as DiscriminantKind>::Discriminant {discriminant_value::<T>}, val: Value(<ZST>) }
 +         _2 = discriminant((*_3));        // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45
 +         goto -> bb1;                     // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45
       }
@@ -53,7 +53,7 @@
 -         _5 = discriminant_value::<i32>(move _6) -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:50:5: 50:41
--                                          // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r i32) -> <i32 as DiscriminantKind>::Discriminant {discriminant_value::<i32>}, val: Value(<ZST>) }
+-                                          // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a i32) -> <i32 as DiscriminantKind>::Discriminant {discriminant_value::<i32>}, val: Value(<ZST>) }
 +         _5 = discriminant((*_6));        // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45
 +         goto -> bb2;                     // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45
       }
@@ -74,7 +74,7 @@
 -         _9 = discriminant_value::<()>(move _10) -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:51:5: 51:41
--                                          // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r ()) -> <() as DiscriminantKind>::Discriminant {discriminant_value::<()>}, val: Value(<ZST>) }
+-                                          // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a ()) -> <() as DiscriminantKind>::Discriminant {discriminant_value::<()>}, val: Value(<ZST>) }
 +         _9 = discriminant((*_10));       // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46
 +         goto -> bb3;                     // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46
       }
@@ -95,7 +95,7 @@
 -         _13 = discriminant_value::<E>(move _14) -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:52:5: 52:41
--                                          // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r E) -> <E as DiscriminantKind>::Discriminant {discriminant_value::<E>}, val: Value(<ZST>) }
+-                                          // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a E) -> <E as DiscriminantKind>::Discriminant {discriminant_value::<E>}, val: Value(<ZST>) }
 +         _13 = discriminant((*_14));      // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48
 +         goto -> bb4;                     // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48
       }
diff --git a/src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff b/src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff
index 46fccba56f7..5f5d6e68fdc 100644
--- a/src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff
+++ b/src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff
@@ -23,7 +23,7 @@
 -         _5 = core::slice::<impl [u8]>::len(move _6) -> bb1; // scope 0 at $DIR/lower_slice_len.rs:+1:16: +1:27
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_slice_len.rs:5:22: 5:25
--                                          // + literal: Const { ty: for<'r> fn(&'r [u8]) -> usize {core::slice::<impl [u8]>::len}, val: Value(<ZST>) }
+-                                          // + literal: Const { ty: for<'a> fn(&'a [u8]) -> usize {core::slice::<impl [u8]>::len}, val: Value(<ZST>) }
 +         _5 = Len((*_6));                 // scope 0 at $DIR/lower_slice_len.rs:+1:16: +1:27
 +         goto -> bb1;                     // scope 0 at $DIR/lower_slice_len.rs:+1:16: +1:27
       }
diff --git a/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir b/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir
index 25c6e306006..963e7cde656 100644
--- a/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir
+++ b/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir
@@ -20,7 +20,7 @@ fn main() -> () {
         _2 = <str as ToString>::to_string(move _3) -> bb1; // scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:20: +1:34
                                          // mir::Constant
                                          // + span: $DIR/no-spurious-drop-after-call.rs:9:23: 9:32
-                                         // + literal: Const { ty: for<'r> fn(&'r str) -> String {<str as ToString>::to_string}, val: Value(<ZST>) }
+                                         // + literal: Const { ty: for<'a> fn(&'a str) -> String {<str as ToString>::to_string}, val: Value(<ZST>) }
     }
 
     bb1: {
diff --git a/src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff b/src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff
index 9e89bd9fb96..ce35f920bf6 100644
--- a/src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff
+++ b/src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff
@@ -1,13 +1,13 @@
 - // MIR for `nrvo` before RenameReturnPlace
 + // MIR for `nrvo` after RenameReturnPlace
   
-  fn nrvo(_1: for<'r> fn(&'r mut [u8; 1024])) -> [u8; 1024] {
+  fn nrvo(_1: for<'a> fn(&'a mut [u8; 1024])) -> [u8; 1024] {
       debug init => _1;                    // in scope 0 at $DIR/nrvo-simple.rs:+0:9: +0:13
 -     let mut _0: [u8; 1024];              // return place in scope 0 at $DIR/nrvo-simple.rs:+0:39: +0:49
 +     let mut _0: [u8; 1024];              // return place in scope 0 at $DIR/nrvo-simple.rs:+1:9: +1:16
       let mut _2: [u8; 1024];              // in scope 0 at $DIR/nrvo-simple.rs:+1:9: +1:16
       let _3: ();                          // in scope 0 at $DIR/nrvo-simple.rs:+2:5: +2:19
-      let mut _4: for<'r> fn(&'r mut [u8; 1024]); // in scope 0 at $DIR/nrvo-simple.rs:+2:5: +2:9
+      let mut _4: for<'a> fn(&'a mut [u8; 1024]); // in scope 0 at $DIR/nrvo-simple.rs:+2:5: +2:9
       let mut _5: &mut [u8; 1024];         // in scope 0 at $DIR/nrvo-simple.rs:+2:10: +2:18
       let mut _6: &mut [u8; 1024];         // in scope 0 at $DIR/nrvo-simple.rs:+2:10: +2:18
       scope 1 {
diff --git a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff
index 99667aabdae..188aa556490 100644
--- a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff
+++ b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff
@@ -57,7 +57,7 @@
           _7 = <std::ops::Range<i32> as Iterator>::next(move _8) -> bb3; // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
                                            // mir::Constant
                                            // + span: $DIR/remove_storage_markers.rs:10:14: 10:19
-                                           // + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> Option<<std::ops::Range<i32> as Iterator>::Item> {<std::ops::Range<i32> as Iterator>::next}, val: Value(<ZST>) }
+                                           // + literal: Const { ty: for<'a> fn(&'a mut std::ops::Range<i32>) -> Option<<std::ops::Range<i32> as Iterator>::Item> {<std::ops::Range<i32> as Iterator>::next}, val: Value(<ZST>) }
       }
   
       bb3: {
diff --git a/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir
index 318b241fa73..fe57e32a7ac 100644
--- a/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir
+++ b/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir
@@ -180,7 +180,7 @@ fn array_casts() -> () {
         _28 = core::panicking::assert_failed::<usize, usize>(move _29, move _30, move _32, move _34); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                          // mir::Constant
                                          // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                         // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r usize, &'s usize, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<usize, usize>}, val: Value(<ZST>) }
+                                         // + literal: Const { ty: for<'a, 'b, 'c> fn(core::panicking::AssertKind, &'a usize, &'b usize, Option<Arguments<'c>>) -> ! {core::panicking::assert_failed::<usize, usize>}, val: Value(<ZST>) }
     }
 
     bb4: {
diff --git a/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir b/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir
index 84f674db2d1..cdc413c568f 100644
--- a/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir
+++ b/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir
@@ -11,7 +11,7 @@ fn std::ptr::drop_in_place(_1: *mut Test) -> () {
         _3 = <Test as Drop>::drop(move _2) -> bb1; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
                                          // mir::Constant
                                          // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-                                         // + literal: Const { ty: for<'r> fn(&'r mut Test) {<Test as Drop>::drop}, val: Value(<ZST>) }
+                                         // + literal: Const { ty: for<'a> fn(&'a mut Test) {<Test as Drop>::drop}, val: Value(<ZST>) }
     }
 
     bb1: {
diff --git a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir
index 7212de52fc3..81225b44ebf 100644
--- a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir
+++ b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir
@@ -11,7 +11,7 @@ fn main() -> () {
     let mut _9: &mut i32;                // in scope 0 at $DIR/retag.rs:+4:19: +4:20
     let mut _12: *mut i32;               // in scope 0 at $DIR/retag.rs:+7:18: +7:29
     let mut _14: [closure@main::{closure#0}]; // in scope 0 at $DIR/retag.rs:+11:31: +14:6
-    let mut _16: for<'r> fn(&'r i32) -> &'r i32; // in scope 0 at $DIR/retag.rs:+15:14: +15:15
+    let mut _16: for<'a> fn(&'a i32) -> &'a i32; // in scope 0 at $DIR/retag.rs:+15:14: +15:15
     let mut _17: &i32;                   // in scope 0 at $DIR/retag.rs:+15:16: +15:18
     let _18: &i32;                       // in scope 0 at $DIR/retag.rs:+15:16: +15:18
     let _19: &i32;                       // in scope 0 at $DIR/retag.rs:+18:5: +18:24
@@ -25,7 +25,7 @@ fn main() -> () {
     scope 1 {
         debug x => _1;                   // in scope 1 at $DIR/retag.rs:+1:9: +1:14
         let _3: &mut i32;                // in scope 1 at $DIR/retag.rs:+3:13: +3:14
-        let _13: for<'r> fn(&'r i32) -> &'r i32; // in scope 1 at $DIR/retag.rs:+11:9: +11:10
+        let _13: for<'a> fn(&'a i32) -> &'a i32; // in scope 1 at $DIR/retag.rs:+11:9: +11:10
         scope 2 {
             debug v => _3;               // in scope 2 at $DIR/retag.rs:+3:13: +3:14
             let _8: &mut i32;            // in scope 2 at $DIR/retag.rs:+4:13: +4:14
@@ -75,7 +75,7 @@ fn main() -> () {
         _3 = Test::foo(move _4, move _6) -> [return: bb1, unwind: bb8]; // scope 1 at $DIR/retag.rs:+3:17: +3:36
                                          // mir::Constant
                                          // + span: $DIR/retag.rs:33:25: 33:28
-                                         // + literal: Const { ty: for<'r, 'x> fn(&'r Test, &'x mut i32) -> &'x mut i32 {Test::foo}, val: Value(<ZST>) }
+                                         // + literal: Const { ty: for<'a, 'x> fn(&'a Test, &'x mut i32) -> &'x mut i32 {Test::foo}, val: Value(<ZST>) }
     }
 
     bb1: {
@@ -114,7 +114,7 @@ fn main() -> () {
         StorageLive(_14);                // scope 1 at $DIR/retag.rs:+11:31: +14:6
         Deinit(_14);                     // scope 1 at $DIR/retag.rs:+11:31: +14:6
         Retag(_14);                      // scope 1 at $DIR/retag.rs:+11:31: +14:6
-        _13 = move _14 as for<'r> fn(&'r i32) -> &'r i32 (Pointer(ClosureFnPointer(Normal))); // scope 1 at $DIR/retag.rs:+11:31: +14:6
+        _13 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (Pointer(ClosureFnPointer(Normal))); // scope 1 at $DIR/retag.rs:+11:31: +14:6
         StorageDead(_14);                // scope 1 at $DIR/retag.rs:+11:47: +11:48
         StorageLive(_15);                // scope 6 at $DIR/retag.rs:+15:9: +15:11
         StorageLive(_16);                // scope 6 at $DIR/retag.rs:+15:14: +15:15
@@ -154,7 +154,7 @@ fn main() -> () {
         _19 = Test::foo_shr(move _20, move _22) -> [return: bb4, unwind: bb7]; // scope 7 at $DIR/retag.rs:+18:5: +18:24
                                          // mir::Constant
                                          // + span: $DIR/retag.rs:48:13: 48:20
-                                         // + literal: Const { ty: for<'r, 'x> fn(&'r Test, &'x i32) -> &'x i32 {Test::foo_shr}, val: Value(<ZST>) }
+                                         // + literal: Const { ty: for<'a, 'x> fn(&'a Test, &'x i32) -> &'x i32 {Test::foo_shr}, val: Value(<ZST>) }
     }
 
     bb4: {
diff --git a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir
index 7ffd242e0dc..ed9f3bdbdf4 100644
--- a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir
+++ b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir
@@ -34,6 +34,6 @@ fn std::ptr::drop_in_place(_1: *mut Vec<i32>) -> () {
         _3 = <Vec<i32> as Drop>::drop(move _2) -> [return: bb5, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
                                          // mir::Constant
                                          // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-                                         // + literal: Const { ty: for<'r> fn(&'r mut Vec<i32>) {<Vec<i32> as Drop>::drop}, val: Value(<ZST>) }
+                                         // + literal: Const { ty: for<'a> fn(&'a mut Vec<i32>) {<Vec<i32> as Drop>::drop}, val: Value(<ZST>) }
     }
 }
diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp
index 10958a7727c..18e6d75b1d5 100644
--- a/src/test/pretty/issue-4264.pp
+++ b/src/test/pretty/issue-4264.pp
@@ -32,7 +32,7 @@ fn bar() ({
         ({
                 let res =
                     ((::alloc::fmt::format as
-                            for<'r> fn(Arguments<'r>) -> String {format})(((::core::fmt::Arguments::new_v1
+                            for<'a> fn(Arguments<'a>) -> String {format})(((::core::fmt::Arguments::new_v1
                                 as
                                 fn(&[&'static str], &[ArgumentV1<'_>]) -> Arguments<'_> {Arguments::<'_>::new_v1})((&([("test"
                                             as &str)] as [&str; 1]) as &[&str; 1]),
diff --git a/src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/src/lib.rs b/src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/src/lib.rs
index bac3970a4d3..d8658a0f255 100644
--- a/src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/src/lib.rs
+++ b/src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/src/lib.rs
@@ -1,8 +1,8 @@
 // Scraped example should only include line numbers for items b and c in ex.rs
-// @!has foobar/fn.f.html '//*[@class="line-numbers"]' '14'
-// @has foobar/fn.f.html '//*[@class="line-numbers"]' '15'
-// @has foobar/fn.f.html '//*[@class="line-numbers"]' '21'
-// @!has foobar/fn.f.html '//*[@class="line-numbers"]' '22'
+// @!has foobar/fn.f.html '//*[@class="src-line-numbers"]' '14'
+// @has foobar/fn.f.html '//*[@class="src-line-numbers"]' '15'
+// @has foobar/fn.f.html '//*[@class="src-line-numbers"]' '21'
+// @!has foobar/fn.f.html '//*[@class="src-line-numbers"]' '22'
 
 pub fn f() {}
 
diff --git a/src/test/rustdoc-gui/anchor-navigable.goml b/src/test/rustdoc-gui/anchor-navigable.goml
index 424c312233b..14653f0bfc7 100644
--- a/src/test/rustdoc-gui/anchor-navigable.goml
+++ b/src/test/rustdoc-gui/anchor-navigable.goml
@@ -7,5 +7,5 @@
 goto: file://|DOC_PATH|/test_docs/struct.Foo.html
 // We check that ".item-info" is bigger than its content.
 move-cursor-to: ".impl"
-assert-property: (".impl > a.anchor", {"offsetWidth": "9"})
+assert-property: (".impl > a.anchor", {"offsetWidth": "8"})
 assert-css: (".impl > a.anchor", {"left": "-8px"})
diff --git a/src/test/rustdoc-gui/basic-code.goml b/src/test/rustdoc-gui/basic-code.goml
index 27deb2c989c..79090b499c8 100644
--- a/src/test/rustdoc-gui/basic-code.goml
+++ b/src/test/rustdoc-gui/basic-code.goml
@@ -1,3 +1,3 @@
 goto: file://|DOC_PATH|/test_docs/index.html
 click: ".srclink"
-assert-count: (".line-numbers", 1)
+assert-count: (".src-line-numbers", 1)
diff --git a/src/test/rustdoc-gui/docblock-code-block-line-number.goml b/src/test/rustdoc-gui/docblock-code-block-line-number.goml
index ebfffbce715..4e1e83c0fbd 100644
--- a/src/test/rustdoc-gui/docblock-code-block-line-number.goml
+++ b/src/test/rustdoc-gui/docblock-code-block-line-number.goml
@@ -2,7 +2,7 @@
 goto: file://|DOC_PATH|/test_docs/fn.foo.html
 
 // We check that without this setting, there is no line number displayed.
-assert-false: "pre.line-number"
+assert-false: "pre.example-line-numbers"
 
 // We now set the setting to show the line numbers on code examples.
 local-storage: {"rustdoc-line-numbers": "true" }
@@ -10,16 +10,16 @@ local-storage: {"rustdoc-line-numbers": "true" }
 reload:
 
 // We wait for them to be added into the DOM by the JS...
-wait-for: "pre.line-number"
+wait-for: "pre.example-line-numbers"
 // If the test didn't fail, it means that it was found!
 // Let's now check some CSS properties...
-assert-css: ("pre.line-number", {
+assert-css: ("pre.example-line-numbers", {
     "margin": "0px",
     "padding": "13px 8px",
     "text-align": "right",
 })
 // The first code block has two lines so let's check its `<pre>` elements lists both of them.
-assert-text: ("pre.line-number", "1\n2")
+assert-text: ("pre.example-line-numbers", "1\n2")
 
 // Now, try changing the setting dynamically. We'll turn it off, using the settings menu,
 // and make sure it goes away.
@@ -32,8 +32,8 @@ assert-css: ("#settings", {"display": "block"})
 // Then, click the toggle button.
 click: "input#line-numbers + .slider"
 wait-for: 100 // wait-for-false does not exist
-assert-false: "pre.line-number"
+assert-false: "pre.example-line-numbers"
 
 // Finally, turn it on again.
 click: "input#line-numbers + .slider"
-wait-for: "pre.line-number"
+wait-for: "pre.example-line-numbers"
diff --git a/src/test/rustdoc-gui/font-weight.goml b/src/test/rustdoc-gui/font-weight.goml
index 13e8ec9fb16..d5c934551a5 100644
--- a/src/test/rustdoc-gui/font-weight.goml
+++ b/src/test/rustdoc-gui/font-weight.goml
@@ -13,7 +13,7 @@ goto: file://|DOC_PATH|/test_docs/type.SomeType.html
 assert-css: (".top-doc .docblock p", {"font-weight": "400"}, ALL)
 
 goto: file://|DOC_PATH|/test_docs/struct.Foo.html
-assert-css: (".impl-items .method", {"font-weight": "600"}, ALL)
+assert-css: (".impl-items .method > .code-header", {"font-weight": "600"}, ALL)
 
 goto: file://|DOC_PATH|/lib2/trait.Trait.html
 
@@ -41,4 +41,4 @@ assert-count: (".methods .associatedtype", 1)
 assert-css: (".methods .associatedtype", {"font-weight": "600"})
 assert-count: (".methods .constant", 1)
 assert-css: (".methods .constant", {"font-weight": "600"})
-assert-css: (".methods .method", {"font-weight": "600"})
+assert-css: (".methods .method > .code-header", {"font-weight": "600"})
diff --git a/src/test/rustdoc-gui/headers-color.goml b/src/test/rustdoc-gui/headers-color.goml
index a47a9c8a14c..4f01f1a1624 100644
--- a/src/test/rustdoc-gui/headers-color.goml
+++ b/src/test/rustdoc-gui/headers-color.goml
@@ -19,7 +19,7 @@ assert-css: (
 )
 assert-css: (
     ".impl .code-header",
-    {"color": "rgb(230, 225, 207)", "background-color": "rgb(15, 20, 25)"},
+    {"color": "rgb(230, 225, 207)", "background-color": "rgba(0, 0, 0, 0)"},
     ALL,
 )
 
@@ -58,7 +58,7 @@ assert-css: (
 )
 assert-css: (
     ".impl .code-header",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgb(53, 53, 53)"},
+    {"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"},
     ALL,
 )
 
@@ -95,7 +95,7 @@ assert-css: (
 )
 assert-css: (
     ".impl .code-header",
-    {"color": "rgb(0, 0, 0)", "background-color": "rgb(255, 255, 255)"},
+    {"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"},
     ALL,
 )
 
diff --git a/src/test/rustdoc-gui/implementors.goml b/src/test/rustdoc-gui/implementors.goml
index 666a6e1253d..2fcbee27147 100644
--- a/src/test/rustdoc-gui/implementors.goml
+++ b/src/test/rustdoc-gui/implementors.goml
@@ -8,23 +8,23 @@ assert-count: ("#implementors-list .impl", 2)
 assert: ("#implementors-list .impl:nth-child(1) > a.anchor")
 assert-attribute: ("#implementors-list .impl:nth-child(1)", {"id": "impl-Whatever-for-Struct"})
 assert-attribute: ("#implementors-list .impl:nth-child(1) > a.anchor", {"href": "#impl-Whatever-for-Struct"})
-assert: "#implementors-list .impl:nth-child(1) > .code-header.in-band"
+assert: "#implementors-list .impl:nth-child(1) > .code-header"
 
 assert: ("#implementors-list .impl:nth-child(2) > a.anchor")
 assert-attribute: ("#implementors-list .impl:nth-child(2)", {"id": "impl-Whatever-1"})
 assert-attribute: ("#implementors-list .impl:nth-child(2) > a.anchor", {"href": "#impl-Whatever-1"})
-assert: "#implementors-list .impl:nth-child(2) > .code-header.in-band"
+assert: "#implementors-list .impl:nth-child(2) > .code-header"
 
 goto: file://|DOC_PATH|/test_docs/struct.HasEmptyTraits.html
 compare-elements-position-near-false: (
     "#impl-EmptyTrait1-for-HasEmptyTraits",
     "#impl-EmptyTrait2-for-HasEmptyTraits",
-    {"y": 30},
+    {"y": 34},
 )
 compare-elements-position-near: (
     "#impl-EmptyTrait3-for-HasEmptyTraits h3",
     "#impl-EmptyTrait3-for-HasEmptyTraits .item-info",
-    {"y": 30},
+    {"y": 34},
 )
 
 // Now check that re-exports work correctly.
diff --git a/src/test/rustdoc-gui/search-result-color.goml b/src/test/rustdoc-gui/search-result-color.goml
index 5e328133e62..c4b5fdf53dd 100644
--- a/src/test/rustdoc-gui/search-result-color.goml
+++ b/src/test/rustdoc-gui/search-result-color.goml
@@ -7,7 +7,6 @@ show-text: true
 // Ayu theme
 local-storage: {
     "rustdoc-theme": "ayu",
-    "rustdoc-preferred-dark-theme": "ayu",
     "rustdoc-use-system-theme": "false",
 }
 reload:
@@ -23,16 +22,66 @@ assert-css: (
     {"color": "rgb(0, 150, 207)"},
 )
 
-// Checking the color for "keyword".
+// Checking the color of "keyword" text.
 assert-css: (
     "//*[@class='result-name']//*[text()='(keyword)']",
     {"color": "rgb(120, 135, 151)"},
 )
 
+// Checking the color of "keyword".
+assert-css: (
+    ".result-name .keyword",
+    {"color": "rgb(57, 175, 215)"},
+    ALL,
+)
+// Check the color of "struct".
+assert-css: (
+    ".result-name .struct",
+    {"color": "rgb(255, 160, 165)"},
+    ALL,
+)
+// Check the color of "associated type".
+assert-css: (
+    ".result-name .associatedtype",
+    {"color": "rgb(57, 175, 215)"},
+    ALL,
+)
+// Check the color of "type method".
+assert-css: (
+    ".result-name .tymethod",
+    {"color": "rgb(253, 214, 135)"},
+    ALL,
+)
+// Check the color of "method".
+assert-css: (
+    ".result-name .method",
+    {"color": "rgb(253, 214, 135)"},
+    ALL,
+)
+// Check the color of "struct field".
+assert-css: (
+    ".result-name .structfield",
+    {"color": "rgb(0, 150, 207)"},
+    ALL,
+)
+// Check the color of "macro".
+assert-css: (
+    ".result-name .macro",
+    {"color": "rgb(163, 122, 204)"},
+    ALL,
+)
+// Check the color of "fn".
+assert-css: (
+    ".result-name .fn",
+    {"color": "rgb(253, 214, 135)"},
+    ALL,
+)
+
 // Checking the `<a>` container.
 assert-css: (
     "//*[@class='result-name']/*[text()='test_docs::']/ancestor::a",
     {"color": "rgb(0, 150, 207)", "background-color": "rgba(0, 0, 0, 0)"},
+    ALL,
 )
 
 // Checking color and background on hover.
@@ -49,7 +98,6 @@ assert-css: (
 // Dark theme
 local-storage: {
     "rustdoc-theme": "dark",
-    "rustdoc-preferred-dark-theme": "dark",
     "rustdoc-use-system-theme": "false",
 }
 reload:
@@ -71,6 +119,55 @@ assert-css: (
     {"color": "rgb(221, 221, 221)"},
 )
 
+// Checking the color of "keyword".
+assert-css: (
+    ".result-name .keyword",
+    {"color": "rgb(210, 153, 29)"},
+    ALL,
+)
+// Check the color of "struct".
+assert-css: (
+    ".result-name .struct",
+    {"color": "rgb(45, 191, 184)"},
+    ALL,
+)
+// Check the color of "associated type".
+assert-css: (
+    ".result-name .associatedtype",
+    {"color": "rgb(210, 153, 29)"},
+    ALL,
+)
+// Check the color of "type method".
+assert-css: (
+    ".result-name .tymethod",
+    {"color": "rgb(43, 171, 99)"},
+    ALL,
+)
+// Check the color of "method".
+assert-css: (
+    ".result-name .method",
+    {"color": "rgb(43, 171, 99)"},
+    ALL,
+)
+// Check the color of "struct field".
+assert-css: (
+    ".result-name .structfield",
+    {"color": "rgb(221, 221, 221)"},
+    ALL,
+)
+// Check the color of "macro".
+assert-css: (
+    ".result-name .macro",
+    {"color": "rgb(9, 189, 0)"},
+    ALL,
+)
+// Check the color of "fn".
+assert-css: (
+    ".result-name .fn",
+    {"color": "rgb(43, 171, 99)"},
+    ALL,
+)
+
 // Checking the `<a>` container.
 assert-css: (
     "//*[@class='result-name']/*[text()='test_docs::']/ancestor::a",
@@ -109,6 +206,55 @@ assert-css: (
     {"color": "rgb(0, 0, 0)"},
 )
 
+// Checking the color of "keyword".
+assert-css: (
+    ".result-name .keyword",
+    {"color": "rgb(56, 115, 173)"},
+    ALL,
+)
+// Check the color of "struct".
+assert-css: (
+    ".result-name .struct",
+    {"color": "rgb(173, 55, 138)"},
+    ALL,
+)
+// Check the color of "associated type".
+assert-css: (
+    ".result-name .associatedtype",
+    {"color": "rgb(56, 115, 173)"},
+    ALL,
+)
+// Check the color of "type method".
+assert-css: (
+    ".result-name .tymethod",
+    {"color": "rgb(173, 124, 55)"},
+    ALL,
+)
+// Check the color of "method".
+assert-css: (
+    ".result-name .method",
+    {"color": "rgb(173, 124, 55)"},
+    ALL,
+)
+// Check the color of "struct field".
+assert-css: (
+    ".result-name .structfield",
+    {"color": "rgb(0, 0, 0)"},
+    ALL,
+)
+// Check the color of "macro".
+assert-css: (
+    ".result-name .macro",
+    {"color": "rgb(6, 128, 0)"},
+    ALL,
+)
+// Check the color of "fn".
+assert-css: (
+    ".result-name .fn",
+    {"color": "rgb(173, 124, 55)"},
+    ALL,
+)
+
 // Checking the `<a>` container.
 assert-css: (
     "//*[@class='result-name']/*[text()='test_docs::']/ancestor::a",
@@ -132,7 +278,6 @@ goto: file://|DOC_PATH|/test_docs/index.html
 // this test is running on.
 local-storage: {
     "rustdoc-theme": "dark",
-    "rustdoc-preferred-dark-theme": "dark",
     "rustdoc-use-system-theme": "false",
 }
 // If the text isn't displayed, the browser doesn't compute color style correctly...
diff --git a/src/test/rustdoc-gui/sidebar-mobile-scroll.goml b/src/test/rustdoc-gui/sidebar-mobile-scroll.goml
index dc50185f01b..9af7c636a0c 100644
--- a/src/test/rustdoc-gui/sidebar-mobile-scroll.goml
+++ b/src/test/rustdoc-gui/sidebar-mobile-scroll.goml
@@ -6,7 +6,7 @@ assert-css: (".sidebar", {"display": "block", "left": "-1000px"})
 
 // Scroll down.
 scroll-to: "//h2[@id='blanket-implementations']"
-assert-window-property: {"pageYOffset": "643"}
+assert-window-property: {"pageYOffset": "639"}
 
 // Open the sidebar menu.
 click: ".sidebar-menu-toggle"
@@ -21,11 +21,11 @@ assert-window-property: {"pageYOffset": "0"}
 // Close the sidebar menu. Make sure the scroll position gets restored.
 click: ".sidebar-menu-toggle"
 wait-for-css: (".sidebar", {"left": "-1000px"})
-assert-window-property: {"pageYOffset": "643"}
+assert-window-property: {"pageYOffset": "639"}
 
 // Now test that scrollability returns when the browser window is just resized.
 click: ".sidebar-menu-toggle"
 wait-for-css: (".sidebar", {"left": "0px"})
 assert-window-property: {"pageYOffset": "0"}
 size: (900, 600)
-assert-window-property: {"pageYOffset": "643"}
+assert-window-property: {"pageYOffset": "639"}
diff --git a/src/test/rustdoc-gui/source-code-page.goml b/src/test/rustdoc-gui/source-code-page.goml
index 581f826a3d9..5f0bb7f19c0 100644
--- a/src/test/rustdoc-gui/source-code-page.goml
+++ b/src/test/rustdoc-gui/source-code-page.goml
@@ -1,22 +1,22 @@
 // Checks that the interactions with the source code pages are working as expected.
 goto: file://|DOC_PATH|/src/test_docs/lib.rs.html
 // Check that we can click on the line number.
-click: ".line-numbers > span:nth-child(4)" // This is the span for line 4.
+click: ".src-line-numbers > span:nth-child(4)" // This is the span for line 4.
 // Ensure that the page URL was updated.
 assert-document-property: ({"URL": "lib.rs.html#4"}, ENDS_WITH)
 assert-attribute: ("//*[@id='4']", {"class": "line-highlighted"})
 // We now check that the good spans are highlighted
 goto: file://|DOC_PATH|/src/test_docs/lib.rs.html#4-6
-assert-attribute-false: (".line-numbers > span:nth-child(3)", {"class": "line-highlighted"})
-assert-attribute: (".line-numbers > span:nth-child(4)", {"class": "line-highlighted"})
-assert-attribute: (".line-numbers > span:nth-child(5)", {"class": "line-highlighted"})
-assert-attribute: (".line-numbers > span:nth-child(6)", {"class": "line-highlighted"})
-assert-attribute-false: (".line-numbers > span:nth-child(7)", {"class": "line-highlighted"})
+assert-attribute-false: (".src-line-numbers > span:nth-child(3)", {"class": "line-highlighted"})
+assert-attribute: (".src-line-numbers > span:nth-child(4)", {"class": "line-highlighted"})
+assert-attribute: (".src-line-numbers > span:nth-child(5)", {"class": "line-highlighted"})
+assert-attribute: (".src-line-numbers > span:nth-child(6)", {"class": "line-highlighted"})
+assert-attribute-false: (".src-line-numbers > span:nth-child(7)", {"class": "line-highlighted"})
 // This is to ensure that the content is correctly align with the line numbers.
 compare-elements-position: ("//*[@id='1']", ".rust > code > span", ("y"))
 
 // Assert that the line numbers text is aligned to the right.
-assert-css: (".line-numbers", {"text-align": "right"})
+assert-css: (".src-line-numbers", {"text-align": "right"})
 
 // Now let's check that clicking on something else than the line number doesn't
 // do anything (and certainly not add a `#NaN` to the URL!).
@@ -24,7 +24,7 @@ show-text: true
 goto: file://|DOC_PATH|/src/test_docs/lib.rs.html
 // We use this assert-position to know where we will click.
 assert-position: ("//*[@id='1']", {"x": 104, "y": 103})
-// We click on the left of the "1" span but still in the "line-number" `<pre>`.
+// We click on the left of the "1" span but still in the "src-line-number" `<pre>`.
 click: (103, 103)
 assert-document-property: ({"URL": "/lib.rs.html"}, ENDS_WITH)
 
diff --git a/src/test/rustdoc-gui/src-font-size.goml b/src/test/rustdoc-gui/src-font-size.goml
index 0c01e254554..ebb413b8c41 100644
--- a/src/test/rustdoc-gui/src-font-size.goml
+++ b/src/test/rustdoc-gui/src-font-size.goml
@@ -4,8 +4,8 @@
 goto: file://|DOC_PATH|/test_docs/struct.Foo.html
 show-text: true
 // Check the impl headers.
-assert-css: (".impl.has-srclink .srclink", {"font-size": "16px"}, ALL)
-assert-css: (".impl.has-srclink .code-header.in-band", {"font-size": "18px"}, ALL)
+assert-css: (".impl.has-srclink .srclink", {"font-size": "16px", "font-weight": 400}, ALL)
+assert-css: (".impl.has-srclink .code-header", {"font-size": "18px", "font-weight": 600}, ALL)
 // Check the impl items.
-assert-css: (".impl-items .has-srclink .srclink", {"font-size": "16px"}, ALL)
-assert-css: (".impl-items .has-srclink .code-header", {"font-size": "16px"}, ALL)
+assert-css: (".impl-items .has-srclink .srclink", {"font-size": "16px", "font-weight": 400}, ALL)
+assert-css: (".impl-items .has-srclink .code-header", {"font-size": "16px", "font-weight": 600}, ALL)
diff --git a/src/test/rustdoc-gui/src/lib2/lib.rs b/src/test/rustdoc-gui/src/lib2/lib.rs
index 5a151ed7b68..24aecc70d65 100644
--- a/src/test/rustdoc-gui/src/lib2/lib.rs
+++ b/src/test/rustdoc-gui/src/lib2/lib.rs
@@ -38,11 +38,14 @@ pub trait Trait {
 
     #[deprecated = "Whatever [`Foo`](#tadam)"]
     fn foo() {}
+    fn fooo();
 }
 
 impl Trait for Foo {
     type X = u32;
     const Y: u32 = 0;
+
+    fn fooo() {}
 }
 
 impl implementors::Whatever for Foo {
diff --git a/src/test/rustdoc-js-std/asrawfd.js b/src/test/rustdoc-js-std/asrawfd.js
index fd228a59099..369a34f9c6e 100644
--- a/src/test/rustdoc-js-std/asrawfd.js
+++ b/src/test/rustdoc-js-std/asrawfd.js
@@ -6,9 +6,9 @@ const EXPECTED = {
     'others': [
         // Reproduction test for https://github.com/rust-lang/rust/issues/78724
         // Validate that type alias methods get the correct path.
-        { 'path': 'std::os::unix::io::AsRawFd', 'name': 'as_raw_fd' },
-        { 'path': 'std::os::wasi::io::AsRawFd', 'name': 'as_raw_fd' },
+        { 'path': 'std::os::fd::AsRawFd', 'name': 'as_raw_fd' },
+        { 'path': 'std::os::fd::AsRawFd', 'name': 'as_raw_fd' },
         { 'path': 'std::os::linux::process::PidFd', 'name': 'as_raw_fd' },
-        { 'path': 'std::os::unix::io::RawFd', 'name': 'as_raw_fd' },
+        { 'path': 'std::os::fd::RawFd', 'name': 'as_raw_fd' },
     ],
 };
diff --git a/src/test/rustdoc-json/primitives/primitive_impls.rs b/src/test/rustdoc-json/primitives/primitive_impls.rs
new file mode 100644
index 00000000000..1fc9374065f
--- /dev/null
+++ b/src/test/rustdoc-json/primitives/primitive_impls.rs
@@ -0,0 +1,34 @@
+#![feature(no_core)]
+#![feature(rustc_attrs)]
+#![feature(rustdoc_internals)]
+#![no_core]
+#![rustc_coherence_is_core]
+
+// @set impl_i32 = "$.index[*][?(@.docs=='Only core can do this')].id"
+
+/// Only core can do this
+impl i32 {
+    // @set identity = "$.index[*][?(@.docs=='Do Nothing')].id"
+
+    /// Do Nothing
+    pub fn identity(self) -> Self {
+        self
+    }
+
+    // @is "$.index[*][?(@.docs=='Only core can do this')].inner.items[*]" $identity
+}
+
+// @set Trait = "$.index[*][?(@.name=='Trait')].id"
+pub trait Trait {}
+// @set impl_trait_for_i32 = "$.index[*][?(@.docs=='impl Trait for i32')].id"
+/// impl Trait for i32
+impl Trait for i32 {}
+
+/// i32
+#[doc(primitive = "i32")]
+mod prim_i32 {}
+
+// @set i32 = "$.index[*][?(@.docs=='i32')].id"
+// @is "$.index[*][?(@.docs=='i32')].name" '"i32"'
+// @is "$.index[*][?(@.docs=='i32')].inner.name" '"i32"'
+// @ismany "$.index[*][?(@.docs=='i32')].inner.impls[*]" $impl_i32 $impl_trait_for_i32
diff --git a/src/test/rustdoc-json/primitive_overloading.rs b/src/test/rustdoc-json/primitives/primitive_overloading.rs
index 56b35cd14c0..56b35cd14c0 100644
--- a/src/test/rustdoc-json/primitive_overloading.rs
+++ b/src/test/rustdoc-json/primitives/primitive_overloading.rs
diff --git a/src/test/rustdoc-json/primitives.rs b/src/test/rustdoc-json/primitives/primitive_type.rs
index 8024044bc05..8024044bc05 100644
--- a/src/test/rustdoc-json/primitives.rs
+++ b/src/test/rustdoc-json/primitives/primitive_type.rs
diff --git a/src/test/rustdoc-json/primitive.rs b/src/test/rustdoc-json/primitives/use_primitive.rs
index 6454dd7f51f..e2292737462 100644
--- a/src/test/rustdoc-json/primitive.rs
+++ b/src/test/rustdoc-json/primitives/use_primitive.rs
@@ -5,7 +5,7 @@
 #[doc(primitive = "usize")]
 mod usize {}
 
-// @set local_crate_id = "$.index[*][?(@.name=='primitive')].crate_id"
+// @set local_crate_id = "$.index[*][?(@.name=='use_primitive')].crate_id"
 
 // @has "$.index[*][?(@.name=='ilog10')]"
 // @!is "$.index[*][?(@.name=='ilog10')].crate_id" $local_crate_id
diff --git a/src/test/rustdoc-ui/diagnostic-width.rs b/src/test/rustdoc-ui/diagnostic-width.rs
index 61961d5ec71..290d9db775b 100644
--- a/src/test/rustdoc-ui/diagnostic-width.rs
+++ b/src/test/rustdoc-ui/diagnostic-width.rs
@@ -1,4 +1,4 @@
-// compile-flags: -Zunstable-options --diagnostic-width=10
+// compile-flags: --diagnostic-width=10
 #![deny(rustdoc::bare_urls)]
 
 /// This is a long line that contains a http://link.com
diff --git a/src/test/rustdoc-ui/z-help.stdout b/src/test/rustdoc-ui/z-help.stdout
index 749abe36419..25d5c6e4ad2 100644
--- a/src/test/rustdoc-ui/z-help.stdout
+++ b/src/test/rustdoc-ui/z-help.stdout
@@ -82,7 +82,6 @@
     -Z                           mir-opt-level=val -- MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)
     -Z                         move-size-limit=val -- the size at which the `large_assignments` lint starts to be emitted
     -Z                         mutable-noalias=val -- emit noalias metadata for mutable references (default: yes)
-    -Z                   new-llvm-pass-manager=val -- use new LLVM pass manager (default: no)
     -Z                               nll-facts=val -- dump facts from NLL analysis into side files (default: no)
     -Z                           nll-facts-dir=val -- the directory the NLL facts are dumped into (default: `nll-facts`)
     -Z                             no-analysis=val -- parse and expand the source, but run no analysis
diff --git a/src/test/rustdoc/anonymous-lifetime.rs b/src/test/rustdoc/anonymous-lifetime.rs
index f5a7d225847..390ed5a1f93 100644
--- a/src/test/rustdoc/anonymous-lifetime.rs
+++ b/src/test/rustdoc/anonymous-lifetime.rs
@@ -12,7 +12,7 @@ pub trait Stream {
 }
 
 // @has 'foo/trait.Stream.html'
-// @has - '//*[@class="code-header in-band"]' 'impl<S: ?Sized + Stream + Unpin> Stream for &mut S'
+// @has - '//*[@class="code-header"]' 'impl<S: ?Sized + Stream + Unpin> Stream for &mut S'
 impl<S: ?Sized + Stream + Unpin> Stream for &mut S {
     type Item = S::Item;
 
diff --git a/src/test/rustdoc/assoc-consts.rs b/src/test/rustdoc/assoc-consts.rs
index 97b7739b4c9..a3e10ee5555 100644
--- a/src/test/rustdoc/assoc-consts.rs
+++ b/src/test/rustdoc/assoc-consts.rs
@@ -13,7 +13,7 @@ pub trait Foo {
 pub struct Bar;
 
 impl Foo for Bar {
-    // @has assoc_consts/struct.Bar.html '//h3[@class="code-header in-band"]' 'impl Foo for Bar'
+    // @has assoc_consts/struct.Bar.html '//h3[@class="code-header"]' 'impl Foo for Bar'
     // @has - '//*[@id="associatedconstant.FOO"]' 'const FOO: usize'
     const FOO: usize = 12;
     // @has - '//*[@id="associatedconstant.FOO_NO_DEFAULT"]' 'const FOO_NO_DEFAULT: bool'
@@ -81,7 +81,7 @@ pub trait Qux {
     const QUX_DEFAULT2: u32 = 3;
 }
 
-// @has assoc_consts/struct.Bar.html '//h3[@class="code-header in-band"]' 'impl Qux for Bar'
+// @has assoc_consts/struct.Bar.html '//h3[@class="code-header"]' 'impl Qux for Bar'
 impl Qux for Bar {
     // @has - '//*[@id="associatedconstant.QUX0"]' 'const QUX0: u8'
     // @has - '//*[@class="docblock"]' "Docs for QUX0 in trait."
diff --git a/src/test/rustdoc/blanket-reexport-item.rs b/src/test/rustdoc/blanket-reexport-item.rs
index 676d656dabf..437f0001fcf 100644
--- a/src/test/rustdoc/blanket-reexport-item.rs
+++ b/src/test/rustdoc/blanket-reexport-item.rs
@@ -1,6 +1,6 @@
 #![crate_name = "foo"]
 
-// @has foo/struct.S.html '//*[@id="impl-Into%3CU%3E-for-S"]//h3[@class="code-header in-band"]' 'impl<T, U> Into<U> for T'
+// @has foo/struct.S.html '//*[@id="impl-Into%3CU%3E-for-S"]//h3[@class="code-header"]' 'impl<T, U> Into<U> for T'
 pub struct S2 {}
 mod m {
     pub struct S {}
diff --git a/src/test/rustdoc/const-generics/add-impl.rs b/src/test/rustdoc/const-generics/add-impl.rs
index 59113952345..6cbae9abebb 100644
--- a/src/test/rustdoc/const-generics/add-impl.rs
+++ b/src/test/rustdoc/const-generics/add-impl.rs
@@ -7,7 +7,7 @@ pub struct Simd<T, const WIDTH: usize> {
     inner: T,
 }
 
-// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]//h3[@class="code-header in-band"]' 'impl Add<Simd<u8, 16>> for Simd<u8, 16>'
+// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]//h3[@class="code-header"]' 'impl Add<Simd<u8, 16>> for Simd<u8, 16>'
 impl Add for Simd<u8, 16> {
     type Output = Self;
 
diff --git a/src/test/rustdoc/const-generics/const-generics-docs.rs b/src/test/rustdoc/const-generics/const-generics-docs.rs
index 87d2f29e260..5bf76e3c469 100644
--- a/src/test/rustdoc/const-generics/const-generics-docs.rs
+++ b/src/test/rustdoc/const-generics/const-generics-docs.rs
@@ -19,10 +19,10 @@ pub use extern_crate::WTrait;
 
 // @has foo/trait.Trait.html '//pre[@class="rust trait"]' \
 //      'pub trait Trait<const N: usize>'
-// @has - '//*[@id="impl-Trait%3C1%3E-for-u8"]//h3[@class="code-header in-band"]' 'impl Trait<1> for u8'
-// @has - '//*[@id="impl-Trait%3C2%3E-for-u8"]//h3[@class="code-header in-band"]' 'impl Trait<2> for u8'
-// @has - '//*[@id="impl-Trait%3C{1%20+%202}%3E-for-u8"]//h3[@class="code-header in-band"]' 'impl Trait<{1 + 2}> for u8'
-// @has - '//*[@id="impl-Trait%3CN%3E-for-%5Bu8%3B%20N%5D"]//h3[@class="code-header in-band"]' \
+// @has - '//*[@id="impl-Trait%3C1%3E-for-u8"]//h3[@class="code-header"]' 'impl Trait<1> for u8'
+// @has - '//*[@id="impl-Trait%3C2%3E-for-u8"]//h3[@class="code-header"]' 'impl Trait<2> for u8'
+// @has - '//*[@id="impl-Trait%3C{1%20+%202}%3E-for-u8"]//h3[@class="code-header"]' 'impl Trait<{1 + 2}> for u8'
+// @has - '//*[@id="impl-Trait%3CN%3E-for-%5Bu8%3B%20N%5D"]//h3[@class="code-header"]' \
 //      'impl<const N: usize> Trait<N> for [u8; N]'
 pub trait Trait<const N: usize> {}
 impl Trait<1> for u8 {}
@@ -36,7 +36,7 @@ pub struct Foo<const N: usize> where u8: Trait<N>;
 // @has foo/struct.Bar.html '//pre[@class="rust struct"]' 'pub struct Bar<T, const N: usize>(_)'
 pub struct Bar<T, const N: usize>([T; N]);
 
-// @has foo/struct.Foo.html '//*[@id="impl-Foo%3CM%3E"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Foo<M>where u8: Trait<M>'
+// @has foo/struct.Foo.html '//*[@id="impl-Foo%3CM%3E"]/h3[@class="code-header"]' 'impl<const M: usize> Foo<M>where u8: Trait<M>'
 impl<const M: usize> Foo<M> where u8: Trait<M> {
     // @has - '//*[@id="associatedconstant.FOO_ASSOC"]' 'pub const FOO_ASSOC: usize'
     pub const FOO_ASSOC: usize = M + 13;
@@ -47,7 +47,7 @@ impl<const M: usize> Foo<M> where u8: Trait<M> {
     }
 }
 
-// @has foo/struct.Bar.html '//*[@id="impl-Bar%3Cu8%2C%20M%3E"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Bar<u8, M>'
+// @has foo/struct.Bar.html '//*[@id="impl-Bar%3Cu8%2C%20M%3E"]/h3[@class="code-header"]' 'impl<const M: usize> Bar<u8, M>'
 impl<const M: usize> Bar<u8, M> {
     // @has - '//*[@id="method.hey"]' \
     //      'pub fn hey<const N: usize>(&self) -> Foo<N>where u8: Trait<N>'
diff --git a/src/test/rustdoc/const-generics/const-impl.rs b/src/test/rustdoc/const-generics/const-impl.rs
index f1181d54ac8..75ee84279be 100644
--- a/src/test/rustdoc/const-generics/const-impl.rs
+++ b/src/test/rustdoc/const-generics/const-impl.rs
@@ -9,20 +9,20 @@ pub enum Order {
 }
 
 // @has foo/struct.VSet.html '//pre[@class="rust struct"]' 'pub struct VSet<T, const ORDER: Order>'
-// @has foo/struct.VSet.html '//*[@id="impl-Send-for-VSet%3CT%2C%20ORDER%3E"]/h3[@class="code-header in-band"]' 'impl<T, const ORDER: Order> Send for VSet<T, ORDER>'
-// @has foo/struct.VSet.html '//*[@id="impl-Sync-for-VSet%3CT%2C%20ORDER%3E"]/h3[@class="code-header in-band"]' 'impl<T, const ORDER: Order> Sync for VSet<T, ORDER>'
+// @has foo/struct.VSet.html '//*[@id="impl-Send-for-VSet%3CT%2C%20ORDER%3E"]/h3[@class="code-header"]' 'impl<T, const ORDER: Order> Send for VSet<T, ORDER>'
+// @has foo/struct.VSet.html '//*[@id="impl-Sync-for-VSet%3CT%2C%20ORDER%3E"]/h3[@class="code-header"]' 'impl<T, const ORDER: Order> Sync for VSet<T, ORDER>'
 pub struct VSet<T, const ORDER: Order> {
     inner: Vec<T>,
 }
 
-// @has foo/struct.VSet.html '//*[@id="impl-VSet%3CT%2C%20{%20Order%3A%3ASorted%20}%3E"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, { Order::Sorted }>'
+// @has foo/struct.VSet.html '//*[@id="impl-VSet%3CT%2C%20{%20Order%3A%3ASorted%20}%3E"]/h3[@class="code-header"]' 'impl<T> VSet<T, { Order::Sorted }>'
 impl<T> VSet<T, { Order::Sorted }> {
     pub fn new() -> Self {
         Self { inner: Vec::new() }
     }
 }
 
-// @has foo/struct.VSet.html '//*[@id="impl-VSet%3CT%2C%20{%20Order%3A%3AUnsorted%20}%3E"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, { Order::Unsorted }>'
+// @has foo/struct.VSet.html '//*[@id="impl-VSet%3CT%2C%20{%20Order%3A%3AUnsorted%20}%3E"]/h3[@class="code-header"]' 'impl<T> VSet<T, { Order::Unsorted }>'
 impl<T> VSet<T, { Order::Unsorted }> {
     pub fn new() -> Self {
         Self { inner: Vec::new() }
@@ -31,7 +31,7 @@ impl<T> VSet<T, { Order::Unsorted }> {
 
 pub struct Escape<const S: &'static str>;
 
-// @has foo/struct.Escape.html '//*[@id="impl-Escape%3Cr#%22%3Cscript%3Ealert(%22Escape%22)%3B%3C/script%3E%22#%3E"]/h3[@class="code-header in-band"]' 'impl Escape<r#"<script>alert("Escape");</script>"#>'
+// @has foo/struct.Escape.html '//*[@id="impl-Escape%3Cr#%22%3Cscript%3Ealert(%22Escape%22)%3B%3C/script%3E%22#%3E"]/h3[@class="code-header"]' 'impl Escape<r#"<script>alert("Escape");</script>"#>'
 impl Escape<r#"<script>alert("Escape");</script>"#> {
     pub fn f() {}
 }
diff --git a/src/test/rustdoc/const-generics/lazy_normalization_consts/const-equate-pred.rs b/src/test/rustdoc/const-generics/lazy_normalization_consts/const-equate-pred.rs
index 4eac8e31e45..310e89a35c4 100644
--- a/src/test/rustdoc/const-generics/lazy_normalization_consts/const-equate-pred.rs
+++ b/src/test/rustdoc/const-generics/lazy_normalization_consts/const-equate-pred.rs
@@ -12,7 +12,7 @@ pub struct Hasher<T> {
 unsafe impl<T: Default> Send for Hasher<T> {}
 
 // @has foo/struct.Foo.html
-// @has - '//h3[@class="code-header in-band"]' 'impl Send for Foo'
+// @has - '//h3[@class="code-header"]' 'impl Send for Foo'
 pub struct Foo {
     hasher: Hasher<[u8; 3]>,
 }
diff --git a/src/test/rustdoc/duplicate_impls/issue-33054.rs b/src/test/rustdoc/duplicate_impls/issue-33054.rs
index 84c9e4ac0cd..c1f95ac91c3 100644
--- a/src/test/rustdoc/duplicate_impls/issue-33054.rs
+++ b/src/test/rustdoc/duplicate_impls/issue-33054.rs
@@ -1,12 +1,12 @@
 // ignore-tidy-linelength
 
 // @has issue_33054/impls/struct.Foo.html
-// @has - '//h3[@class="code-header in-band"]' 'impl Foo'
-// @has - '//h3[@class="code-header in-band"]' 'impl Bar for Foo'
+// @has - '//h3[@class="code-header"]' 'impl Foo'
+// @has - '//h3[@class="code-header"]' 'impl Bar for Foo'
 // @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
 // @count - '//*[@id="main-content"]/div[@id="implementations-list"]/details/summary/*[@class="impl has-srclink"]' 1
 // @has issue_33054/impls/bar/trait.Bar.html
-// @has - '//h3[@class="code-header in-band"]' 'impl Bar for Foo'
+// @has - '//h3[@class="code-header"]' 'impl Bar for Foo'
 // @count - '//*[@class="struct"]' 1
 pub mod impls;
 
diff --git a/src/test/rustdoc/empty-impl-block.rs b/src/test/rustdoc/empty-impl-block.rs
index 6a2a254f63a..95d4db06b31 100644
--- a/src/test/rustdoc/empty-impl-block.rs
+++ b/src/test/rustdoc/empty-impl-block.rs
@@ -16,5 +16,5 @@ pub struct Another;
 pub trait Bar {}
 
 // @has 'foo/struct.Another.html'
-// @has - '//h3[@class="code-header in-band"]' 'impl Bar for Another'
+// @has - '//h3[@class="code-header"]' 'impl Bar for Another'
 impl Bar for Another {}
diff --git a/src/test/rustdoc/extern-impl.rs b/src/test/rustdoc/extern-impl.rs
index f357d65df94..fd1bc214008 100644
--- a/src/test/rustdoc/extern-impl.rs
+++ b/src/test/rustdoc/extern-impl.rs
@@ -19,9 +19,9 @@ impl Foo {
 // @has foo/trait.Bar.html
 pub trait Bar {}
 
-// @has - '//h3[@class="code-header in-band"]' 'impl Bar for fn()'
+// @has - '//h3[@class="code-header"]' 'impl Bar for fn()'
 impl Bar for fn() {}
-// @has - '//h3[@class="code-header in-band"]' 'impl Bar for extern "C" fn()'
+// @has - '//h3[@class="code-header"]' 'impl Bar for extern "C" fn()'
 impl Bar for extern fn() {}
-// @has - '//h3[@class="code-header in-band"]' 'impl Bar for extern "system" fn()'
+// @has - '//h3[@class="code-header"]' 'impl Bar for extern "system" fn()'
 impl Bar for extern "system" fn() {}
diff --git a/src/test/rustdoc/fn-bound.rs b/src/test/rustdoc/fn-bound.rs
index 4c4ffddc8a6..9e060ff2026 100644
--- a/src/test/rustdoc/fn-bound.rs
+++ b/src/test/rustdoc/fn-bound.rs
@@ -11,7 +11,7 @@ pub struct ConditionalIterator<F> {
 }
 
 
-// @has 'fn_bound/struct.ConditionalIterator.html' '//h3[@class="code-header in-band"]' 'impl<F: Fn(&i32)> Iterator for ConditionalIterator<F>'
+// @has 'fn_bound/struct.ConditionalIterator.html' '//h3[@class="code-header"]' 'impl<F: Fn(&i32)> Iterator for ConditionalIterator<F>'
 impl<F: Fn(&i32)> Iterator for ConditionalIterator<F> {
     type Item = ();
 
diff --git a/src/test/rustdoc/generic-impl.rs b/src/test/rustdoc/generic-impl.rs
index c6beed70abe..6f68b157499 100644
--- a/src/test/rustdoc/generic-impl.rs
+++ b/src/test/rustdoc/generic-impl.rs
@@ -5,7 +5,7 @@ use std::fmt;
 // @!has foo/struct.Bar.html '//*[@id="impl-ToString-for-Bar"]' ''
 pub struct Bar;
 
-// @has foo/struct.Foo.html '//*[@id="impl-ToString-for-Foo"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T'
+// @has foo/struct.Foo.html '//*[@id="impl-ToString-for-Foo"]//h3[@class="code-header"]' 'impl<T> ToString for T'
 pub struct Foo;
 // @has foo/struct.Foo.html '//*[@class="sidebar-elems"]//section//a[@href="#impl-ToString-for-Foo"]' 'ToString'
 
diff --git a/src/test/rustdoc/higher-ranked-trait-bounds.rs b/src/test/rustdoc/higher-ranked-trait-bounds.rs
index 59b5b6e5797..3493ae6d2bb 100644
--- a/src/test/rustdoc/higher-ranked-trait-bounds.rs
+++ b/src/test/rustdoc/higher-ranked-trait-bounds.rs
@@ -49,7 +49,7 @@ impl<'a> Foo<'a> {
 // @has foo/trait.B.html
 pub trait B<'x> {}
 
-// @has - '//h3[@class="code-header in-band"]' "impl<'a> B<'a> for dyn for<'b> Trait<'b>"
+// @has - '//h3[@class="code-header"]' "impl<'a> B<'a> for dyn for<'b> Trait<'b>"
 impl<'a> B<'a> for dyn for<'b> Trait<'b> {}
 
 // @has foo/struct.Bar.html
diff --git a/src/test/rustdoc/impl-disambiguation.rs b/src/test/rustdoc/impl-disambiguation.rs
index d1d39ccff32..bb978dc0f3e 100644
--- a/src/test/rustdoc/impl-disambiguation.rs
+++ b/src/test/rustdoc/impl-disambiguation.rs
@@ -4,13 +4,13 @@ pub trait Foo {}
 
 pub struct Bar<T> { field: T }
 
-// @has foo/trait.Foo.html '//*[@class="item-list"]//h3[@class="code-header in-band"]' \
+// @has foo/trait.Foo.html '//*[@class="item-list"]//h3[@class="code-header"]' \
 //     "impl Foo for Bar<u8>"
 impl Foo for Bar<u8> {}
-// @has foo/trait.Foo.html '//*[@class="item-list"]//h3[@class="code-header in-band"]' \
+// @has foo/trait.Foo.html '//*[@class="item-list"]//h3[@class="code-header"]' \
 //     "impl Foo for Bar<u16>"
 impl Foo for Bar<u16> {}
-// @has foo/trait.Foo.html '//*[@class="item-list"]//h3[@class="code-header in-band"]' \
+// @has foo/trait.Foo.html '//*[@class="item-list"]//h3[@class="code-header"]' \
 //     "impl<'a> Foo for &'a Bar<u8>"
 impl<'a> Foo for &'a Bar<u8> {}
 
@@ -22,9 +22,9 @@ pub mod mod2 {
     pub enum Baz {}
 }
 
-// @has foo/trait.Foo.html '//*[@class="item-list"]//h3[@class="code-header in-band"]' \
+// @has foo/trait.Foo.html '//*[@class="item-list"]//h3[@class="code-header"]' \
 //     "impl Foo for foo::mod1::Baz"
 impl Foo for mod1::Baz {}
-// @has foo/trait.Foo.html '//*[@class="item-list"]//h3[@class="code-header in-band"]' \
+// @has foo/trait.Foo.html '//*[@class="item-list"]//h3[@class="code-header"]' \
 //     "impl<'a> Foo for &'a foo::mod2::Baz"
 impl<'a> Foo for &'a mod2::Baz {}
diff --git a/src/test/rustdoc/impl-parts.rs b/src/test/rustdoc/impl-parts.rs
index b1481e1f279..0a8c2c8d2a9 100644
--- a/src/test/rustdoc/impl-parts.rs
+++ b/src/test/rustdoc/impl-parts.rs
@@ -5,8 +5,8 @@ pub auto trait AnAutoTrait {}
 
 pub struct Foo<T> { field: T }
 
-// @has impl_parts/struct.Foo.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @has impl_parts/struct.Foo.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 //     "impl<T: Clone> !AnAutoTrait for Foo<T>where T: Sync,"
-// @has impl_parts/trait.AnAutoTrait.html '//*[@class="item-list"]//h3[@class="code-header in-band"]' \
+// @has impl_parts/trait.AnAutoTrait.html '//*[@class="item-list"]//h3[@class="code-header"]' \
 //     "impl<T: Clone> !AnAutoTrait for Foo<T>where T: Sync,"
 impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync {}
diff --git a/src/test/rustdoc/inline_cross/issue-31948-1.rs b/src/test/rustdoc/inline_cross/issue-31948-1.rs
index be8585dd16e..6e89167b3a4 100644
--- a/src/test/rustdoc/inline_cross/issue-31948-1.rs
+++ b/src/test/rustdoc/inline_cross/issue-31948-1.rs
@@ -5,22 +5,22 @@
 extern crate rustdoc_nonreachable_impls;
 
 // @has issue_31948_1/struct.Wobble.html
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Bark for'
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Woof for'
-// @!has - '//*[@class="impl"]//h3[@class="code-header in-band"]' 'Bar for'
-// @!has - '//*[@class="impl"]//h3[@class="code-header in-band"]' 'Qux for'
+// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Bark for'
+// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Woof for'
+// @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bar for'
+// @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Qux for'
 pub use rustdoc_nonreachable_impls::hidden::Wobble;
 
 // @has issue_31948_1/trait.Bark.html
-// @has - '//h3[@class="code-header in-band"]' 'for Foo'
-// @has - '//h3[@class="code-header in-band"]' 'for Wobble'
-// @!has - '//h3[@class="code-header in-band"]' 'for Wibble'
+// @has - '//h3[@class="code-header"]' 'for Foo'
+// @has - '//h3[@class="code-header"]' 'for Wobble'
+// @!has - '//h3[@class="code-header"]' 'for Wibble'
 pub use rustdoc_nonreachable_impls::Bark;
 
 // @has issue_31948_1/trait.Woof.html
-// @has - '//h3[@class="code-header in-band"]' 'for Foo'
-// @has - '//h3[@class="code-header in-band"]' 'for Wobble'
-// @!has - '//h3[@class="code-header in-band"]' 'for Wibble'
+// @has - '//h3[@class="code-header"]' 'for Foo'
+// @has - '//h3[@class="code-header"]' 'for Wobble'
+// @!has - '//h3[@class="code-header"]' 'for Wibble'
 pub use rustdoc_nonreachable_impls::Woof;
 
 // @!has issue_31948_1/trait.Bar.html
diff --git a/src/test/rustdoc/inline_cross/issue-31948-2.rs b/src/test/rustdoc/inline_cross/issue-31948-2.rs
index 7aa994f19d6..141e07656a0 100644
--- a/src/test/rustdoc/inline_cross/issue-31948-2.rs
+++ b/src/test/rustdoc/inline_cross/issue-31948-2.rs
@@ -5,15 +5,15 @@
 extern crate rustdoc_nonreachable_impls;
 
 // @has issue_31948_2/struct.Wobble.html
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Qux for'
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Bark for'
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Woof for'
-// @!has - '//*[@class="impl"]//h3[@class="code-header in-band"]' 'Bar for'
+// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Qux for'
+// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Bark for'
+// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Woof for'
+// @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bar for'
 pub use rustdoc_nonreachable_impls::hidden::Wobble;
 
 // @has issue_31948_2/trait.Qux.html
-// @has - '//h3[@class="code-header in-band"]' 'for Foo'
-// @has - '//h3[@class="code-header in-band"]' 'for Wobble'
+// @has - '//h3[@class="code-header"]' 'for Foo'
+// @has - '//h3[@class="code-header"]' 'for Wobble'
 pub use rustdoc_nonreachable_impls::hidden::Qux;
 
 // @!has issue_31948_2/trait.Bar.html
diff --git a/src/test/rustdoc/inline_cross/issue-31948.rs b/src/test/rustdoc/inline_cross/issue-31948.rs
index 7bf4110d32a..96fc6ca47e7 100644
--- a/src/test/rustdoc/inline_cross/issue-31948.rs
+++ b/src/test/rustdoc/inline_cross/issue-31948.rs
@@ -5,22 +5,22 @@
 extern crate rustdoc_nonreachable_impls;
 
 // @has issue_31948/struct.Foo.html
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Bark for'
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Woof for'
-// @!has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Bar for'
-// @!has - '//*[@class="impl"]//h3[@class="code-header in-band"]' 'Qux for'
+// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Bark for'
+// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Woof for'
+// @!has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Bar for'
+// @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Qux for'
 pub use rustdoc_nonreachable_impls::Foo;
 
 // @has issue_31948/trait.Bark.html
-// @has - '//h3[@class="code-header in-band"]' 'for Foo'
-// @!has - '//h3[@class="code-header in-band"]' 'for Wibble'
-// @!has - '//h3[@class="code-header in-band"]' 'for Wobble'
+// @has - '//h3[@class="code-header"]' 'for Foo'
+// @!has - '//h3[@class="code-header"]' 'for Wibble'
+// @!has - '//h3[@class="code-header"]' 'for Wobble'
 pub use rustdoc_nonreachable_impls::Bark;
 
 // @has issue_31948/trait.Woof.html
-// @has - '//h3[@class="code-header in-band"]' 'for Foo'
-// @!has - '//h3[@class="code-header in-band"]' 'for Wibble'
-// @!has - '//h3[@class="code-header in-band"]' 'for Wobble'
+// @has - '//h3[@class="code-header"]' 'for Foo'
+// @!has - '//h3[@class="code-header"]' 'for Wibble'
+// @!has - '//h3[@class="code-header"]' 'for Wobble'
 pub use rustdoc_nonreachable_impls::Woof;
 
 // @!has issue_31948/trait.Bar.html
diff --git a/src/test/rustdoc/inline_cross/issue-32881.rs b/src/test/rustdoc/inline_cross/issue-32881.rs
index 8052339a83b..183fd15abbe 100644
--- a/src/test/rustdoc/inline_cross/issue-32881.rs
+++ b/src/test/rustdoc/inline_cross/issue-32881.rs
@@ -5,7 +5,7 @@
 extern crate rustdoc_trait_object_impl;
 
 // @has issue_32881/trait.Bar.html
-// @has - '//h3[@class="code-header in-band"]' "impl<'a> dyn Bar"
-// @has - '//h3[@class="code-header in-band"]' "impl<'a> Debug for dyn Bar"
+// @has - '//h3[@class="code-header"]' "impl<'a> dyn Bar"
+// @has - '//h3[@class="code-header"]' "impl<'a> Debug for dyn Bar"
 
 pub use rustdoc_trait_object_impl::Bar;
diff --git a/src/test/rustdoc/inline_cross/issue-33113.rs b/src/test/rustdoc/inline_cross/issue-33113.rs
index c60859bbcea..d954707facf 100644
--- a/src/test/rustdoc/inline_cross/issue-33113.rs
+++ b/src/test/rustdoc/inline_cross/issue-33113.rs
@@ -5,6 +5,6 @@
 extern crate bar;
 
 // @has issue_33113/trait.Bar.html
-// @has - '//h3[@class="code-header in-band"]' "for &'a char"
-// @has - '//h3[@class="code-header in-band"]' "for Foo"
+// @has - '//h3[@class="code-header"]' "for &'a char"
+// @has - '//h3[@class="code-header"]' "for Foo"
 pub use bar::Bar;
diff --git a/src/test/rustdoc/inline_cross/trait-vis.rs b/src/test/rustdoc/inline_cross/trait-vis.rs
index 363c52a336e..b646babacc5 100644
--- a/src/test/rustdoc/inline_cross/trait-vis.rs
+++ b/src/test/rustdoc/inline_cross/trait-vis.rs
@@ -3,5 +3,5 @@
 extern crate inner;
 
 // @has trait_vis/struct.SomeStruct.html
-// @has - '//h3[@class="code-header in-band"]' 'impl Clone for SomeStruct'
+// @has - '//h3[@class="code-header"]' 'impl Clone for SomeStruct'
 pub use inner::SomeStruct;
diff --git a/src/test/rustdoc/inline_local/trait-vis.rs b/src/test/rustdoc/inline_local/trait-vis.rs
index e7b08088f40..19b69da1513 100644
--- a/src/test/rustdoc/inline_local/trait-vis.rs
+++ b/src/test/rustdoc/inline_local/trait-vis.rs
@@ -13,6 +13,6 @@ mod asdf {
 }
 
 // @has trait_vis/struct.SomeStruct.html
-// @has - '//h3[@class="code-header in-band"]' 'impl ThisTrait for SomeStruct'
-// @!has - '//h3[@class="code-header in-band"]' 'impl PrivateTrait for SomeStruct'
+// @has - '//h3[@class="code-header"]' 'impl ThisTrait for SomeStruct'
+// @!has - '//h3[@class="code-header"]' 'impl PrivateTrait for SomeStruct'
 pub use asdf::SomeStruct;
diff --git a/src/test/rustdoc/issue-29503.rs b/src/test/rustdoc/issue-29503.rs
index 134821e1ef3..01ae4438500 100644
--- a/src/test/rustdoc/issue-29503.rs
+++ b/src/test/rustdoc/issue-29503.rs
@@ -5,7 +5,7 @@ pub trait MyTrait {
     fn my_string(&self) -> String;
 }
 
-// @has - "//div[@id='implementors-list']//*[@id='impl-MyTrait-for-T']//h3[@class='code-header in-band']" "impl<T> MyTrait for Twhere T: Debug"
+// @has - "//div[@id='implementors-list']//*[@id='impl-MyTrait-for-T']//h3[@class='code-header']" "impl<T> MyTrait for Twhere T: Debug"
 impl<T> MyTrait for T
 where
     T: fmt::Debug,
diff --git a/src/test/rustdoc/issue-33592.rs b/src/test/rustdoc/issue-33592.rs
index 815439db9bf..7a128f0b897 100644
--- a/src/test/rustdoc/issue-33592.rs
+++ b/src/test/rustdoc/issue-33592.rs
@@ -6,8 +6,8 @@ pub struct Bar;
 
 pub struct Baz;
 
-// @has foo/trait.Foo.html '//h3[@class="code-header in-band"]' 'impl Foo<i32> for Bar'
+// @has foo/trait.Foo.html '//h3[@class="code-header"]' 'impl Foo<i32> for Bar'
 impl Foo<i32> for Bar {}
 
-// @has foo/trait.Foo.html '//h3[@class="code-header in-band"]' 'impl<T> Foo<T> for Baz'
+// @has foo/trait.Foo.html '//h3[@class="code-header"]' 'impl<T> Foo<T> for Baz'
 impl<T> Foo<T> for Baz {}
diff --git a/src/test/rustdoc/issue-46727.rs b/src/test/rustdoc/issue-46727.rs
index 00e9127a34d..8cfc4827a7f 100644
--- a/src/test/rustdoc/issue-46727.rs
+++ b/src/test/rustdoc/issue-46727.rs
@@ -3,5 +3,5 @@
 extern crate issue_46727;
 
 // @has issue_46727/trait.Foo.html
-// @has - '//h3[@class="code-header in-band"]' 'impl<T> Foo for Bar<[T; 3]>'
+// @has - '//h3[@class="code-header"]' 'impl<T> Foo for Bar<[T; 3]>'
 pub use issue_46727::{Foo, Bar};
diff --git a/src/test/rustdoc/issue-50159.rs b/src/test/rustdoc/issue-50159.rs
index 43fb705f589..04bc4f304d6 100644
--- a/src/test/rustdoc/issue-50159.rs
+++ b/src/test/rustdoc/issue-50159.rs
@@ -11,8 +11,8 @@ impl<B, C> Signal2 for B where B: Signal<Item = C> {
 }
 
 // @has issue_50159/struct.Switch.html
-// @has - '//h3[@class="code-header in-band"]' 'impl<B> Send for Switch<B>where <B as Signal>::Item: Send'
-// @has - '//h3[@class="code-header in-band"]' 'impl<B> Sync for Switch<B>where <B as Signal>::Item: Sync'
+// @has - '//h3[@class="code-header"]' 'impl<B> Send for Switch<B>where <B as Signal>::Item: Send'
+// @has - '//h3[@class="code-header"]' 'impl<B> Sync for Switch<B>where <B as Signal>::Item: Sync'
 // @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0
 // @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5
 pub struct Switch<B: Signal> {
diff --git a/src/test/rustdoc/issue-51236.rs b/src/test/rustdoc/issue-51236.rs
index aa5890a8451..1c7aa9c7eef 100644
--- a/src/test/rustdoc/issue-51236.rs
+++ b/src/test/rustdoc/issue-51236.rs
@@ -7,7 +7,7 @@ pub mod traits {
 }
 
 // @has issue_51236/struct.Owned.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 // "impl<T> Send for Owned<T>where <T as Owned<'static>>::Reader: Send"
 pub struct Owned<T> where T: for<'a> ::traits::Owned<'a> {
     marker: PhantomData<<T as ::traits::Owned<'static>>::Reader>,
diff --git a/src/test/rustdoc/issue-54705.rs b/src/test/rustdoc/issue-54705.rs
index ce0f85d25da..7b7290ab4b7 100644
--- a/src/test/rustdoc/issue-54705.rs
+++ b/src/test/rustdoc/issue-54705.rs
@@ -1,10 +1,10 @@
 pub trait ScopeHandle<'scope> {}
 
 // @has issue_54705/struct.ScopeFutureContents.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 // "impl<'scope, S> Send for ScopeFutureContents<'scope, S>where S: Sync"
 //
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 // "impl<'scope, S> Sync for ScopeFutureContents<'scope, S>where S: Sync"
 pub struct ScopeFutureContents<'scope, S>
     where S: ScopeHandle<'scope>,
diff --git a/src/test/rustdoc/issue-55321.rs b/src/test/rustdoc/issue-55321.rs
index ee2420d86d2..22a18ef90e1 100644
--- a/src/test/rustdoc/issue-55321.rs
+++ b/src/test/rustdoc/issue-55321.rs
@@ -1,9 +1,9 @@
 #![feature(negative_impls)]
 
 // @has issue_55321/struct.A.html
-// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 // "impl !Send for A"
-// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 // "impl !Sync for A"
 pub struct A();
 
@@ -11,8 +11,8 @@ impl !Send for A {}
 impl !Sync for A {}
 
 // @has issue_55321/struct.B.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 // "impl<T> !Send for B<T>"
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 // "impl<T> !Sync for B<T>"
 pub struct B<T: ?Sized>(A, Box<T>);
diff --git a/src/test/rustdoc/issue-56822.rs b/src/test/rustdoc/issue-56822.rs
index aef6ddd8d23..b4eef344b5f 100644
--- a/src/test/rustdoc/issue-56822.rs
+++ b/src/test/rustdoc/issue-56822.rs
@@ -17,7 +17,7 @@ impl<'a, T> MyTrait for Inner<'a, T> {
 }
 
 // @has issue_56822/struct.Parser.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 // "impl<'a> Send for Parser<'a>"
 pub struct Parser<'a> {
     field: <Wrapper<Inner<'a, u8>> as MyTrait>::Output
diff --git a/src/test/rustdoc/issue-60726.rs b/src/test/rustdoc/issue-60726.rs
index 167f0f039c1..fbb0f82ae39 100644
--- a/src/test/rustdoc/issue-60726.rs
+++ b/src/test/rustdoc/issue-60726.rs
@@ -26,9 +26,9 @@ where
 {}
 
 // @has issue_60726/struct.IntoIter.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 // "impl<T> !Send for IntoIter<T>"
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 // "impl<T> !Sync for IntoIter<T>"
 pub struct IntoIter<T>{
     hello:DynTrait<FooInterface<T>>,
diff --git a/src/test/rustdoc/issue-75588.rs b/src/test/rustdoc/issue-75588.rs
index ac97b94fb35..3b11059a755 100644
--- a/src/test/rustdoc/issue-75588.rs
+++ b/src/test/rustdoc/issue-75588.rs
@@ -10,8 +10,8 @@ extern crate realcore;
 extern crate real_gimli;
 
 // issue #74672
-// @!has foo/trait.Deref.html '//*[@id="impl-Deref-for-EndianSlice"]//h3[@class="code-header in-band"]' 'impl Deref for EndianSlice'
+// @!has foo/trait.Deref.html '//*[@id="impl-Deref-for-EndianSlice"]//h3[@class="code-header"]' 'impl Deref for EndianSlice'
 pub use realcore::Deref;
 
-// @has foo/trait.Join.html '//*[@id="impl-Join-for-Foo"]//h3[@class="code-header in-band"]' 'impl Join for Foo'
+// @has foo/trait.Join.html '//*[@id="impl-Join-for-Foo"]//h3[@class="code-header"]' 'impl Join for Foo'
 pub use realcore::Join;
diff --git a/src/test/rustdoc/issue-80233-normalize-auto-trait.rs b/src/test/rustdoc/issue-80233-normalize-auto-trait.rs
index 515e617b4f4..62fbc2444db 100644
--- a/src/test/rustdoc/issue-80233-normalize-auto-trait.rs
+++ b/src/test/rustdoc/issue-80233-normalize-auto-trait.rs
@@ -31,7 +31,7 @@ impl<T: Trait3> Trait3 for Vec<T> {
 pub struct Struct1 {}
 
 // @has issue_80233_normalize_auto_trait/struct.Question.html
-// @has - '//h3[@class="code-header in-band"]' 'impl<T> Send for Question<T>'
+// @has - '//h3[@class="code-header"]' 'impl<T> Send for Question<T>'
 pub struct Question<T: Trait1> {
     pub ins: <<Vec<T> as Trait3>::Type3 as Trait2>::Type2,
 }
diff --git a/src/test/rustdoc/issue-82465-asref-for-and-of-local.rs b/src/test/rustdoc/issue-82465-asref-for-and-of-local.rs
index 8999e6a889b..adf4d111a6c 100644
--- a/src/test/rustdoc/issue-82465-asref-for-and-of-local.rs
+++ b/src/test/rustdoc/issue-82465-asref-for-and-of-local.rs
@@ -1,14 +1,14 @@
 use std::convert::AsRef;
 pub struct Local;
 
-// @has issue_82465_asref_for_and_of_local/struct.Local.html '//h3[@class="code-header in-band"]' 'impl AsRef<str> for Local'
+// @has issue_82465_asref_for_and_of_local/struct.Local.html '//h3[@class="code-header"]' 'impl AsRef<str> for Local'
 impl AsRef<str> for Local {
     fn as_ref(&self) -> &str {
         todo!()
     }
 }
 
-// @has - '//h3[@class="code-header in-band"]' 'impl AsRef<Local> for str'
+// @has - '//h3[@class="code-header"]' 'impl AsRef<Local> for str'
 impl AsRef<Local> for str {
     fn as_ref(&self) -> &Local {
         todo!()
diff --git a/src/test/rustdoc/issue-98697.rs b/src/test/rustdoc/issue-98697.rs
index a8841f137fe..d50268509b2 100644
--- a/src/test/rustdoc/issue-98697.rs
+++ b/src/test/rustdoc/issue-98697.rs
@@ -12,6 +12,6 @@ extern crate issue_98697_reexport_with_anonymous_lifetime;
 // @!has issue_98697/fn.repro.html '//pre[@class="rust fn"]/code' 'for<'
 pub use issue_98697_reexport_with_anonymous_lifetime::repro;
 
-// @has issue_98697/struct.Extra.html '//div[@id="trait-implementations-list"]//h3[@class="code-header in-band"]' 'impl MyTrait<&Extra> for Extra'
-// @!has issue_98697/struct.Extra.html '//div[@id="trait-implementations-list"]//h3[@class="code-header in-band"]' 'impl<'
+// @has issue_98697/struct.Extra.html '//div[@id="trait-implementations-list"]//h3[@class="code-header"]' 'impl MyTrait<&Extra> for Extra'
+// @!has issue_98697/struct.Extra.html '//div[@id="trait-implementations-list"]//h3[@class="code-header"]' 'impl<'
 pub use issue_98697_reexport_with_anonymous_lifetime::Extra;
diff --git a/src/test/rustdoc/negative-impl.rs b/src/test/rustdoc/negative-impl.rs
index 61a23986862..af19c784d6d 100644
--- a/src/test/rustdoc/negative-impl.rs
+++ b/src/test/rustdoc/negative-impl.rs
@@ -5,10 +5,10 @@ pub struct Alpha;
 // @matches negative_impl/struct.Bravo.html '//pre' "pub struct Bravo<B>"
 pub struct Bravo<B>(B);
 
-// @matches negative_impl/struct.Alpha.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @matches negative_impl/struct.Alpha.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 // "impl !Send for Alpha"
 impl !Send for Alpha {}
 
-// @matches negative_impl/struct.Bravo.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' "\
+// @matches negative_impl/struct.Bravo.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' "\
 // impl<B> !Send for Bravo<B>"
 impl<B> !Send for Bravo<B> {}
diff --git a/src/test/rustdoc/primitive-reference.rs b/src/test/rustdoc/primitive-reference.rs
index 5c119340609..431c9aa79c7 100644
--- a/src/test/rustdoc/primitive-reference.rs
+++ b/src/test/rustdoc/primitive-reference.rs
@@ -14,7 +14,7 @@
 
 // There should be only one implementation listed.
 // @count - '//*[@class="impl has-srclink"]' 1
-// @has - '//*[@id="impl-Foo%3C%26A%3E-for-%26B"]/*[@class="code-header in-band"]' \
+// @has - '//*[@id="impl-Foo%3C%26A%3E-for-%26B"]/*[@class="code-header"]' \
 //        'impl<A, B> Foo<&A> for &B'
 #[doc(primitive = "reference")]
 /// this is a test!
diff --git a/src/test/rustdoc/primitive/primitive-generic-impl.rs b/src/test/rustdoc/primitive/primitive-generic-impl.rs
index eebb2cf5a35..7b336b39810 100644
--- a/src/test/rustdoc/primitive/primitive-generic-impl.rs
+++ b/src/test/rustdoc/primitive/primitive-generic-impl.rs
@@ -1,7 +1,7 @@
 #![feature(rustdoc_internals)]
 #![crate_name = "foo"]
 
-// @has foo/primitive.i32.html '//*[@id="impl-ToString-for-i32"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T'
+// @has foo/primitive.i32.html '//*[@id="impl-ToString-for-i32"]//h3[@class="code-header"]' 'impl<T> ToString for T'
 
 #[doc(primitive = "i32")]
 /// Some useless docs, wouhou!
diff --git a/src/test/rustdoc/recursive-deref.rs b/src/test/rustdoc/recursive-deref.rs
index 2ab9d44be6d..aa38485c445 100644
--- a/src/test/rustdoc/recursive-deref.rs
+++ b/src/test/rustdoc/recursive-deref.rs
@@ -9,7 +9,7 @@ impl C {
     pub fn c(&self) {}
 }
 
-// @has recursive_deref/struct.A.html '//h3[@class="code-header in-band"]' 'impl Deref for A'
+// @has recursive_deref/struct.A.html '//h3[@class="code-header"]' 'impl Deref for A'
 // @has '-' '//*[@class="impl-items"]//*[@id="method.c"]' 'pub fn c(&self)'
 impl Deref for A {
     type Target = B;
@@ -19,7 +19,7 @@ impl Deref for A {
     }
 }
 
-// @has recursive_deref/struct.B.html '//h3[@class="code-header in-band"]' 'impl Deref for B'
+// @has recursive_deref/struct.B.html '//h3[@class="code-header"]' 'impl Deref for B'
 // @has '-' '//*[@class="impl-items"]//*[@id="method.c"]' 'pub fn c(&self)'
 impl Deref for B {
     type Target = C;
@@ -29,7 +29,7 @@ impl Deref for B {
     }
 }
 
-// @has recursive_deref/struct.C.html '//h3[@class="code-header in-band"]' 'impl Deref for C'
+// @has recursive_deref/struct.C.html '//h3[@class="code-header"]' 'impl Deref for C'
 impl Deref for C {
     type Target = B;
 
@@ -49,7 +49,7 @@ impl G {
     pub fn g() {}
 }
 
-// @has recursive_deref/struct.D.html '//h3[@class="code-header in-band"]' 'impl Deref for D'
+// @has recursive_deref/struct.D.html '//h3[@class="code-header"]' 'impl Deref for D'
 // We also check that `G::g` method isn't rendered because there is no `self` argument.
 // @!has '-' '//*[@id="deref-methods-G"]' ''
 impl Deref for D {
@@ -60,7 +60,7 @@ impl Deref for D {
     }
 }
 
-// @has recursive_deref/struct.E.html '//h3[@class="code-header in-band"]' 'impl Deref for E'
+// @has recursive_deref/struct.E.html '//h3[@class="code-header"]' 'impl Deref for E'
 // We also check that `G::g` method isn't rendered because there is no `self` argument.
 // @!has '-' '//*[@id="deref-methods-G"]' ''
 impl Deref for E {
@@ -71,7 +71,7 @@ impl Deref for E {
     }
 }
 
-// @has recursive_deref/struct.F.html '//h3[@class="code-header in-band"]' 'impl Deref for F'
+// @has recursive_deref/struct.F.html '//h3[@class="code-header"]' 'impl Deref for F'
 // We also check that `G::g` method isn't rendered because there is no `self` argument.
 // @!has '-' '//*[@id="deref-methods-G"]' ''
 impl Deref for F {
@@ -82,7 +82,7 @@ impl Deref for F {
     }
 }
 
-// @has recursive_deref/struct.G.html '//h3[@class="code-header in-band"]' 'impl Deref for G'
+// @has recursive_deref/struct.G.html '//h3[@class="code-header"]' 'impl Deref for G'
 impl Deref for G {
     type Target = E;
 
@@ -100,7 +100,7 @@ impl I {
     pub fn i() {}
 }
 
-// @has recursive_deref/struct.H.html '//h3[@class="code-header in-band"]' 'impl Deref for H'
+// @has recursive_deref/struct.H.html '//h3[@class="code-header"]' 'impl Deref for H'
 // @!has '-' '//*[@id="deref-methods-I"]' ''
 impl Deref for H {
     type Target = I;
@@ -110,7 +110,7 @@ impl Deref for H {
     }
 }
 
-// @has recursive_deref/struct.I.html '//h3[@class="code-header in-band"]' 'impl Deref for I'
+// @has recursive_deref/struct.I.html '//h3[@class="code-header"]' 'impl Deref for I'
 impl Deref for I {
     type Target = H;
 
diff --git a/src/test/rustdoc/rfc-2632-const-trait-impl.rs b/src/test/rustdoc/rfc-2632-const-trait-impl.rs
index f3e211e3017..8bd402291aa 100644
--- a/src/test/rustdoc/rfc-2632-const-trait-impl.rs
+++ b/src/test/rustdoc/rfc-2632-const-trait-impl.rs
@@ -30,10 +30,10 @@ pub trait Tr<T> {
 }
 
 // @has - '//section[@id="impl-Tr%3CT%3E-for-T"]' ''
-// @!has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header in-band"]' '~const'
-// @has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header in-band"]/a[@class="trait"]' 'Clone'
-// @!has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header in-band"]/span[@class="where"]' '~const'
-// @has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header in-band"]/span[@class="where fmt-newline"]' ': Clone'
+// @!has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header"]' '~const'
+// @has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header"]/a[@class="trait"]' 'Clone'
+// @!has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header"]/span[@class="where"]' '~const'
+// @has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header"]/span[@class="where fmt-newline"]' ': Clone'
 impl<T: ~const Clone + ~const Destruct> const Tr<T> for T
 where
     Option<T>: ~const Clone + ~const Destruct,
diff --git a/src/test/rustdoc/safe-intrinsic.rs b/src/test/rustdoc/safe-intrinsic.rs
index d3bb8514b7e..d08abdaeb14 100644
--- a/src/test/rustdoc/safe-intrinsic.rs
+++ b/src/test/rustdoc/safe-intrinsic.rs
@@ -1,5 +1,6 @@
 #![feature(intrinsics)]
 #![feature(no_core)]
+#![feature(rustc_attrs)]
 
 #![no_core]
 #![crate_name = "foo"]
@@ -7,6 +8,7 @@
 extern "rust-intrinsic" {
     // @has 'foo/fn.abort.html'
     // @has - '//pre[@class="rust fn"]' 'pub extern "rust-intrinsic" fn abort() -> !'
+    #[rustc_safe_intrinsic]
     pub fn abort() -> !;
     // @has 'foo/fn.unreachable.html'
     // @has - '//pre[@class="rust fn"]' 'pub unsafe extern "rust-intrinsic" fn unreachable() -> !'
diff --git a/src/test/rustdoc/sidebar-links-to-foreign-impl.rs b/src/test/rustdoc/sidebar-links-to-foreign-impl.rs
index 15515039659..6712af527a3 100644
--- a/src/test/rustdoc/sidebar-links-to-foreign-impl.rs
+++ b/src/test/rustdoc/sidebar-links-to-foreign-impl.rs
@@ -6,9 +6,9 @@
 // @has - '//*[@class="sidebar-title"]/a[@href="#foreign-impls"]' 'Implementations on Foreign Types'
 // @has - '//h2[@id="foreign-impls"]' 'Implementations on Foreign Types'
 // @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo-for-u32"]' 'u32'
-// @has - '//*[@id="impl-Foo-for-u32"]//h3[@class="code-header in-band"]' 'impl Foo for u32'
+// @has - '//*[@id="impl-Foo-for-u32"]//h3[@class="code-header"]' 'impl Foo for u32'
 // @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo-for-%26%27a%20str"]' "&'a str"
-// @has - '//*[@id="impl-Foo-for-%26%27a%20str"]//h3[@class="code-header in-band"]' "impl<'a> Foo for &'a str"
+// @has - '//*[@id="impl-Foo-for-%26%27a%20str"]//h3[@class="code-header"]' "impl<'a> Foo for &'a str"
 pub trait Foo {}
 
 impl Foo for u32 {}
diff --git a/src/test/rustdoc/sized_trait.rs b/src/test/rustdoc/sized_trait.rs
index 36718ebe1a6..feef4de8d57 100644
--- a/src/test/rustdoc/sized_trait.rs
+++ b/src/test/rustdoc/sized_trait.rs
@@ -11,7 +11,7 @@ pub struct Bar {
 pub struct Foo<T: ?Sized>(T);
 
 // @has foo/struct.Unsized.html
-// @has - '//*[@id="impl-Sized-for-Unsized"]//h3[@class="code-header in-band"]' 'impl !Sized for Unsized'
+// @has - '//*[@id="impl-Sized-for-Unsized"]//h3[@class="code-header"]' 'impl !Sized for Unsized'
 pub struct Unsized {
     data: [u8],
 }
diff --git a/src/test/rustdoc/src-links-auto-impls.rs b/src/test/rustdoc/src-links-auto-impls.rs
index 313a4b11893..953563833c9 100644
--- a/src/test/rustdoc/src-links-auto-impls.rs
+++ b/src/test/rustdoc/src-links-auto-impls.rs
@@ -1,11 +1,11 @@
 #![crate_name = "foo"]
 
 // @has foo/struct.Unsized.html
-// @has - '//*[@id="impl-Sized-for-Unsized"]/h3[@class="code-header in-band"]' 'impl !Sized for Unsized'
+// @has - '//*[@id="impl-Sized-for-Unsized"]/h3[@class="code-header"]' 'impl !Sized for Unsized'
 // @!has - '//*[@id="impl-Sized-for-Unsized"]//a[@class="srclink"]' 'source'
-// @has - '//*[@id="impl-Sync-for-Unsized"]/h3[@class="code-header in-band"]' 'impl Sync for Unsized'
+// @has - '//*[@id="impl-Sync-for-Unsized"]/h3[@class="code-header"]' 'impl Sync for Unsized'
 // @!has - '//*[@id="impl-Sync-for-Unsized"]//a[@class="srclink"]' 'source'
-// @has - '//*[@id="impl-Any-for-Unsized"]/h3[@class="code-header in-band"]' 'impl<T> Any for T'
+// @has - '//*[@id="impl-Any-for-Unsized"]/h3[@class="code-header"]' 'impl<T> Any for T'
 // @has - '//*[@id="impl-Any-for-Unsized"]//a[@class="srclink rightside"]' 'source'
 pub struct Unsized {
     data: [u8],
diff --git a/src/test/rustdoc/synthetic_auto/basic.rs b/src/test/rustdoc/synthetic_auto/basic.rs
index 19138fd1ace..7c6a388653c 100644
--- a/src/test/rustdoc/synthetic_auto/basic.rs
+++ b/src/test/rustdoc/synthetic_auto/basic.rs
@@ -1,6 +1,6 @@
 // @has basic/struct.Foo.html
-// @has - '//h3[@class="code-header in-band"]' 'impl<T> Send for Foo<T>where T: Send'
-// @has - '//h3[@class="code-header in-band"]' 'impl<T> Sync for Foo<T>where T: Sync'
+// @has - '//h3[@class="code-header"]' 'impl<T> Send for Foo<T>where T: Send'
+// @has - '//h3[@class="code-header"]' 'impl<T> Sync for Foo<T>where T: Sync'
 // @count - '//*[@id="implementations-list"]//*[@class="impl has-srclink"]' 0
 // @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5
 pub struct Foo<T> {
diff --git a/src/test/rustdoc/synthetic_auto/complex.rs b/src/test/rustdoc/synthetic_auto/complex.rs
index 39f78983da2..43393c21fdd 100644
--- a/src/test/rustdoc/synthetic_auto/complex.rs
+++ b/src/test/rustdoc/synthetic_auto/complex.rs
@@ -20,7 +20,7 @@ mod foo {
 }
 
 // @has complex/struct.NotOuter.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 // "impl<'a, T, K: ?Sized> Send for Outer<'a, T, K>where K: for<'b> Fn((&'b bool, &'a u8)) \
 // -> &'b i8, T: MyTrait<'a>, <T as MyTrait<'a>>::MyItem: Copy, 'a: 'static"
 
diff --git a/src/test/rustdoc/synthetic_auto/crate-local.rs b/src/test/rustdoc/synthetic_auto/crate-local.rs
index 58b787dfafc..ed01f63f998 100644
--- a/src/test/rustdoc/synthetic_auto/crate-local.rs
+++ b/src/test/rustdoc/synthetic_auto/crate-local.rs
@@ -3,7 +3,7 @@
 pub auto trait Banana {}
 
 // @has crate_local/struct.Peach.html
-// @has - '//h3[@class="code-header in-band"]' 'impl Banana for Peach'
-// @has - '//h3[@class="code-header in-band"]' 'impl Send for Peach'
-// @has - '//h3[@class="code-header in-band"]' 'impl Sync for Peach'
+// @has - '//h3[@class="code-header"]' 'impl Banana for Peach'
+// @has - '//h3[@class="code-header"]' 'impl Send for Peach'
+// @has - '//h3[@class="code-header"]' 'impl Sync for Peach'
 pub struct Peach;
diff --git a/src/test/rustdoc/synthetic_auto/lifetimes.rs b/src/test/rustdoc/synthetic_auto/lifetimes.rs
index 0c94850e786..33170a84435 100644
--- a/src/test/rustdoc/synthetic_auto/lifetimes.rs
+++ b/src/test/rustdoc/synthetic_auto/lifetimes.rs
@@ -9,10 +9,10 @@ where
 {}
 
 // @has lifetimes/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 // "impl<'c, K> Send for Foo<'c, K>where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static"
 //
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 // "impl<'c, K> Sync for Foo<'c, K>where K: Sync"
 pub struct Foo<'c, K: 'c> {
     inner_field: Inner<'c, K>,
diff --git a/src/test/rustdoc/synthetic_auto/manual.rs b/src/test/rustdoc/synthetic_auto/manual.rs
index 35047e3e8c0..77c04ad2ad9 100644
--- a/src/test/rustdoc/synthetic_auto/manual.rs
+++ b/src/test/rustdoc/synthetic_auto/manual.rs
@@ -1,8 +1,8 @@
 // @has manual/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 // 'impl<T> Sync for Foo<T>where T: Sync'
 //
-// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 // 'impl<T> Send for Foo<T>'
 //
 // @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
diff --git a/src/test/rustdoc/synthetic_auto/negative.rs b/src/test/rustdoc/synthetic_auto/negative.rs
index 66e749ac38d..2c2c848a5e0 100644
--- a/src/test/rustdoc/synthetic_auto/negative.rs
+++ b/src/test/rustdoc/synthetic_auto/negative.rs
@@ -3,10 +3,10 @@ pub struct Inner<T: Copy> {
 }
 
 // @has negative/struct.Outer.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 // "impl<T> !Send for Outer<T>"
 //
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 // "impl<T> !Sync for Outer<T>"
 pub struct Outer<T: Copy> {
     inner_field: Inner<T>,
diff --git a/src/test/rustdoc/synthetic_auto/nested.rs b/src/test/rustdoc/synthetic_auto/nested.rs
index 09587bcc30f..423bf115ab1 100644
--- a/src/test/rustdoc/synthetic_auto/nested.rs
+++ b/src/test/rustdoc/synthetic_auto/nested.rs
@@ -9,10 +9,10 @@ where
 }
 
 // @has nested/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 // 'impl<T> Send for Foo<T>where T: Copy'
 //
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 // 'impl<T> Sync for Foo<T>where T: Sync'
 pub struct Foo<T> {
     inner_field: Inner<T>,
diff --git a/src/test/rustdoc/synthetic_auto/no-redundancy.rs b/src/test/rustdoc/synthetic_auto/no-redundancy.rs
index 41375decc8a..59f33623322 100644
--- a/src/test/rustdoc/synthetic_auto/no-redundancy.rs
+++ b/src/test/rustdoc/synthetic_auto/no-redundancy.rs
@@ -9,7 +9,7 @@ where
 }
 
 // @has no_redundancy/struct.Outer.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 // "impl<T> Send for Outer<T>where T: Send + Copy"
 pub struct Outer<T> {
     inner_field: Inner<T>,
diff --git a/src/test/rustdoc/synthetic_auto/overflow.rs b/src/test/rustdoc/synthetic_auto/overflow.rs
index c132ab6fb1b..35a487c764d 100644
--- a/src/test/rustdoc/synthetic_auto/overflow.rs
+++ b/src/test/rustdoc/synthetic_auto/overflow.rs
@@ -21,7 +21,7 @@ enum TyData<I: Interner> {
 struct VariableKind<I: Interner>(I::InternedType);
 
 // @has overflow/struct.BoundVarsCollector.html
-// @has - '//h3[@class="code-header in-band"]' "impl<'tcx> Send for BoundVarsCollector<'tcx>"
+// @has - '//h3[@class="code-header"]' "impl<'tcx> Send for BoundVarsCollector<'tcx>"
 pub struct BoundVarsCollector<'tcx> {
     val: VariableKind<RustInterner<'tcx>>
 }
diff --git a/src/test/rustdoc/synthetic_auto/project.rs b/src/test/rustdoc/synthetic_auto/project.rs
index e80b1b1dc9b..558ff2add40 100644
--- a/src/test/rustdoc/synthetic_auto/project.rs
+++ b/src/test/rustdoc/synthetic_auto/project.rs
@@ -23,10 +23,10 @@ where
 }
 
 // @has project/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 // "impl<'c, K> Send for Foo<'c, K>where K: MyTrait<MyItem = bool>, 'c: 'static"
 //
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 // "impl<'c, K> Sync for Foo<'c, K>where K: MyTrait, <K as MyTrait>::MyItem: OtherTrait, \
 // 'c: 'static,"
 pub struct Foo<'c, K: 'c> {
diff --git a/src/test/rustdoc/synthetic_auto/self-referential.rs b/src/test/rustdoc/synthetic_auto/self-referential.rs
index d15a8de7d2f..c6ae96de776 100644
--- a/src/test/rustdoc/synthetic_auto/self-referential.rs
+++ b/src/test/rustdoc/synthetic_auto/self-referential.rs
@@ -23,7 +23,7 @@ impl<T> Pattern for Wrapper<T> {
 
 
 // @has self_referential/struct.WriteAndThen.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 // "impl<P1> Send for WriteAndThen<P1>where    <P1 as Pattern>::Value: Send"
 pub struct WriteAndThen<P1>(pub P1::Value,pub <Constrain<P1, Wrapper<P1::Value>> as Pattern>::Value)
     where P1: Pattern;
diff --git a/src/test/rustdoc/synthetic_auto/static-region.rs b/src/test/rustdoc/synthetic_auto/static-region.rs
index 08e9567313e..1a76cb919c2 100644
--- a/src/test/rustdoc/synthetic_auto/static-region.rs
+++ b/src/test/rustdoc/synthetic_auto/static-region.rs
@@ -3,7 +3,7 @@ pub trait OwnedTrait<'a> {
 }
 
 // @has static_region/struct.Owned.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 // "impl<T> Send for Owned<T>where <T as OwnedTrait<'static>>::Reader: Send"
 pub struct Owned<T> where T: OwnedTrait<'static> {
     marker: <T as OwnedTrait<'static>>::Reader,
diff --git a/src/test/rustdoc/toggle-trait-fn.rs b/src/test/rustdoc/toggle-trait-fn.rs
index 65e8daeb066..e41422ce7c5 100644
--- a/src/test/rustdoc/toggle-trait-fn.rs
+++ b/src/test/rustdoc/toggle-trait-fn.rs
@@ -4,12 +4,12 @@
 // summary. Trait methods with no documentation should not be wrapped.
 //
 // @has foo/trait.Foo.html
-// @has -  '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'is_documented()'
-// @!has - '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'not_documented()'
-// @has -  '//details[@class="rustdoc-toggle"]//*[@class="docblock"]' 'is_documented is documented'
-// @has -  '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'is_documented_optional()'
-// @!has - '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'not_documented_optional()'
-// @has -  '//details[@class="rustdoc-toggle"]//*[@class="docblock"]' 'is_documented_optional is documented'
+// @has -  '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented()'
+// @!has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented()'
+// @has -  '//details[@class="rustdoc-toggle method-toggle"]//*[@class="docblock"]' 'is_documented is documented'
+// @has -  '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented_optional()'
+// @!has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented_optional()'
+// @has -  '//details[@class="rustdoc-toggle method-toggle"]//*[@class="docblock"]' 'is_documented_optional is documented'
 pub trait Foo {
     fn not_documented();
 
diff --git a/src/test/rustdoc/traits-in-bodies.rs b/src/test/rustdoc/traits-in-bodies.rs
index 6d450a625d0..a65dd7a546c 100644
--- a/src/test/rustdoc/traits-in-bodies.rs
+++ b/src/test/rustdoc/traits-in-bodies.rs
@@ -4,7 +4,7 @@
 pub struct Bounded<T: Clone>(T);
 
 // @has traits_in_bodies/struct.SomeStruct.html
-// @has - '//h3[@class="code-header in-band"]' 'impl Clone for SomeStruct'
+// @has - '//h3[@class="code-header"]' 'impl Clone for SomeStruct'
 pub struct SomeStruct;
 
 fn asdf() -> Bounded<SomeStruct> {
@@ -18,7 +18,7 @@ fn asdf() -> Bounded<SomeStruct> {
 }
 
 // @has traits_in_bodies/struct.Point.html
-// @has - '//h3[@class="code-header in-band"]' 'impl Copy for Point'
+// @has - '//h3[@class="code-header"]' 'impl Copy for Point'
 #[derive(Clone)]
 pub struct Point {
     x: i32,
@@ -31,7 +31,7 @@ const _FOO: () = {
 };
 
 // @has traits_in_bodies/struct.Inception.html
-// @has - '//h3[@class="code-header in-band"]' 'impl Clone for Inception'
+// @has - '//h3[@class="code-header"]' 'impl Clone for Inception'
 pub struct Inception;
 
 static _BAR: usize = {
diff --git a/src/test/rustdoc/typedef.rs b/src/test/rustdoc/typedef.rs
index b68ec4557ad..d5dfa948489 100644
--- a/src/test/rustdoc/typedef.rs
+++ b/src/test/rustdoc/typedef.rs
@@ -9,8 +9,8 @@ impl MyStruct {
 }
 
 // @has typedef/type.MyAlias.html
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'impl MyAlias'
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'impl MyTrait for MyAlias'
+// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'impl MyAlias'
+// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'impl MyTrait for MyAlias'
 // @hasraw - 'Alias docstring'
 // @has - '//*[@class="sidebar"]//*[@class="location"]' 'MyAlias'
 // @has - '//*[@class="sidebar"]//a[@href="#implementations"]' 'Methods'
diff --git a/src/test/rustdoc/where.rs b/src/test/rustdoc/where.rs
index 68a146bfa55..8b5bce28f5a 100644
--- a/src/test/rustdoc/where.rs
+++ b/src/test/rustdoc/where.rs
@@ -13,7 +13,7 @@ pub fn charlie<C>() where C: MyTrait {}
 
 pub struct Delta<D>(D);
 
-// @has foo/struct.Delta.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @has foo/struct.Delta.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 //          "impl<D> Delta<D>where D: MyTrait"
 impl<D> Delta<D> where D: MyTrait {
     pub fn delta() {}
@@ -43,17 +43,17 @@ pub trait TraitWhere {
     { todo!() }
 }
 
-// @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 //          "impl<E> MyTrait for Echo<E>where E: MyTrait"
-// @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header in-band"]' \
+// @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header"]' \
 //          "impl<E> MyTrait for Echo<E>where E: MyTrait"
 impl<E> MyTrait for Echo<E>where E: MyTrait {}
 
 pub enum Foxtrot<F> { Foxtrot1(F) }
 
-// @has foo/enum.Foxtrot.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
+// @has foo/enum.Foxtrot.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
 //          "impl<F> MyTrait for Foxtrot<F>where F: MyTrait"
-// @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header in-band"]' \
+// @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header"]' \
 //          "impl<F> MyTrait for Foxtrot<F>where F: MyTrait"
 impl<F> MyTrait for Foxtrot<F>where F: MyTrait {}
 
diff --git a/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs b/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs
index 03ad3ca8261..03da804bd1c 100644
--- a/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs
+++ b/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs
@@ -44,7 +44,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingAllowedAttrPass {
     ) {
         let item = match cx.tcx.hir().get(id) {
             Node::Item(item) => item,
-            _ => cx.tcx.hir().expect_item(cx.tcx.hir().get_parent_item(id)),
+            _ => cx.tcx.hir().expect_item(cx.tcx.hir().get_parent_item(id).def_id),
         };
 
         let allowed = |attr| pprust::attribute_to_string(attr).contains("allowed_attr");
diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
index 80ea9082881..3d363cae473 100644
--- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
+++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
@@ -37,10 +37,12 @@ struct HelloWarn {}
 
 #[derive(Diagnostic)]
 #[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
-//~^ ERROR `#[derive(Diagnostic)]` can only be used on structs
+//~^ ERROR unsupported type attribute for diagnostic derive enum
 enum DiagnosticOnEnum {
     Foo,
+//~^ ERROR diagnostic slug not specified
     Bar,
+//~^ ERROR diagnostic slug not specified
 }
 
 #[derive(Diagnostic)]
@@ -76,13 +78,15 @@ struct InvalidNestedStructAttr1 {}
 #[derive(Diagnostic)]
 #[diag(nonsense = "...", code = "E0123", slug = "foo")]
 //~^ ERROR `#[diag(nonsense = ...)]` is not a valid attribute
-//~^^ ERROR diagnostic slug not specified
+//~| ERROR `#[diag(slug = ...)]` is not a valid attribute
+//~| ERROR diagnostic slug not specified
 struct InvalidNestedStructAttr2 {}
 
 #[derive(Diagnostic)]
 #[diag(nonsense = 4, code = "E0123", slug = "foo")]
 //~^ ERROR `#[diag(nonsense = ...)]` is not a valid attribute
-//~^^ ERROR diagnostic slug not specified
+//~| ERROR `#[diag(slug = ...)]` is not a valid attribute
+//~| ERROR diagnostic slug not specified
 struct InvalidNestedStructAttr3 {}
 
 #[derive(Diagnostic)]
@@ -217,6 +221,7 @@ struct Suggest {
 #[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct SuggestWithoutCode {
     #[suggestion(typeck::suggestion)]
+    //~^ ERROR suggestion without `code = "..."`
     suggestion: (Span, Applicability),
 }
 
@@ -225,6 +230,7 @@ struct SuggestWithoutCode {
 struct SuggestWithBadKey {
     #[suggestion(nonsense = "bar")]
     //~^ ERROR `#[suggestion(nonsense = ...)]` is not a valid attribute
+    //~| ERROR suggestion without `code = "..."`
     suggestion: (Span, Applicability),
 }
 
@@ -233,6 +239,7 @@ struct SuggestWithBadKey {
 struct SuggestWithShorthandMsg {
     #[suggestion(msg = "bar")]
     //~^ ERROR `#[suggestion(msg = ...)]` is not a valid attribute
+    //~| ERROR suggestion without `code = "..."`
     suggestion: (Span, Applicability),
 }
 
@@ -269,16 +276,16 @@ struct SuggestWithSpanOnly {
 #[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct SuggestWithDuplicateSpanAndApplicability {
     #[suggestion(typeck::suggestion, code = "This is suggested code")]
-    //~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one `Span`
     suggestion: (Span, Span, Applicability),
+    //~^ ERROR specified multiple times
 }
 
 #[derive(Diagnostic)]
 #[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct SuggestWithDuplicateApplicabilityAndSpan {
     #[suggestion(typeck::suggestion, code = "This is suggested code")]
-    //~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one
     suggestion: (Applicability, Applicability, Span),
+    //~^ ERROR specified multiple times
 }
 
 #[derive(Diagnostic)]
@@ -294,7 +301,7 @@ struct WrongKindOfAnnotation {
 struct OptionsInErrors {
     #[label(typeck::label)]
     label: Option<Span>,
-    #[suggestion(typeck::suggestion)]
+    #[suggestion(typeck::suggestion, code = "...")]
     opt_sugg: Option<(Span, Applicability)>,
 }
 
@@ -436,7 +443,7 @@ struct ErrorWithNoteCustomWrongOrder {
 #[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ApplicabilityInBoth {
     #[suggestion(typeck::suggestion, code = "...", applicability = "maybe-incorrect")]
-    //~^ ERROR applicability cannot be set in both the field and attribute
+    //~^ ERROR specified multiple times
     suggestion: (Span, Applicability),
 }
 
@@ -507,7 +514,7 @@ struct OptUnitField {
 #[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct LabelWithTrailingPath {
     #[label(typeck::label, foo)]
-    //~^ ERROR `#[label(...)]` is not a valid attribute
+    //~^ ERROR `#[label(foo)]` is not a valid attribute
     span: Span,
 }
 
@@ -515,7 +522,7 @@ struct LabelWithTrailingPath {
 #[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct LabelWithTrailingNameValue {
     #[label(typeck::label, foo = "...")]
-    //~^ ERROR `#[label(...)]` is not a valid attribute
+    //~^ ERROR `#[label(foo = ...)]` is not a valid attribute
     span: Span,
 }
 
@@ -523,7 +530,7 @@ struct LabelWithTrailingNameValue {
 #[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct LabelWithTrailingList {
     #[label(typeck::label, foo("..."))]
-    //~^ ERROR `#[label(...)]` is not a valid attribute
+    //~^ ERROR `#[label(foo(...))]` is not a valid attribute
     span: Span,
 }
 
@@ -581,3 +588,92 @@ struct LintAttributeOnSessionDiag {}
 //~| ERROR diagnostic slug not specified
 //~| ERROR cannot find attribute `lint` in this scope
 struct LintAttributeOnLintDiag {}
+
+#[derive(Diagnostic)]
+#[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
+struct DuplicatedSuggestionCode {
+    #[suggestion(typeck::suggestion, code = "...", code = ",,,")]
+    //~^ ERROR specified multiple times
+    suggestion: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
+struct InvalidTypeInSuggestionTuple {
+    #[suggestion(typeck::suggestion, code = "...")]
+    suggestion: (Span, usize),
+    //~^ ERROR wrong types for suggestion
+}
+
+#[derive(Diagnostic)]
+#[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
+struct MissingApplicabilityInSuggestionTuple {
+    #[suggestion(typeck::suggestion, code = "...")]
+    suggestion: (Span,),
+    //~^ ERROR wrong types for suggestion
+}
+
+#[derive(Diagnostic)]
+#[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
+struct MissingCodeInSuggestion {
+    #[suggestion(typeck::suggestion)]
+    //~^ ERROR suggestion without `code = "..."`
+    suggestion: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
+#[multipart_suggestion(typeck::suggestion)]
+//~^ ERROR `#[multipart_suggestion(...)]` is not a valid attribute
+//~| ERROR cannot find attribute `multipart_suggestion` in this scope
+#[multipart_suggestion()]
+//~^ ERROR `#[multipart_suggestion(...)]` is not a valid attribute
+//~| ERROR cannot find attribute `multipart_suggestion` in this scope
+struct MultipartSuggestion {
+    #[multipart_suggestion(typeck::suggestion)]
+    //~^ ERROR `#[multipart_suggestion(...)]` is not a valid attribute
+    //~| ERROR cannot find attribute `multipart_suggestion` in this scope
+    suggestion: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
+#[suggestion(typeck::suggestion, code = "...")]
+//~^ ERROR `#[suggestion(...)]` is not a valid attribute
+struct SuggestionOnStruct {
+    #[primary_span]
+    suggestion: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
+#[label]
+//~^ ERROR `#[label]` is not a valid attribute
+struct LabelOnStruct {
+    #[primary_span]
+    suggestion: Span,
+}
+
+#[derive(Diagnostic)]
+enum ExampleEnum {
+    #[diag(typeck::ambiguous_lifetime_bound)]
+    Foo {
+        #[primary_span]
+        sp: Span,
+        #[note]
+        note_sp: Span,
+    },
+    #[diag(typeck::ambiguous_lifetime_bound)]
+    Bar {
+        #[primary_span]
+        sp: Span,
+    },
+    #[diag(typeck::ambiguous_lifetime_bound)]
+    Baz,
+}
+
+#[derive(Diagnostic)]
+#[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
+struct RawIdentDiagnosticArg {
+    pub r#type: String,
+}
diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
index c3972beb512..21a402c7b9d 100644
--- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
+++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
@@ -1,30 +1,39 @@
-error: `#[derive(Diagnostic)]` can only be used on structs
+error: unsupported type attribute for diagnostic derive enum
   --> $DIR/diagnostic-derive.rs:39:1
    |
-LL | / #[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
-LL | |
-LL | | enum DiagnosticOnEnum {
-LL | |     Foo,
-LL | |     Bar,
-LL | | }
-   | |_^
+LL | #[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: diagnostic slug not specified
+  --> $DIR/diagnostic-derive.rs:42:5
+   |
+LL |     Foo,
+   |     ^^^
+   |
+   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(typeck::example_error)]`
+
+error: diagnostic slug not specified
+  --> $DIR/diagnostic-derive.rs:44:5
+   |
+LL |     Bar,
+   |     ^^^
+   |
+   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(typeck::example_error)]`
 
 error: `#[diag = ...]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:48:1
+  --> $DIR/diagnostic-derive.rs:50:1
    |
 LL | #[diag = "E0123"]
    | ^^^^^^^^^^^^^^^^^
 
 error: `#[nonsense(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:53:1
+  --> $DIR/diagnostic-derive.rs:55:1
    |
 LL | #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: only `diag`, `help`, `note` and `warning` are valid attributes
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:53:1
+  --> $DIR/diagnostic-derive.rs:55:1
    |
 LL | / #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")]
 LL | |
@@ -36,15 +45,15 @@ LL | | struct InvalidStructAttr {}
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(typeck::example_error)]`
 
 error: `#[diag("...")]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:60:8
+  --> $DIR/diagnostic-derive.rs:62:8
    |
 LL | #[diag("E0123")]
    |        ^^^^^^^
    |
-   = help: first argument of the attribute should be the diagnostic slug
+   = help: a diagnostic slug is required as the first argument
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:60:1
+  --> $DIR/diagnostic-derive.rs:62:1
    |
 LL | / #[diag("E0123")]
 LL | |
@@ -55,15 +64,15 @@ LL | | struct InvalidLitNestedAttr {}
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(typeck::example_error)]`
 
 error: `#[diag(nonsense(...))]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:71:8
+  --> $DIR/diagnostic-derive.rs:73:8
    |
 LL | #[diag(nonsense("foo"), code = "E0123", slug = "foo")]
    |        ^^^^^^^^^^^^^^^
    |
-   = help: first argument of the attribute should be the diagnostic slug
+   = help: a diagnostic slug is required as the first argument
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:71:1
+  --> $DIR/diagnostic-derive.rs:73:1
    |
 LL | / #[diag(nonsense("foo"), code = "E0123", slug = "foo")]
 LL | |
@@ -74,45 +83,61 @@ LL | | struct InvalidNestedStructAttr1 {}
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(typeck::example_error)]`
 
 error: `#[diag(nonsense = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:77:8
+  --> $DIR/diagnostic-derive.rs:79:8
    |
 LL | #[diag(nonsense = "...", code = "E0123", slug = "foo")]
    |        ^^^^^^^^^^^^^^^^
    |
-   = help: first argument of the attribute should be the diagnostic slug
+   = help: only `code` is a valid nested attributes following the slug
+
+error: `#[diag(slug = ...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:79:42
+   |
+LL | #[diag(nonsense = "...", code = "E0123", slug = "foo")]
+   |                                          ^^^^^^^^^^^^
+   |
+   = help: only `code` is a valid nested attributes following the slug
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:77:1
+  --> $DIR/diagnostic-derive.rs:79:1
    |
 LL | / #[diag(nonsense = "...", code = "E0123", slug = "foo")]
 LL | |
 LL | |
+LL | |
 LL | | struct InvalidNestedStructAttr2 {}
    | |__________________________________^
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(typeck::example_error)]`
 
 error: `#[diag(nonsense = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:83:8
+  --> $DIR/diagnostic-derive.rs:86:8
    |
 LL | #[diag(nonsense = 4, code = "E0123", slug = "foo")]
    |        ^^^^^^^^^^^^
+
+error: `#[diag(slug = ...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:86:38
+   |
+LL | #[diag(nonsense = 4, code = "E0123", slug = "foo")]
+   |                                      ^^^^^^^^^^^^
    |
-   = help: first argument of the attribute should be the diagnostic slug
+   = help: only `code` is a valid nested attributes following the slug
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:83:1
+  --> $DIR/diagnostic-derive.rs:86:1
    |
 LL | / #[diag(nonsense = 4, code = "E0123", slug = "foo")]
 LL | |
 LL | |
+LL | |
 LL | | struct InvalidNestedStructAttr3 {}
    | |__________________________________^
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(typeck::example_error)]`
 
 error: `#[diag(slug = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:89:58
+  --> $DIR/diagnostic-derive.rs:93:58
    |
 LL | #[diag(typeck::ambiguous_lifetime_bound, code = "E0123", slug = "foo")]
    |                                                          ^^^^^^^^^^^^
@@ -120,55 +145,57 @@ LL | #[diag(typeck::ambiguous_lifetime_bound, code = "E0123", slug = "foo")]
    = help: only `code` is a valid nested attributes following the slug
 
 error: `#[suggestion = ...]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:96:5
+  --> $DIR/diagnostic-derive.rs:100:5
    |
 LL |     #[suggestion = "bar"]
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:103:1
+  --> $DIR/diagnostic-derive.rs:107:8
    |
 LL | #[diag(typeck::ambiguous_lifetime_bound, code = "E0456")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:102:1
+  --> $DIR/diagnostic-derive.rs:106:8
    |
 LL | #[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:103:49
+  --> $DIR/diagnostic-derive.rs:107:49
    |
 LL | #[diag(typeck::ambiguous_lifetime_bound, code = "E0456")]
    |                                                 ^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:102:49
+  --> $DIR/diagnostic-derive.rs:106:49
    |
 LL | #[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
    |                                                 ^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:109:65
+  --> $DIR/diagnostic-derive.rs:113:65
    |
 LL | #[diag(typeck::ambiguous_lifetime_bound, code = "E0456", code = "E0457")]
    |                                                                 ^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:109:49
+  --> $DIR/diagnostic-derive.rs:113:49
    |
 LL | #[diag(typeck::ambiguous_lifetime_bound, code = "E0456", code = "E0457")]
    |                                                 ^^^^^^^
 
 error: `#[diag(typeck::ambiguous_lifetime_bound)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:114:42
+  --> $DIR/diagnostic-derive.rs:118:42
    |
 LL | #[diag(typeck::ambiguous_lifetime_bound, typeck::ambiguous_lifetime_bound, code = "E0456")]
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: diagnostic slug must be the first argument
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:119:1
+  --> $DIR/diagnostic-derive.rs:123:1
    |
 LL | struct KindNotProvided {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -176,7 +203,7 @@ LL | struct KindNotProvided {}
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(typeck::example_error)]`
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:122:1
+  --> $DIR/diagnostic-derive.rs:126:1
    |
 LL | / #[diag(code = "E0456")]
 LL | |
@@ -186,75 +213,89 @@ LL | | struct SlugNotProvided {}
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(typeck::example_error)]`
 
 error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
-  --> $DIR/diagnostic-derive.rs:133:5
+  --> $DIR/diagnostic-derive.rs:137:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
 
 error: `#[nonsense]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:141:5
+  --> $DIR/diagnostic-derive.rs:145:5
    |
 LL |     #[nonsense]
    |     ^^^^^^^^^^^
-   |
-   = help: only `skip_arg`, `primary_span`, `label`, `note`, `help` and `subdiagnostic` are valid field attributes
 
 error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
-  --> $DIR/diagnostic-derive.rs:158:5
+  --> $DIR/diagnostic-derive.rs:162:5
    |
 LL |     #[label(typeck::label)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `name` doesn't refer to a field on this type
-  --> $DIR/diagnostic-derive.rs:166:45
+  --> $DIR/diagnostic-derive.rs:170:45
    |
 LL |     #[suggestion(typeck::suggestion, code = "{name}")]
    |                                             ^^^^^^^^
 
 error: invalid format string: expected `'}'` but string was terminated
-  --> $DIR/diagnostic-derive.rs:171:16
+  --> $DIR/diagnostic-derive.rs:175:10
    |
 LL | #[derive(Diagnostic)]
-   |           -    ^ expected `'}'` in format string
-   |           |
-   |           because of this opening brace
+   |          ^^^^^^^^^^ expected `'}'` in format string
    |
    = note: if you intended to print `{`, you can escape it using `{{`
    = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: invalid format string: unmatched `}` found
-  --> $DIR/diagnostic-derive.rs:181:15
+  --> $DIR/diagnostic-derive.rs:185:10
    |
 LL | #[derive(Diagnostic)]
-   |               ^ unmatched `}` in format string
+   |          ^^^^^^^^^^ unmatched `}` in format string
    |
    = note: if you intended to print `}`, you can escape it using `}}`
    = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
-  --> $DIR/diagnostic-derive.rs:201:5
+  --> $DIR/diagnostic-derive.rs:205:5
    |
 LL |     #[label(typeck::label)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
+error: suggestion without `code = "..."`
+  --> $DIR/diagnostic-derive.rs:223:5
+   |
+LL |     #[suggestion(typeck::suggestion)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error: `#[suggestion(nonsense = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:226:18
+  --> $DIR/diagnostic-derive.rs:231:18
    |
 LL |     #[suggestion(nonsense = "bar")]
    |                  ^^^^^^^^^^^^^^^^
    |
-   = help: only `message`, `code` and `applicability` are valid field attributes
+   = help: only `code` and `applicability` are valid nested attributes
+
+error: suggestion without `code = "..."`
+  --> $DIR/diagnostic-derive.rs:231:5
+   |
+LL |     #[suggestion(nonsense = "bar")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[suggestion(msg = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:234:18
+  --> $DIR/diagnostic-derive.rs:240:18
    |
 LL |     #[suggestion(msg = "bar")]
    |                  ^^^^^^^^^^^
    |
-   = help: only `message`, `code` and `applicability` are valid field attributes
+   = help: only `code` and `applicability` are valid nested attributes
+
+error: suggestion without `code = "..."`
+  --> $DIR/diagnostic-derive.rs:240:5
+   |
+LL |     #[suggestion(msg = "bar")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: wrong field type for suggestion
-  --> $DIR/diagnostic-derive.rs:256:5
+  --> $DIR/diagnostic-derive.rs:263:5
    |
 LL | /     #[suggestion(typeck::suggestion, code = "This is suggested code")]
 LL | |
@@ -263,60 +304,76 @@ LL | |     suggestion: Applicability,
    |
    = help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)`
 
-error: type of field annotated with `#[suggestion(...)]` contains more than one `Span`
-  --> $DIR/diagnostic-derive.rs:271:5
+error: specified multiple times
+  --> $DIR/diagnostic-derive.rs:279:24
    |
-LL | /     #[suggestion(typeck::suggestion, code = "This is suggested code")]
-LL | |
-LL | |     suggestion: (Span, Span, Applicability),
-   | |___________________________________________^
+LL |     suggestion: (Span, Span, Applicability),
+   |                        ^^^^
+   |
+note: previously specified here
+  --> $DIR/diagnostic-derive.rs:279:18
+   |
+LL |     suggestion: (Span, Span, Applicability),
+   |                  ^^^^
 
-error: type of field annotated with `#[suggestion(...)]` contains more than one Applicability
-  --> $DIR/diagnostic-derive.rs:279:5
+error: specified multiple times
+  --> $DIR/diagnostic-derive.rs:287:33
    |
-LL | /     #[suggestion(typeck::suggestion, code = "This is suggested code")]
-LL | |
-LL | |     suggestion: (Applicability, Applicability, Span),
-   | |____________________________________________________^
+LL |     suggestion: (Applicability, Applicability, Span),
+   |                                 ^^^^^^^^^^^^^
+   |
+note: previously specified here
+  --> $DIR/diagnostic-derive.rs:287:18
+   |
+LL |     suggestion: (Applicability, Applicability, Span),
+   |                  ^^^^^^^^^^^^^
 
 error: `#[label = ...]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:287:5
+  --> $DIR/diagnostic-derive.rs:294:5
    |
 LL |     #[label = "bar"]
    |     ^^^^^^^^^^^^^^^^
 
-error: applicability cannot be set in both the field and attribute
-  --> $DIR/diagnostic-derive.rs:438:52
+error: specified multiple times
+  --> $DIR/diagnostic-derive.rs:445:52
    |
 LL |     #[suggestion(typeck::suggestion, code = "...", applicability = "maybe-incorrect")]
    |                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: previously specified here
+  --> $DIR/diagnostic-derive.rs:447:24
+   |
+LL |     suggestion: (Span, Applicability),
+   |                        ^^^^^^^^^^^^^
 
 error: invalid applicability
-  --> $DIR/diagnostic-derive.rs:446:52
+  --> $DIR/diagnostic-derive.rs:453:52
    |
 LL |     #[suggestion(typeck::suggestion, code = "...", applicability = "batman")]
    |                                                    ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: `#[label(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:509:5
+error: `#[label(foo)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:516:28
    |
 LL |     #[label(typeck::label, foo)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                            ^^^
+   |
+   = help: a diagnostic slug must be the first argument to the attribute
 
-error: `#[label(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:517:5
+error: `#[label(foo = ...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:524:28
    |
 LL |     #[label(typeck::label, foo = "...")]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                            ^^^^^^^^^^^
 
-error: `#[label(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:525:5
+error: `#[label(foo(...))]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:532:28
    |
 LL |     #[label(typeck::label, foo("..."))]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                            ^^^^^^^^^^
 
 error: `#[primary_span]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:538:5
+  --> $DIR/diagnostic-derive.rs:545:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
@@ -324,15 +381,13 @@ LL |     #[primary_span]
    = help: the `primary_span` field attribute is not valid for lint diagnostics
 
 error: `#[error(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:558:1
+  --> $DIR/diagnostic-derive.rs:565:1
    |
 LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: `error` and `lint` have been replaced by `diag`
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:558:1
+  --> $DIR/diagnostic-derive.rs:565:1
    |
 LL | / #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 LL | |
@@ -344,15 +399,13 @@ LL | | struct ErrorAttribute {}
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(typeck::example_error)]`
 
 error: `#[warn_(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:565:1
+  --> $DIR/diagnostic-derive.rs:572:1
    |
 LL | #[warn_(typeck::ambiguous_lifetime_bound, code = "E0123")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: `warn_` have been replaced by `warning`
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:565:1
+  --> $DIR/diagnostic-derive.rs:572:1
    |
 LL | / #[warn_(typeck::ambiguous_lifetime_bound, code = "E0123")]
 LL | |
@@ -364,15 +417,13 @@ LL | | struct WarnAttribute {}
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(typeck::example_error)]`
 
 error: `#[lint(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:572:1
+  --> $DIR/diagnostic-derive.rs:579:1
    |
 LL | #[lint(typeck::ambiguous_lifetime_bound, code = "E0123")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: `error` and `lint` have been replaced by `diag`
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:572:1
+  --> $DIR/diagnostic-derive.rs:579:1
    |
 LL | / #[lint(typeck::ambiguous_lifetime_bound, code = "E0123")]
 LL | |
@@ -384,15 +435,13 @@ LL | | struct LintAttributeOnSessionDiag {}
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(typeck::example_error)]`
 
 error: `#[lint(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:579:1
+  --> $DIR/diagnostic-derive.rs:586:1
    |
 LL | #[lint(typeck::ambiguous_lifetime_bound, code = "E0123")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: `error` and `lint` have been replaced by `diag`
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:579:1
+  --> $DIR/diagnostic-derive.rs:586:1
    |
 LL | / #[lint(typeck::ambiguous_lifetime_bound, code = "E0123")]
 LL | |
@@ -403,50 +452,142 @@ LL | | struct LintAttributeOnLintDiag {}
    |
    = help: specify the slug as the first argument to the attribute, such as `#[diag(typeck::example_error)]`
 
+error: specified multiple times
+  --> $DIR/diagnostic-derive.rs:595:52
+   |
+LL |     #[suggestion(typeck::suggestion, code = "...", code = ",,,")]
+   |                                                    ^^^^^^^^^^^^
+   |
+note: previously specified here
+  --> $DIR/diagnostic-derive.rs:595:38
+   |
+LL |     #[suggestion(typeck::suggestion, code = "...", code = ",,,")]
+   |                                      ^^^^^^^^^^^^
+
+error: wrong types for suggestion
+  --> $DIR/diagnostic-derive.rs:604:24
+   |
+LL |     suggestion: (Span, usize),
+   |                        ^^^^^
+   |
+   = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)`
+
+error: wrong types for suggestion
+  --> $DIR/diagnostic-derive.rs:612:17
+   |
+LL |     suggestion: (Span,),
+   |                 ^^^^^^^
+   |
+   = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)`
+
+error: suggestion without `code = "..."`
+  --> $DIR/diagnostic-derive.rs:619:5
+   |
+LL |     #[suggestion(typeck::suggestion)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `#[multipart_suggestion(...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:626:1
+   |
+LL | #[multipart_suggestion(typeck::suggestion)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider creating a `Subdiagnostic` instead
+
+error: `#[multipart_suggestion(...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:629:1
+   |
+LL | #[multipart_suggestion()]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider creating a `Subdiagnostic` instead
+
+error: `#[multipart_suggestion(...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:633:5
+   |
+LL |     #[multipart_suggestion(typeck::suggestion)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider creating a `Subdiagnostic` instead
+
+error: `#[suggestion(...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:641:1
+   |
+LL | #[suggestion(typeck::suggestion, code = "...")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[label]` and `#[suggestion]` can only be applied to fields
+
+error: `#[label]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:650:1
+   |
+LL | #[label]
+   | ^^^^^^^^
+   |
+   = help: `#[label]` and `#[suggestion]` can only be applied to fields
+
 error: cannot find attribute `nonsense` in this scope
-  --> $DIR/diagnostic-derive.rs:53:3
+  --> $DIR/diagnostic-derive.rs:55:3
    |
 LL | #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")]
    |   ^^^^^^^^
 
 error: cannot find attribute `nonsense` in this scope
-  --> $DIR/diagnostic-derive.rs:141:7
+  --> $DIR/diagnostic-derive.rs:145:7
    |
 LL |     #[nonsense]
    |       ^^^^^^^^
 
 error: cannot find attribute `error` in this scope
-  --> $DIR/diagnostic-derive.rs:558:3
+  --> $DIR/diagnostic-derive.rs:565:3
    |
 LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
    |   ^^^^^
 
 error: cannot find attribute `warn_` in this scope
-  --> $DIR/diagnostic-derive.rs:565:3
+  --> $DIR/diagnostic-derive.rs:572:3
    |
 LL | #[warn_(typeck::ambiguous_lifetime_bound, code = "E0123")]
    |   ^^^^^ help: a built-in attribute with a similar name exists: `warn`
 
 error: cannot find attribute `lint` in this scope
-  --> $DIR/diagnostic-derive.rs:572:3
+  --> $DIR/diagnostic-derive.rs:579:3
    |
 LL | #[lint(typeck::ambiguous_lifetime_bound, code = "E0123")]
    |   ^^^^ help: a built-in attribute with a similar name exists: `link`
 
 error: cannot find attribute `lint` in this scope
-  --> $DIR/diagnostic-derive.rs:579:3
+  --> $DIR/diagnostic-derive.rs:586:3
    |
 LL | #[lint(typeck::ambiguous_lifetime_bound, code = "E0123")]
    |   ^^^^ help: a built-in attribute with a similar name exists: `link`
 
+error: cannot find attribute `multipart_suggestion` in this scope
+  --> $DIR/diagnostic-derive.rs:626:3
+   |
+LL | #[multipart_suggestion(typeck::suggestion)]
+   |   ^^^^^^^^^^^^^^^^^^^^
+
+error: cannot find attribute `multipart_suggestion` in this scope
+  --> $DIR/diagnostic-derive.rs:629:3
+   |
+LL | #[multipart_suggestion()]
+   |   ^^^^^^^^^^^^^^^^^^^^
+
+error: cannot find attribute `multipart_suggestion` in this scope
+  --> $DIR/diagnostic-derive.rs:633:7
+   |
+LL |     #[multipart_suggestion(typeck::suggestion)]
+   |       ^^^^^^^^^^^^^^^^^^^^
+
 error[E0425]: cannot find value `nonsense` in module `rustc_errors::fluent`
-  --> $DIR/diagnostic-derive.rs:66:8
+  --> $DIR/diagnostic-derive.rs:68:8
    |
 LL | #[diag(nonsense, code = "E0123")]
    |        ^^^^^^^^ not found in `rustc_errors::fluent`
 
 error[E0277]: the trait bound `Hello: IntoDiagnosticArg` is not satisfied
-  --> $DIR/diagnostic-derive.rs:331:10
+  --> $DIR/diagnostic-derive.rs:338:10
    |
 LL | #[derive(Diagnostic)]
    |          ^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `Hello`
@@ -459,7 +600,7 @@ LL |         arg: impl IntoDiagnosticArg,
    |                   ^^^^^^^^^^^^^^^^^ required by this bound in `DiagnosticBuilder::<'a, G>::set_arg`
    = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 55 previous errors
+error: aborting due to 74 previous errors
 
 Some errors have detailed explanations: E0277, E0425.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
index 9fbe7b1f4c8..84ee5af42de 100644
--- a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
+++ b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
@@ -52,7 +52,7 @@ struct C {
 
 #[derive(Subdiagnostic)]
 #[label]
-//~^ ERROR `#[label]` is not a valid attribute
+//~^ ERROR diagnostic slug must be first argument
 struct D {
     #[primary_span]
     span: Span,
@@ -81,6 +81,7 @@ struct F {
 #[derive(Subdiagnostic)]
 #[label(bug = "...")]
 //~^ ERROR `#[label(bug = ...)]` is not a valid attribute
+//~| ERROR diagnostic slug must be first argument
 struct G {
     #[primary_span]
     span: Span,
@@ -90,6 +91,7 @@ struct G {
 #[derive(Subdiagnostic)]
 #[label("...")]
 //~^ ERROR `#[label("...")]` is not a valid attribute
+//~| ERROR diagnostic slug must be first argument
 struct H {
     #[primary_span]
     span: Span,
@@ -99,6 +101,7 @@ struct H {
 #[derive(Subdiagnostic)]
 #[label(slug = 4)]
 //~^ ERROR `#[label(slug = ...)]` is not a valid attribute
+//~| ERROR diagnostic slug must be first argument
 struct J {
     #[primary_span]
     span: Span,
@@ -108,6 +111,7 @@ struct J {
 #[derive(Subdiagnostic)]
 #[label(slug("..."))]
 //~^ ERROR `#[label(slug(...))]` is not a valid attribute
+//~| ERROR diagnostic slug must be first argument
 struct K {
     #[primary_span]
     span: Span,
@@ -135,7 +139,7 @@ struct M {
 
 #[derive(Subdiagnostic)]
 #[label(parser::add_paren, code = "...")]
-//~^ ERROR `code` is not a valid nested attribute of a `label` attribute
+//~^ ERROR `#[label(code = ...)]` is not a valid attribute
 struct N {
     #[primary_span]
     span: Span,
@@ -144,7 +148,7 @@ struct N {
 
 #[derive(Subdiagnostic)]
 #[label(parser::add_paren, applicability = "machine-applicable")]
-//~^ ERROR `applicability` is not a valid nested attribute of a `label` attribute
+//~^ ERROR `#[label(applicability = ...)]` is not a valid attribute
 struct O {
     #[primary_span]
     span: Span,
@@ -216,6 +220,7 @@ enum T {
 enum U {
     #[label(code = "...")]
     //~^ ERROR diagnostic slug must be first argument of a `#[label(...)]` attribute
+    //~| ERROR `#[label(code = ...)]` is not a valid attribute
     A {
         #[primary_span]
         span: Span,
@@ -531,7 +536,7 @@ struct BA {
 #[derive(Subdiagnostic)]
 #[multipart_suggestion(parser::add_paren, code = "...", applicability = "machine-applicable")]
 //~^ ERROR multipart suggestion without any `#[suggestion_part(...)]` fields
-//~| ERROR `code` is not a valid nested attribute of a `multipart_suggestion` attribute
+//~| ERROR `#[multipart_suggestion(code = ...)]` is not a valid attribute
 struct BBa {
     var: String,
 }
@@ -612,10 +617,9 @@ struct BG {
 
 #[derive(Subdiagnostic)]
 #[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
-//~^ NOTE previously specified here
 struct BH {
     #[applicability]
-    //~^ ERROR specified multiple times
+    //~^ ERROR `#[applicability]` has no effect
     appl: Applicability,
     #[suggestion_part(code = "(")]
     first: Span,
@@ -629,3 +633,11 @@ struct BI {
     #[suggestion_part(code = "")]
     spans: Vec<Span>,
 }
+
+#[derive(Subdiagnostic)]
+#[label(parser::add_paren)]
+struct BJ {
+    #[primary_span]
+    span: Span,
+    r#type: String,
+}
diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
index 0a0247e8980..171b89e657d 100644
--- a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
+++ b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
@@ -8,7 +8,7 @@ LL | |     var: String,
 LL | | }
    | |_^
 
-error: `#[label]` is not a valid attribute
+error: diagnostic slug must be first argument of a `#[label(...)]` attribute
   --> $DIR/subdiagnostic-derive.rs:54:1
    |
 LL | #[label]
@@ -31,101 +31,123 @@ error: `#[label(bug = ...)]` is not a valid attribute
    |
 LL | #[label(bug = "...")]
    |         ^^^^^^^^^^^
+
+error: diagnostic slug must be first argument of a `#[label(...)]` attribute
+  --> $DIR/subdiagnostic-derive.rs:82:1
    |
-   = help: first argument of the attribute should be the diagnostic slug
+LL | #[label(bug = "...")]
+   | ^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[label("...")]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:91:9
+  --> $DIR/subdiagnostic-derive.rs:92:9
    |
 LL | #[label("...")]
    |         ^^^^^
+
+error: diagnostic slug must be first argument of a `#[label(...)]` attribute
+  --> $DIR/subdiagnostic-derive.rs:92:1
    |
-   = help: first argument of the attribute should be the diagnostic slug
+LL | #[label("...")]
+   | ^^^^^^^^^^^^^^^
 
 error: `#[label(slug = ...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:100:9
+  --> $DIR/subdiagnostic-derive.rs:102:9
    |
 LL | #[label(slug = 4)]
    |         ^^^^^^^^
+
+error: diagnostic slug must be first argument of a `#[label(...)]` attribute
+  --> $DIR/subdiagnostic-derive.rs:102:1
    |
-   = help: first argument of the attribute should be the diagnostic slug
+LL | #[label(slug = 4)]
+   | ^^^^^^^^^^^^^^^^^^
 
 error: `#[label(slug(...))]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:109:9
+  --> $DIR/subdiagnostic-derive.rs:112:9
    |
 LL | #[label(slug("..."))]
    |         ^^^^^^^^^^^
+
+error: diagnostic slug must be first argument of a `#[label(...)]` attribute
+  --> $DIR/subdiagnostic-derive.rs:112:1
    |
-   = help: first argument of the attribute should be the diagnostic slug
+LL | #[label(slug("..."))]
+   | ^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostic slug must be first argument of a `#[label(...)]` attribute
-  --> $DIR/subdiagnostic-derive.rs:128:1
+  --> $DIR/subdiagnostic-derive.rs:132:1
    |
 LL | #[label()]
    | ^^^^^^^^^^
 
-error: `code` is not a valid nested attribute of a `label` attribute
-  --> $DIR/subdiagnostic-derive.rs:137:28
+error: `#[label(code = ...)]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:141:28
    |
 LL | #[label(parser::add_paren, code = "...")]
    |                            ^^^^^^^^^^^^
 
-error: `applicability` is not a valid nested attribute of a `label` attribute
-  --> $DIR/subdiagnostic-derive.rs:146:28
+error: `#[label(applicability = ...)]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:150:28
    |
 LL | #[label(parser::add_paren, applicability = "machine-applicable")]
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: unsupported type attribute for subdiagnostic enum
-  --> $DIR/subdiagnostic-derive.rs:155:1
+  --> $DIR/subdiagnostic-derive.rs:159:1
    |
 LL | #[foo]
    | ^^^^^^
 
 error: `#[bar]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:169:5
+  --> $DIR/subdiagnostic-derive.rs:173:5
    |
 LL |     #[bar]
    |     ^^^^^^
 
 error: `#[bar = ...]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:181:5
+  --> $DIR/subdiagnostic-derive.rs:185:5
    |
 LL |     #[bar = "..."]
    |     ^^^^^^^^^^^^^^
 
 error: `#[bar = ...]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:193:5
+  --> $DIR/subdiagnostic-derive.rs:197:5
    |
 LL |     #[bar = 4]
    |     ^^^^^^^^^^
 
 error: `#[bar(...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:205:5
+  --> $DIR/subdiagnostic-derive.rs:209:5
    |
 LL |     #[bar("...")]
    |     ^^^^^^^^^^^^^
 
+error: `#[label(code = ...)]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:221:13
+   |
+LL |     #[label(code = "...")]
+   |             ^^^^^^^^^^^^
+
 error: diagnostic slug must be first argument of a `#[label(...)]` attribute
-  --> $DIR/subdiagnostic-derive.rs:217:5
+  --> $DIR/subdiagnostic-derive.rs:221:5
    |
 LL |     #[label(code = "...")]
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: subdiagnostic kind not specified
-  --> $DIR/subdiagnostic-derive.rs:234:5
+  --> $DIR/subdiagnostic-derive.rs:239:5
    |
 LL |     B {
    |     ^
 
 error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
-  --> $DIR/subdiagnostic-derive.rs:246:5
+  --> $DIR/subdiagnostic-derive.rs:251:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
 
 error: label without `#[primary_span]` field
-  --> $DIR/subdiagnostic-derive.rs:243:1
+  --> $DIR/subdiagnostic-derive.rs:248:1
    |
 LL | / #[label(parser::add_paren)]
 LL | |
@@ -137,13 +159,13 @@ LL | | }
    | |_^
 
 error: `#[applicability]` is only valid on suggestions
-  --> $DIR/subdiagnostic-derive.rs:256:5
+  --> $DIR/subdiagnostic-derive.rs:261:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
 
 error: `#[bar]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:266:5
+  --> $DIR/subdiagnostic-derive.rs:271:5
    |
 LL |     #[bar]
    |     ^^^^^^
@@ -151,13 +173,13 @@ LL |     #[bar]
    = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes
 
 error: `#[bar = ...]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:277:5
+  --> $DIR/subdiagnostic-derive.rs:282:5
    |
 LL |     #[bar = "..."]
    |     ^^^^^^^^^^^^^^
 
 error: `#[bar(...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:288:5
+  --> $DIR/subdiagnostic-derive.rs:293:5
    |
 LL |     #[bar("...")]
    |     ^^^^^^^^^^^^^
@@ -165,7 +187,7 @@ LL |     #[bar("...")]
    = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes
 
 error: unexpected unsupported untagged union
-  --> $DIR/subdiagnostic-derive.rs:304:1
+  --> $DIR/subdiagnostic-derive.rs:309:1
    |
 LL | / union AC {
 LL | |
@@ -175,7 +197,7 @@ LL | | }
    | |_^
 
 error: `#[label(parser::add_paren)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:319:28
+  --> $DIR/subdiagnostic-derive.rs:324:28
    |
 LL | #[label(parser::add_paren, parser::add_paren)]
    |                            ^^^^^^^^^^^^^^^^^
@@ -183,67 +205,67 @@ LL | #[label(parser::add_paren, parser::add_paren)]
    = help: a diagnostic slug must be the first argument to the attribute
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:332:5
+  --> $DIR/subdiagnostic-derive.rs:337:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:329:5
+  --> $DIR/subdiagnostic-derive.rs:334:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
 
 error: subdiagnostic kind not specified
-  --> $DIR/subdiagnostic-derive.rs:338:8
+  --> $DIR/subdiagnostic-derive.rs:343:8
    |
 LL | struct AG {
    |        ^^
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:375:47
+  --> $DIR/subdiagnostic-derive.rs:380:47
    |
 LL | #[suggestion(parser::add_paren, code = "...", code = "...")]
    |                                               ^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:375:33
+  --> $DIR/subdiagnostic-derive.rs:380:33
    |
 LL | #[suggestion(parser::add_paren, code = "...", code = "...")]
    |                                 ^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:393:5
+  --> $DIR/subdiagnostic-derive.rs:398:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:390:5
+  --> $DIR/subdiagnostic-derive.rs:395:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
 
 error: the `#[applicability]` attribute can only be applied to fields of type `Applicability`
-  --> $DIR/subdiagnostic-derive.rs:403:5
+  --> $DIR/subdiagnostic-derive.rs:408:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
 
 error: suggestion without `code = "..."`
-  --> $DIR/subdiagnostic-derive.rs:416:1
+  --> $DIR/subdiagnostic-derive.rs:421:1
    |
 LL | #[suggestion(parser::add_paren)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: invalid applicability
-  --> $DIR/subdiagnostic-derive.rs:426:46
+  --> $DIR/subdiagnostic-derive.rs:431:46
    |
 LL | #[suggestion(parser::add_paren, code ="...", applicability = "foo")]
    |                                              ^^^^^^^^^^^^^^^^^^^^^
 
 error: suggestion without `#[primary_span]` field
-  --> $DIR/subdiagnostic-derive.rs:444:1
+  --> $DIR/subdiagnostic-derive.rs:449:1
    |
 LL | / #[suggestion(parser::add_paren, code = "...")]
 LL | |
@@ -253,25 +275,25 @@ LL | | }
    | |_^
 
 error: unsupported type attribute for subdiagnostic enum
-  --> $DIR/subdiagnostic-derive.rs:458:1
+  --> $DIR/subdiagnostic-derive.rs:463:1
    |
 LL | #[label]
    | ^^^^^^^^
 
 error: `var` doesn't refer to a field on this type
-  --> $DIR/subdiagnostic-derive.rs:478:39
+  --> $DIR/subdiagnostic-derive.rs:483:39
    |
 LL | #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
    |                                       ^^^^^^^
 
 error: `var` doesn't refer to a field on this type
-  --> $DIR/subdiagnostic-derive.rs:497:43
+  --> $DIR/subdiagnostic-derive.rs:502:43
    |
 LL |     #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
    |                                           ^^^^^^^
 
 error: `#[suggestion_part]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:520:5
+  --> $DIR/subdiagnostic-derive.rs:525:5
    |
 LL |     #[suggestion_part]
    |     ^^^^^^^^^^^^^^^^^^
@@ -279,7 +301,7 @@ LL |     #[suggestion_part]
    = help: `#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead
 
 error: `#[suggestion_part(...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:523:5
+  --> $DIR/subdiagnostic-derive.rs:528:5
    |
 LL |     #[suggestion_part(code = "...")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -287,7 +309,7 @@ LL |     #[suggestion_part(code = "...")]
    = help: `#[suggestion_part(...)]` is only valid in multipart suggestions
 
 error: suggestion without `#[primary_span]` field
-  --> $DIR/subdiagnostic-derive.rs:517:1
+  --> $DIR/subdiagnostic-derive.rs:522:1
    |
 LL | / #[suggestion(parser::add_paren, code = "...")]
 LL | |
@@ -298,14 +320,16 @@ LL | |     var: String,
 LL | | }
    | |_^
 
-error: `code` is not a valid nested attribute of a `multipart_suggestion` attribute
-  --> $DIR/subdiagnostic-derive.rs:532:43
+error: `#[multipart_suggestion(code = ...)]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:537:43
    |
 LL | #[multipart_suggestion(parser::add_paren, code = "...", applicability = "machine-applicable")]
    |                                           ^^^^^^^^^^^^
+   |
+   = help: only `applicability` is a valid nested attributes
 
 error: multipart suggestion without any `#[suggestion_part(...)]` fields
-  --> $DIR/subdiagnostic-derive.rs:532:1
+  --> $DIR/subdiagnostic-derive.rs:537:1
    |
 LL | / #[multipart_suggestion(parser::add_paren, code = "...", applicability = "machine-applicable")]
 LL | |
@@ -316,19 +340,19 @@ LL | | }
    | |_^
 
 error: `#[suggestion_part(...)]` attribute without `code = "..."`
-  --> $DIR/subdiagnostic-derive.rs:542:5
+  --> $DIR/subdiagnostic-derive.rs:547:5
    |
 LL |     #[suggestion_part]
    |     ^^^^^^^^^^^^^^^^^^
 
 error: `#[suggestion_part(...)]` attribute without `code = "..."`
-  --> $DIR/subdiagnostic-derive.rs:550:5
+  --> $DIR/subdiagnostic-derive.rs:555:5
    |
 LL |     #[suggestion_part()]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: `#[primary_span]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:559:5
+  --> $DIR/subdiagnostic-derive.rs:564:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
@@ -336,7 +360,7 @@ LL |     #[primary_span]
    = help: multipart suggestions use one or more `#[suggestion_part]`s rather than one `#[primary_span]`
 
 error: multipart suggestion without any `#[suggestion_part(...)]` fields
-  --> $DIR/subdiagnostic-derive.rs:556:1
+  --> $DIR/subdiagnostic-derive.rs:561:1
    |
 LL | / #[multipart_suggestion(parser::add_paren)]
 LL | |
@@ -348,19 +372,19 @@ LL | | }
    | |_^
 
 error: `#[suggestion_part(...)]` attribute without `code = "..."`
-  --> $DIR/subdiagnostic-derive.rs:567:5
+  --> $DIR/subdiagnostic-derive.rs:572:5
    |
 LL |     #[suggestion_part]
    |     ^^^^^^^^^^^^^^^^^^
 
 error: `#[suggestion_part(...)]` attribute without `code = "..."`
-  --> $DIR/subdiagnostic-derive.rs:570:5
+  --> $DIR/subdiagnostic-derive.rs:575:5
    |
 LL |     #[suggestion_part()]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: `#[suggestion_part(foo = ...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:573:23
+  --> $DIR/subdiagnostic-derive.rs:578:23
    |
 LL |     #[suggestion_part(foo = "bar")]
    |                       ^^^^^^^^^^^
@@ -368,40 +392,34 @@ LL |     #[suggestion_part(foo = "bar")]
    = help: `code` is the only valid nested attribute
 
 error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
-  --> $DIR/subdiagnostic-derive.rs:576:5
+  --> $DIR/subdiagnostic-derive.rs:581:5
    |
 LL |     #[suggestion_part(code = "...")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
-  --> $DIR/subdiagnostic-derive.rs:579:5
+  --> $DIR/subdiagnostic-derive.rs:584:5
    |
 LL |     #[suggestion_part()]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:587:37
+  --> $DIR/subdiagnostic-derive.rs:592:37
    |
 LL |     #[suggestion_part(code = "...", code = ",,,")]
    |                                     ^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:587:23
+  --> $DIR/subdiagnostic-derive.rs:592:23
    |
 LL |     #[suggestion_part(code = "...", code = ",,,")]
    |                       ^^^^^^^^^^^^
 
-error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:617:5
+error: `#[applicability]` has no effect if all `#[suggestion]`/`#[multipart_suggestion]` attributes have a static `applicability = "..."`
+  --> $DIR/subdiagnostic-derive.rs:621:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
-   |
-note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:614:43
-   |
-LL | #[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
-   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: cannot find attribute `foo` in this scope
   --> $DIR/subdiagnostic-derive.rs:63:3
@@ -410,59 +428,59 @@ LL | #[foo]
    |   ^^^
 
 error: cannot find attribute `foo` in this scope
-  --> $DIR/subdiagnostic-derive.rs:155:3
+  --> $DIR/subdiagnostic-derive.rs:159:3
    |
 LL | #[foo]
    |   ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:169:7
+  --> $DIR/subdiagnostic-derive.rs:173:7
    |
 LL |     #[bar]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:181:7
+  --> $DIR/subdiagnostic-derive.rs:185:7
    |
 LL |     #[bar = "..."]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:193:7
+  --> $DIR/subdiagnostic-derive.rs:197:7
    |
 LL |     #[bar = 4]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:205:7
+  --> $DIR/subdiagnostic-derive.rs:209:7
    |
 LL |     #[bar("...")]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:266:7
+  --> $DIR/subdiagnostic-derive.rs:271:7
    |
 LL |     #[bar]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:277:7
+  --> $DIR/subdiagnostic-derive.rs:282:7
    |
 LL |     #[bar = "..."]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:288:7
+  --> $DIR/subdiagnostic-derive.rs:293:7
    |
 LL |     #[bar("...")]
    |       ^^^
 
 error[E0425]: cannot find value `slug` in module `rustc_errors::fluent`
-  --> $DIR/subdiagnostic-derive.rs:118:9
+  --> $DIR/subdiagnostic-derive.rs:122:9
    |
 LL | #[label(slug)]
    |         ^^^^ not found in `rustc_errors::fluent`
 
-error: aborting due to 63 previous errors
+error: aborting due to 68 previous errors
 
 For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/abi/stack-probes-lto.rs b/src/test/ui/abi/stack-probes-lto.rs
index 74b5e843f77..6d934538f4c 100644
--- a/src/test/ui/abi/stack-probes-lto.rs
+++ b/src/test/ui/abi/stack-probes-lto.rs
@@ -3,8 +3,6 @@
 // ignore-aarch64
 // ignore-mips
 // ignore-mips64
-// ignore-powerpc
-// ignore-s390x
 // ignore-sparc
 // ignore-sparc64
 // ignore-wasm
diff --git a/src/test/ui/abi/stack-probes.rs b/src/test/ui/abi/stack-probes.rs
index b497af7abad..e7b91644b3b 100644
--- a/src/test/ui/abi/stack-probes.rs
+++ b/src/test/ui/abi/stack-probes.rs
@@ -3,8 +3,6 @@
 // ignore-aarch64
 // ignore-mips
 // ignore-mips64
-// ignore-powerpc
-// ignore-s390x
 // ignore-sparc
 // ignore-sparc64
 // ignore-wasm
@@ -27,8 +25,9 @@ fn main() {
     let args = env::args().skip(1).collect::<Vec<_>>();
     if args.len() > 0 {
         match &args[0][..] {
-            "main-thread" => recurse(&MaybeUninit::uninit()),
-            "child-thread" => thread::spawn(|| recurse(&MaybeUninit::uninit())).join().unwrap(),
+            "main-recurse" => overflow_recurse(),
+            "child-recurse" => thread::spawn(overflow_recurse).join().unwrap(),
+            "child-frame" => overflow_frame(),
             _ => panic!(),
         }
         return;
@@ -41,9 +40,10 @@ fn main() {
     // that we report stack overflow on the main thread, see #43052 for some
     // details
     if cfg!(not(target_os = "linux")) {
-        assert_overflow(Command::new(&me).arg("main-thread"));
+        assert_overflow(Command::new(&me).arg("main-recurse"));
     }
-    assert_overflow(Command::new(&me).arg("child-thread"));
+    assert_overflow(Command::new(&me).arg("child-recurse"));
+    assert_overflow(Command::new(&me).arg("child-frame"));
 }
 
 #[allow(unconditional_recursion)]
@@ -55,6 +55,23 @@ fn recurse(array: &MaybeUninit<[u64; 1024]>) {
     recurse(&local);
 }
 
+#[inline(never)]
+fn overflow_recurse() {
+    recurse(&MaybeUninit::uninit());
+}
+
+fn overflow_frame() {
+    // By using a 1MiB stack frame with only 512KiB stack, we'll jump over any
+    // guard page, even with 64K pages -- but stack probes should catch it.
+    const STACK_SIZE: usize = 512 * 1024;
+    thread::Builder::new().stack_size(STACK_SIZE).spawn(|| {
+        let local: MaybeUninit<[u8; 2 * STACK_SIZE]> = MaybeUninit::uninit();
+        unsafe {
+            black_box(local.as_ptr() as u64);
+        }
+    }).unwrap().join().unwrap();
+}
+
 fn assert_overflow(cmd: &mut Command) {
     let output = cmd.output().unwrap();
     assert!(!output.status.success());
diff --git a/src/test/ui/anonymous-higher-ranked-lifetime.stderr b/src/test/ui/anonymous-higher-ranked-lifetime.stderr
index 1a0a5fdf4eb..bf5f642ca82 100644
--- a/src/test/ui/anonymous-higher-ranked-lifetime.stderr
+++ b/src/test/ui/anonymous-higher-ranked-lifetime.stderr
@@ -6,7 +6,7 @@ LL |     f1(|_: (), _: ()| {});
    |     |
    |     expected due to this
    |
-   = note: expected closure signature `for<'r, 's> fn(&'r (), &'s ()) -> _`
+   = note: expected closure signature `for<'a, 'b> fn(&'a (), &'b ()) -> _`
               found closure signature `fn((), ()) -> _`
 note: required by a bound in `f1`
   --> $DIR/anonymous-higher-ranked-lifetime.rs:16:25
@@ -22,7 +22,7 @@ LL |     f2(|_: (), _: ()| {});
    |     |
    |     expected due to this
    |
-   = note: expected closure signature `for<'a, 'r> fn(&'a (), &'r ()) -> _`
+   = note: expected closure signature `for<'a, 'b> fn(&'a (), &'b ()) -> _`
               found closure signature `fn((), ()) -> _`
 note: required by a bound in `f2`
   --> $DIR/anonymous-higher-ranked-lifetime.rs:17:25
@@ -38,7 +38,7 @@ LL |     f3(|_: (), _: ()| {});
    |     |
    |     expected due to this
    |
-   = note: expected closure signature `for<'r> fn(&(), &'r ()) -> _`
+   = note: expected closure signature `for<'a> fn(&(), &'a ()) -> _`
               found closure signature `fn((), ()) -> _`
 note: required by a bound in `f3`
   --> $DIR/anonymous-higher-ranked-lifetime.rs:18:29
@@ -54,7 +54,7 @@ LL |     f4(|_: (), _: ()| {});
    |     |
    |     expected due to this
    |
-   = note: expected closure signature `for<'r, 's> fn(&'s (), &'r ()) -> _`
+   = note: expected closure signature `for<'r, 'a> fn(&'a (), &'r ()) -> _`
               found closure signature `fn((), ()) -> _`
 note: required by a bound in `f4`
   --> $DIR/anonymous-higher-ranked-lifetime.rs:19:25
@@ -86,7 +86,7 @@ LL |     g1(|_: (), _: ()| {});
    |     |
    |     expected due to this
    |
-   = note: expected closure signature `for<'r> fn(&'r (), Box<(dyn for<'r> Fn(&'r ()) + 'static)>) -> _`
+   = note: expected closure signature `for<'a> fn(&'a (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>) -> _`
               found closure signature `fn((), ()) -> _`
 note: required by a bound in `g1`
   --> $DIR/anonymous-higher-ranked-lifetime.rs:23:25
@@ -102,7 +102,7 @@ LL |     g2(|_: (), _: ()| {});
    |     |
    |     expected due to this
    |
-   = note: expected closure signature `for<'r> fn(&'r (), for<'r> fn(&'r ())) -> _`
+   = note: expected closure signature `for<'a> fn(&'a (), for<'a> fn(&'a ())) -> _`
               found closure signature `fn((), ()) -> _`
 note: required by a bound in `g2`
   --> $DIR/anonymous-higher-ranked-lifetime.rs:24:25
@@ -118,7 +118,7 @@ LL |     g3(|_: (), _: ()| {});
    |     |
    |     expected due to this
    |
-   = note: expected closure signature `for<'s> fn(&'s (), Box<(dyn for<'r> Fn(&'r ()) + 'static)>) -> _`
+   = note: expected closure signature `for<'s> fn(&'s (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>) -> _`
               found closure signature `fn((), ()) -> _`
 note: required by a bound in `g3`
   --> $DIR/anonymous-higher-ranked-lifetime.rs:25:25
@@ -134,7 +134,7 @@ LL |     g4(|_: (), _: ()| {});
    |     |
    |     expected due to this
    |
-   = note: expected closure signature `for<'s> fn(&'s (), for<'r> fn(&'r ())) -> _`
+   = note: expected closure signature `for<'a> fn(&'a (), for<'r> fn(&'r ())) -> _`
               found closure signature `fn((), ()) -> _`
 note: required by a bound in `g4`
   --> $DIR/anonymous-higher-ranked-lifetime.rs:26:25
@@ -150,7 +150,7 @@ LL |     h1(|_: (), _: (), _: (), _: ()| {});
    |     |
    |     expected due to this
    |
-   = note: expected closure signature `for<'r, 's> fn(&'r (), Box<(dyn for<'r> Fn(&'r ()) + 'static)>, &'s (), for<'r, 's> fn(&'r (), &'s ())) -> _`
+   = note: expected closure signature `for<'a, 'b> fn(&'a (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>, &'b (), for<'a, 'b> fn(&'a (), &'b ())) -> _`
               found closure signature `fn((), (), (), ()) -> _`
 note: required by a bound in `h1`
   --> $DIR/anonymous-higher-ranked-lifetime.rs:29:25
@@ -166,7 +166,7 @@ LL |     h2(|_: (), _: (), _: (), _: ()| {});
    |     |
    |     expected due to this
    |
-   = note: expected closure signature `for<'t0, 'r> fn(&'r (), Box<(dyn for<'r> Fn(&'r ()) + 'static)>, &'t0 (), for<'r, 's> fn(&'r (), &'s ())) -> _`
+   = note: expected closure signature `for<'t0, 'a> fn(&'a (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>, &'t0 (), for<'a, 'b> fn(&'a (), &'b ())) -> _`
               found closure signature `fn((), (), (), ()) -> _`
 note: required by a bound in `h2`
   --> $DIR/anonymous-higher-ranked-lifetime.rs:30:25
diff --git a/src/test/ui/asm/aarch64/type-check-2-2.stderr b/src/test/ui/asm/aarch64/type-check-2-2.stderr
index b2a695529f9..eef16a165a8 100644
--- a/src/test/ui/asm/aarch64/type-check-2-2.stderr
+++ b/src/test/ui/asm/aarch64/type-check-2-2.stderr
@@ -5,6 +5,11 @@ LL |         let x: u64;
    |             - binding declared here but left uninitialized
 LL |         asm!("{}", in(reg) x);
    |                            ^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |         let x: u64 = 0;
+   |                    +++
 
 error[E0381]: used binding `y` isn't initialized
   --> $DIR/type-check-2-2.rs:22:9
@@ -13,6 +18,11 @@ LL |         let mut y: u64;
    |             ----- binding declared here but left uninitialized
 LL |         asm!("{}", inout(reg) y);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ `y` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |         let mut y: u64 = 0;
+   |                        +++
 
 error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
   --> $DIR/type-check-2-2.rs:30:29
diff --git a/src/test/ui/asm/x86_64/type-check-5.stderr b/src/test/ui/asm/x86_64/type-check-5.stderr
index e9c93fea561..bd90461e52c 100644
--- a/src/test/ui/asm/x86_64/type-check-5.stderr
+++ b/src/test/ui/asm/x86_64/type-check-5.stderr
@@ -5,6 +5,11 @@ LL |         let x: u64;
    |             - binding declared here but left uninitialized
 LL |         asm!("{}", in(reg) x);
    |                            ^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |         let x: u64 = 0;
+   |                    +++
 
 error[E0381]: used binding `y` isn't initialized
   --> $DIR/type-check-5.rs:18:9
@@ -13,6 +18,11 @@ LL |         let mut y: u64;
    |             ----- binding declared here but left uninitialized
 LL |         asm!("{}", inout(reg) y);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ `y` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |         let mut y: u64 = 0;
+   |                        +++
 
 error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
   --> $DIR/type-check-5.rs:26:29
diff --git a/src/test/ui/associated-consts/issue-102335-const.rs b/src/test/ui/associated-consts/issue-102335-const.rs
new file mode 100644
index 00000000000..f60cb92da7f
--- /dev/null
+++ b/src/test/ui/associated-consts/issue-102335-const.rs
@@ -0,0 +1,12 @@
+#![feature(associated_const_equality)]
+
+trait T {
+    type A: S<C<X = 0i32> = 34>;
+    //~^ ERROR associated type bindings are not allowed here
+}
+
+trait S {
+    const C: i32;
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-consts/issue-102335-const.stderr b/src/test/ui/associated-consts/issue-102335-const.stderr
new file mode 100644
index 00000000000..531d15c5900
--- /dev/null
+++ b/src/test/ui/associated-consts/issue-102335-const.stderr
@@ -0,0 +1,9 @@
+error[E0229]: associated type bindings are not allowed here
+  --> $DIR/issue-102335-const.rs:4:17
+   |
+LL |     type A: S<C<X = 0i32> = 34>;
+   |                 ^^^^^^^^ associated type not allowed here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0229`.
diff --git a/src/test/ui/associated-type-bounds/issue-102335-ty.rs b/src/test/ui/associated-type-bounds/issue-102335-ty.rs
new file mode 100644
index 00000000000..363df73c1ff
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/issue-102335-ty.rs
@@ -0,0 +1,12 @@
+trait T {
+    type A: S<C<i32 = u32> = ()>;
+    //~^ ERROR associated type bindings are not allowed here
+}
+
+trait Q {}
+
+trait S {
+    type C: Q;
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-type-bounds/issue-102335-ty.stderr b/src/test/ui/associated-type-bounds/issue-102335-ty.stderr
new file mode 100644
index 00000000000..8777b296515
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/issue-102335-ty.stderr
@@ -0,0 +1,9 @@
+error[E0229]: associated type bindings are not allowed here
+  --> $DIR/issue-102335-ty.rs:2:17
+   |
+LL |     type A: S<C<i32 = u32> = ()>;
+   |                 ^^^^^^^^^ associated type not allowed here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0229`.
diff --git a/src/test/ui/async-await/await-keyword/2018-edition-error-in-non-macro-position.stderr b/src/test/ui/async-await/await-keyword/2018-edition-error-in-non-macro-position.stderr
index ccbaa1f2af0..6bd8f671d73 100644
--- a/src/test/ui/async-await/await-keyword/2018-edition-error-in-non-macro-position.stderr
+++ b/src/test/ui/async-await/await-keyword/2018-edition-error-in-non-macro-position.stderr
@@ -46,7 +46,9 @@ error: expected identifier, found keyword `await`
   --> $DIR/2018-edition-error-in-non-macro-position.rs:13:14
    |
 LL | struct Foo { await: () }
-   |              ^^^^^ expected identifier, found keyword
+   |        ---   ^^^^^ expected identifier, found keyword
+   |        |
+   |        while parsing this struct
    |
 help: escape `await` to use it as an identifier
    |
diff --git a/src/test/ui/async-await/in-trait/issue-102138.rs b/src/test/ui/async-await/in-trait/issue-102138.rs
new file mode 100644
index 00000000000..f61b34ed99e
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/issue-102138.rs
@@ -0,0 +1,46 @@
+// check-pass
+// edition:2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+use std::future::Future;
+
+async fn yield_now() {}
+
+trait AsyncIterator {
+    type Item;
+    async fn next(&mut self) -> Option<Self::Item>;
+}
+
+struct YieldingRange {
+    counter: u32,
+    stop: u32,
+}
+
+impl AsyncIterator for YieldingRange {
+    type Item = u32;
+
+    async fn next(&mut self) -> Option<Self::Item> {
+        if self.counter == self.stop {
+            None
+        } else {
+            let c = self.counter;
+            self.counter += 1;
+            yield_now().await;
+            Some(c)
+        }
+    }
+}
+
+async fn async_main() {
+    let mut x = YieldingRange { counter: 0, stop: 10 };
+
+    while let Some(v) = x.next().await {
+        println!("Hi: {v}");
+    }
+}
+
+fn main() {
+    let _ = async_main();
+}
diff --git a/src/test/ui/async-await/in-trait/issue-102219.rs b/src/test/ui/async-await/in-trait/issue-102219.rs
new file mode 100644
index 00000000000..9a35f6515cb
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/issue-102219.rs
@@ -0,0 +1,10 @@
+// compile-flags:--crate-type=lib
+// edition:2021
+// check-pass
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+trait T {
+    async fn foo();
+}
diff --git a/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr b/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr
index 198de7bf79f..85f7d1dd674 100644
--- a/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr
+++ b/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr
@@ -18,7 +18,7 @@ LL |   async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
    |  ___________________________________________________________________^
 LL | | }
    | |_^
-   = note: required because it captures the following types: `ResumeTy`, `impl for<'r, 's, 't0> Future<Output = ()>`, `()`
+   = note: required because it captures the following types: `ResumeTy`, `impl for<'a, 'b, 'c> Future<Output = ()>`, `()`
 note: required because it's used within this `async` block
   --> $DIR/issue-70935-complex-spans.rs:16:16
    |
diff --git a/src/test/ui/binop/issue-77910-1.rs b/src/test/ui/binop/issue-77910-1.rs
index d786e335859..95bbd6a60ec 100644
--- a/src/test/ui/binop/issue-77910-1.rs
+++ b/src/test/ui/binop/issue-77910-1.rs
@@ -7,5 +7,5 @@ fn main() {
     // we shouldn't ice with the bound var here.
     assert_eq!(foo, y);
     //~^ ERROR binary operation `==` cannot be applied to type
-    //~| ERROR `for<'r> fn(&'r i32) -> &'r i32 {foo}` doesn't implement `Debug`
+    //~| ERROR `for<'a> fn(&'a i32) -> &'a i32 {foo}` doesn't implement `Debug`
 }
diff --git a/src/test/ui/binop/issue-77910-1.stderr b/src/test/ui/binop/issue-77910-1.stderr
index 097a14f26f8..9c7bf6228be 100644
--- a/src/test/ui/binop/issue-77910-1.stderr
+++ b/src/test/ui/binop/issue-77910-1.stderr
@@ -1,24 +1,24 @@
-error[E0369]: binary operation `==` cannot be applied to type `for<'r> fn(&'r i32) -> &'r i32 {foo}`
+error[E0369]: binary operation `==` cannot be applied to type `for<'a> fn(&'a i32) -> &'a i32 {foo}`
   --> $DIR/issue-77910-1.rs:8:5
    |
 LL |     assert_eq!(foo, y);
    |     ^^^^^^^^^^^^^^^^^^
    |     |
-   |     for<'r> fn(&'r i32) -> &'r i32 {foo}
+   |     for<'a> fn(&'a i32) -> &'a i32 {foo}
    |     _
    |
    = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0277]: `for<'r> fn(&'r i32) -> &'r i32 {foo}` doesn't implement `Debug`
+error[E0277]: `for<'a> fn(&'a i32) -> &'a i32 {foo}` doesn't implement `Debug`
   --> $DIR/issue-77910-1.rs:8:5
    |
 LL | fn foo(s: &i32) -> &i32 {
    |    --- consider calling this function
 ...
 LL |     assert_eq!(foo, y);
-   |     ^^^^^^^^^^^^^^^^^^ `for<'r> fn(&'r i32) -> &'r i32 {foo}` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+   |     ^^^^^^^^^^^^^^^^^^ `for<'a> fn(&'a i32) -> &'a i32 {foo}` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
-   = help: the trait `Debug` is not implemented for fn item `for<'r> fn(&'r i32) -> &'r i32 {foo}`
+   = help: the trait `Debug` is not implemented for fn item `for<'a> fn(&'a i32) -> &'a i32 {foo}`
    = help: use parentheses to call the function: `foo(s)`
    = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/src/test/ui/binop/issue-77910-2.stderr b/src/test/ui/binop/issue-77910-2.stderr
index a334bd85625..b3856b6ae16 100644
--- a/src/test/ui/binop/issue-77910-2.stderr
+++ b/src/test/ui/binop/issue-77910-2.stderr
@@ -1,10 +1,10 @@
-error[E0369]: binary operation `==` cannot be applied to type `for<'r> fn(&'r i32) -> &'r i32 {foo}`
+error[E0369]: binary operation `==` cannot be applied to type `for<'a> fn(&'a i32) -> &'a i32 {foo}`
   --> $DIR/issue-77910-2.rs:7:12
    |
 LL |     if foo == y {}
    |        --- ^^ - _
    |        |
-   |        for<'r> fn(&'r i32) -> &'r i32 {foo}
+   |        for<'a> fn(&'a i32) -> &'a i32 {foo}
    |
 help: use parentheses to call this function
    |
diff --git a/src/test/ui/borrowck/borrowck-block-unint.stderr b/src/test/ui/borrowck/borrowck-block-unint.stderr
index e720db1c696..f47921a9752 100644
--- a/src/test/ui/borrowck/borrowck-block-unint.stderr
+++ b/src/test/ui/borrowck/borrowck-block-unint.stderr
@@ -7,6 +7,11 @@ LL |     force(|| {
    |           ^^ `x` used here but it isn't initialized
 LL |         println!("{}", x);
    |                        - borrow occurs due to use in closure
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-break-uninit-2.stderr b/src/test/ui/borrowck/borrowck-break-uninit-2.stderr
index 91038b3adca..ea93a8f409c 100644
--- a/src/test/ui/borrowck/borrowck-break-uninit-2.stderr
+++ b/src/test/ui/borrowck/borrowck-break-uninit-2.stderr
@@ -8,6 +8,10 @@ LL |     println!("{}", x);
    |                    ^ `x` used here but it isn't initialized
    |
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-break-uninit.stderr b/src/test/ui/borrowck/borrowck-break-uninit.stderr
index 8d0c9582fda..a7a8fc2ff83 100644
--- a/src/test/ui/borrowck/borrowck-break-uninit.stderr
+++ b/src/test/ui/borrowck/borrowck-break-uninit.stderr
@@ -8,6 +8,10 @@ LL |     println!("{}", x);
    |                    ^ `x` used here but it isn't initialized
    |
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.stderr b/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.stderr
index e8a2fbc91ea..1a22b5f0975 100644
--- a/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.stderr
+++ b/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.stderr
@@ -5,6 +5,11 @@ LL |         let i: isize;
    |             - binding declared here but left uninitialized
 LL |         i
    |         ^ `i` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |         let i: isize = 0;
+   |                      +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-init-in-fn-expr.stderr b/src/test/ui/borrowck/borrowck-init-in-fn-expr.stderr
index 1e950d6a20d..f1b9b9aa709 100644
--- a/src/test/ui/borrowck/borrowck-init-in-fn-expr.stderr
+++ b/src/test/ui/borrowck/borrowck-init-in-fn-expr.stderr
@@ -5,6 +5,11 @@ LL |         let i: isize;
    |             - binding declared here but left uninitialized
 LL |         i
    |         ^ `i` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |         let i: isize = 0;
+   |                      +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-init-in-fru.stderr b/src/test/ui/borrowck/borrowck-init-in-fru.stderr
index 83a3e3e0e3a..39b28811a0c 100644
--- a/src/test/ui/borrowck/borrowck-init-in-fru.stderr
+++ b/src/test/ui/borrowck/borrowck-init-in-fru.stderr
@@ -5,6 +5,11 @@ LL |     let mut origin: Point;
    |         ---------- binding declared here but left uninitialized
 LL |     origin = Point { x: 10, ..origin };
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^ `origin.y` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let mut origin: Point = todo!();
+   |                           +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-init-op-equal.stderr b/src/test/ui/borrowck/borrowck-init-op-equal.stderr
index 74704b2abfe..ef0fa6df4fb 100644
--- a/src/test/ui/borrowck/borrowck-init-op-equal.stderr
+++ b/src/test/ui/borrowck/borrowck-init-op-equal.stderr
@@ -5,6 +5,11 @@ LL |     let v: isize;
    |         - binding declared here but left uninitialized
 LL |     v += 1;
    |     ^^^^^^ `v` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let v: isize = 0;
+   |                  +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-init-plus-equal.stderr b/src/test/ui/borrowck/borrowck-init-plus-equal.stderr
index 7542576d636..cec05331836 100644
--- a/src/test/ui/borrowck/borrowck-init-plus-equal.stderr
+++ b/src/test/ui/borrowck/borrowck-init-plus-equal.stderr
@@ -5,6 +5,11 @@ LL |     let mut v: isize;
    |         ----- binding declared here but left uninitialized
 LL |     v = v + 1;
    |         ^ `v` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let mut v: isize = 0;
+   |                      +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-return.stderr b/src/test/ui/borrowck/borrowck-return.stderr
index 1c916e22317..9799357c9ca 100644
--- a/src/test/ui/borrowck/borrowck-return.stderr
+++ b/src/test/ui/borrowck/borrowck-return.stderr
@@ -5,6 +5,11 @@ LL |     let x: isize;
    |         - binding declared here but left uninitialized
 LL |     return x;
    |            ^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-storage-dead.stderr b/src/test/ui/borrowck/borrowck-storage-dead.stderr
index 2cea4392d6a..3a413153acd 100644
--- a/src/test/ui/borrowck/borrowck-storage-dead.stderr
+++ b/src/test/ui/borrowck/borrowck-storage-dead.stderr
@@ -5,6 +5,11 @@ LL |         let x: i32;
    |             - binding declared here but left uninitialized
 LL |         let _ = x + 1;
    |                 ^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |         let x: i32 = 0;
+   |                    +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-uninit-after-item.stderr b/src/test/ui/borrowck/borrowck-uninit-after-item.stderr
index 588b1b0c972..071598b42ee 100644
--- a/src/test/ui/borrowck/borrowck-uninit-after-item.stderr
+++ b/src/test/ui/borrowck/borrowck-uninit-after-item.stderr
@@ -6,6 +6,11 @@ LL |     let bar;
 LL |     fn baz(_x: isize) { }
 LL |     baz(bar);
    |         ^^^ `bar` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let bar = 0;
+   |             +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-uninit-field-access.stderr b/src/test/ui/borrowck/borrowck-uninit-field-access.stderr
index 6a38a798919..f0f4ad704b7 100644
--- a/src/test/ui/borrowck/borrowck-uninit-field-access.stderr
+++ b/src/test/ui/borrowck/borrowck-uninit-field-access.stderr
@@ -5,6 +5,11 @@ LL |     let mut a: Point;
    |         ----- binding declared here but left uninitialized
 LL |     let _ = a.x + 1;
    |             ^^^ `a.x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let mut a: Point = Default::default();
+   |                      ++++++++++++++++++++
 
 error[E0382]: use of moved value: `line1.origin`
   --> $DIR/borrowck-uninit-field-access.rs:25:13
diff --git a/src/test/ui/borrowck/borrowck-uninit-in-assignop.stderr b/src/test/ui/borrowck/borrowck-uninit-in-assignop.stderr
index 744cb14e662..fdbb451bde4 100644
--- a/src/test/ui/borrowck/borrowck-uninit-in-assignop.stderr
+++ b/src/test/ui/borrowck/borrowck-uninit-in-assignop.stderr
@@ -5,6 +5,11 @@ LL |     let x: isize;
    |         - binding declared here but left uninitialized
 LL |     x += 1;
    |     ^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:9:5
@@ -13,6 +18,11 @@ LL |     let x: isize;
    |         - binding declared here but left uninitialized
 LL |     x -= 1;
    |     ^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:12:5
@@ -21,6 +31,11 @@ LL |     let x: isize;
    |         - binding declared here but left uninitialized
 LL |     x *= 1;
    |     ^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:15:5
@@ -29,6 +44,11 @@ LL |     let x: isize;
    |         - binding declared here but left uninitialized
 LL |     x /= 1;
    |     ^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:18:5
@@ -37,6 +57,11 @@ LL |     let x: isize;
    |         - binding declared here but left uninitialized
 LL |     x %= 1;
    |     ^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:21:5
@@ -45,6 +70,11 @@ LL |     let x: isize;
    |         - binding declared here but left uninitialized
 LL |     x ^= 1;
    |     ^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:24:5
@@ -53,6 +83,11 @@ LL |     let x: isize;
    |         - binding declared here but left uninitialized
 LL |     x &= 1;
    |     ^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:27:5
@@ -61,6 +96,11 @@ LL |     let x: isize;
    |         - binding declared here but left uninitialized
 LL |     x |= 1;
    |     ^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:30:5
@@ -69,6 +109,11 @@ LL |     let x: isize;
    |         - binding declared here but left uninitialized
 LL |     x <<= 1;
    |     ^^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:33:5
@@ -77,6 +122,11 @@ LL |     let x: isize;
    |         - binding declared here but left uninitialized
 LL |     x >>= 1;
    |     ^^^^^^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error: aborting due to 10 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-uninit-ref-chain.stderr b/src/test/ui/borrowck/borrowck-uninit-ref-chain.stderr
index c486cb6dd0c..73fded7545c 100644
--- a/src/test/ui/borrowck/borrowck-uninit-ref-chain.stderr
+++ b/src/test/ui/borrowck/borrowck-uninit-ref-chain.stderr
@@ -5,6 +5,11 @@ LL |     let x: &&Box<i32>;
    |         - binding declared here but left uninitialized
 LL |     let _y = &**x;
    |              ^^^^ `**x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: &&Box<i32> = todo!();
+   |                       +++++++++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-ref-chain.rs:11:14
@@ -13,6 +18,11 @@ LL |     let x: &&S<i32, i32>;
    |         - binding declared here but left uninitialized
 LL |     let _y = &**x;
    |              ^^^^ `**x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: &&S<i32, i32> = todo!();
+   |                          +++++++++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-ref-chain.rs:14:14
@@ -21,6 +31,11 @@ LL |     let x: &&i32;
    |         - binding declared here but left uninitialized
 LL |     let _y = &**x;
    |              ^^^^ `**x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: &&i32 = todo!();
+   |                  +++++++++
 
 error[E0381]: partially assigned binding `a` isn't fully initialized
   --> $DIR/borrowck-uninit-ref-chain.rs:18:5
diff --git a/src/test/ui/borrowck/borrowck-uninit.stderr b/src/test/ui/borrowck/borrowck-uninit.stderr
index d5566691a82..eeafc4ce191 100644
--- a/src/test/ui/borrowck/borrowck-uninit.stderr
+++ b/src/test/ui/borrowck/borrowck-uninit.stderr
@@ -5,6 +5,11 @@ LL |     let x: isize;
    |         - binding declared here but left uninitialized
 LL |     foo(x);
    |         ^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: isize = 0;
+   |                  +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-use-in-index-lvalue.stderr b/src/test/ui/borrowck/borrowck-use-in-index-lvalue.stderr
index 459cf1398b7..18e808f10d0 100644
--- a/src/test/ui/borrowck/borrowck-use-in-index-lvalue.stderr
+++ b/src/test/ui/borrowck/borrowck-use-in-index-lvalue.stderr
@@ -5,6 +5,11 @@ LL |     let w: &mut [isize];
    |         - binding declared here but left uninitialized
 LL |     w[5] = 0;
    |     ^^^^ `*w` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let w: &mut [isize] = todo!();
+   |                         +++++++++
 
 error[E0381]: used binding `w` isn't initialized
   --> $DIR/borrowck-use-in-index-lvalue.rs:6:5
@@ -13,6 +18,11 @@ LL |     let mut w: &mut [isize];
    |         ----- binding declared here but left uninitialized
 LL |     w[5] = 0;
    |     ^^^^ `*w` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let mut w: &mut [isize] = todo!();
+   |                             +++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr
index 942ed4fc6ca..55f3ff553c1 100644
--- a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr
+++ b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr
@@ -5,6 +5,11 @@ LL |     let x: &i32;
    |         - binding declared here but left uninitialized
 LL |     let y = x as *const dyn Foo;
    |             ^ `*x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: &i32 = todo!();
+   |                 +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr
index f3289e23981..ea3d0d3ef51 100644
--- a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr
+++ b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr
@@ -5,6 +5,11 @@ LL |     let x: &i32;
    |         - binding declared here but left uninitialized
 LL |     let y = x as *const i32;
    |             ^ `*x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: &i32 = todo!();
+   |                 +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-while-cond.stderr b/src/test/ui/borrowck/borrowck-while-cond.stderr
index e41c1c55e60..5d019498956 100644
--- a/src/test/ui/borrowck/borrowck-while-cond.stderr
+++ b/src/test/ui/borrowck/borrowck-while-cond.stderr
@@ -5,6 +5,11 @@ LL |     let x: bool;
    |         - binding declared here but left uninitialized
 LL |     while x { }
    |           ^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: bool = false;
+   |                 +++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/issue-24267-flow-exit.stderr b/src/test/ui/borrowck/issue-24267-flow-exit.stderr
index b85e8f216e5..58d1c8c0f73 100644
--- a/src/test/ui/borrowck/issue-24267-flow-exit.stderr
+++ b/src/test/ui/borrowck/issue-24267-flow-exit.stderr
@@ -8,6 +8,10 @@ LL |     println!("{}", x);
    |                    ^ `x` used here but it isn't initialized
    |
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let x: i32 = 0;
+   |                +++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/issue-24267-flow-exit.rs:18:20
@@ -19,6 +23,10 @@ LL |     println!("{}", x);
    |                    ^ `x` used here but it isn't initialized
    |
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let x: i32 = 0;
+   |                +++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/borrowck/issue-62107-match-arm-scopes.stderr b/src/test/ui/borrowck/issue-62107-match-arm-scopes.stderr
index f5d2eecfa91..9683da919aa 100644
--- a/src/test/ui/borrowck/issue-62107-match-arm-scopes.stderr
+++ b/src/test/ui/borrowck/issue-62107-match-arm-scopes.stderr
@@ -5,6 +5,11 @@ LL |     let e: i32;
    |         - binding declared here but left uninitialized
 LL |     match e {
    |           ^ `e` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let e: i32 = 0;
+   |                +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/reborrow-sugg-move-then-borrow.rs b/src/test/ui/borrowck/reborrow-sugg-move-then-borrow.rs
new file mode 100644
index 00000000000..31eba074008
--- /dev/null
+++ b/src/test/ui/borrowck/reborrow-sugg-move-then-borrow.rs
@@ -0,0 +1,26 @@
+// Tests the suggestion to reborrow the first move site
+// when we move then borrow a `&mut` ref.
+
+struct State;
+
+impl IntoIterator for &mut State {
+    type IntoIter = std::vec::IntoIter<()>;
+    type Item = ();
+
+    fn into_iter(self) -> Self::IntoIter {
+        vec![].into_iter()
+    }
+}
+
+fn once(f: impl FnOnce()) {}
+
+fn fill_memory_blocks_mt(state: &mut State) {
+    for _ in state {}
+    //~^ HELP consider creating a fresh reborrow of `state` here
+    fill_segment(state);
+    //~^ ERROR borrow of moved value: `state`
+}
+
+fn fill_segment(state: &mut State) {}
+
+fn main() {}
diff --git a/src/test/ui/borrowck/reborrow-sugg-move-then-borrow.stderr b/src/test/ui/borrowck/reborrow-sugg-move-then-borrow.stderr
new file mode 100644
index 00000000000..13a2005e2ef
--- /dev/null
+++ b/src/test/ui/borrowck/reborrow-sugg-move-then-borrow.stderr
@@ -0,0 +1,24 @@
+error[E0382]: borrow of moved value: `state`
+  --> $DIR/reborrow-sugg-move-then-borrow.rs:20:18
+   |
+LL | fn fill_memory_blocks_mt(state: &mut State) {
+   |                          ----- move occurs because `state` has type `&mut State`, which does not implement the `Copy` trait
+LL |     for _ in state {}
+   |              ----- `state` moved due to this implicit call to `.into_iter()`
+LL |
+LL |     fill_segment(state);
+   |                  ^^^^^ value borrowed here after move
+   |
+note: this function takes ownership of the receiver `self`, which moves `state`
+  --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+   |
+LL |     fn into_iter(self) -> Self::IntoIter;
+   |                  ^^^^
+help: consider creating a fresh reborrow of `state` here
+   |
+LL |     for _ in &mut *state {}
+   |              ++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/borrowck/suggest-assign-rvalue.rs b/src/test/ui/borrowck/suggest-assign-rvalue.rs
new file mode 100644
index 00000000000..aaca9d47f0a
--- /dev/null
+++ b/src/test/ui/borrowck/suggest-assign-rvalue.rs
@@ -0,0 +1,57 @@
+#![allow(dead_code)]
+#![feature(never_type)]
+
+#[derive(Debug, Default)]
+struct Demo {}
+
+#[derive(Debug)]
+struct DemoNoDef {}
+
+fn apple(_: u32) {}
+
+fn banana() {
+    let chaenomeles;
+    apple(chaenomeles);
+    //~^ ERROR used binding `chaenomeles` isn't initialized [E0381]
+}
+
+fn main() {
+    let my_bool: bool = bool::default();
+    println!("my_bool: {}", my_bool);
+
+    let my_float: f32;
+    println!("my_float: {}", my_float);
+    //~^ ERROR used binding `my_float` isn't initialized
+    let demo: Demo;
+    println!("demo: {:?}", demo);
+    //~^ ERROR used binding `demo` isn't initialized
+
+    let demo_no: DemoNoDef;
+    println!("demo_no: {:?}", demo_no);
+    //~^ ERROR used binding `demo_no` isn't initialized
+
+    let arr: [i32; 5];
+    println!("arr: {:?}", arr);
+    //~^ ERROR used binding `arr` isn't initialized
+    let foo: Vec<&str>;
+    println!("foo: {:?}", foo);
+    //~^ ERROR used binding `foo` isn't initialized
+
+    let my_string: String;
+    println!("my_string: {}", my_string);
+    //~^ ERROR used binding `my_string` isn't initialized
+
+    let my_int: &i32;
+    println!("my_int: {}", *my_int);
+    //~^ ERROR used binding `my_int` isn't initialized
+
+    let hello: &str;
+    println!("hello: {}", hello);
+    //~^ ERROR used binding `hello` isn't initialized
+
+    let never: !;
+    println!("never: {}", never);
+    //~^ ERROR used binding `never` isn't initialized [E0381]
+
+    banana();
+}
diff --git a/src/test/ui/borrowck/suggest-assign-rvalue.stderr b/src/test/ui/borrowck/suggest-assign-rvalue.stderr
new file mode 100644
index 00000000000..92acba640d7
--- /dev/null
+++ b/src/test/ui/borrowck/suggest-assign-rvalue.stderr
@@ -0,0 +1,138 @@
+error[E0381]: used binding `chaenomeles` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:14:11
+   |
+LL |     let chaenomeles;
+   |         ----------- binding declared here but left uninitialized
+LL |     apple(chaenomeles);
+   |           ^^^^^^^^^^^ `chaenomeles` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let chaenomeles = 0;
+   |                     +++
+
+error[E0381]: used binding `my_float` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:23:30
+   |
+LL |     let my_float: f32;
+   |         -------- binding declared here but left uninitialized
+LL |     println!("my_float: {}", my_float);
+   |                              ^^^^^^^^ `my_float` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let my_float: f32 = 0.0;
+   |                       +++++
+
+error[E0381]: used binding `demo` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:26:28
+   |
+LL |     let demo: Demo;
+   |         ---- binding declared here but left uninitialized
+LL |     println!("demo: {:?}", demo);
+   |                            ^^^^ `demo` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let demo: Demo = Default::default();
+   |                    ++++++++++++++++++++
+
+error[E0381]: used binding `demo_no` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:30:31
+   |
+LL |     let demo_no: DemoNoDef;
+   |         ------- binding declared here but left uninitialized
+LL |     println!("demo_no: {:?}", demo_no);
+   |                               ^^^^^^^ `demo_no` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let demo_no: DemoNoDef = todo!();
+   |                            +++++++++
+
+error[E0381]: used binding `arr` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:34:27
+   |
+LL |     let arr: [i32; 5];
+   |         --- binding declared here but left uninitialized
+LL |     println!("arr: {:?}", arr);
+   |                           ^^^ `arr` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let arr: [i32; 5] = todo!();
+   |                       +++++++++
+
+error[E0381]: used binding `foo` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:37:27
+   |
+LL |     let foo: Vec<&str>;
+   |         --- binding declared here but left uninitialized
+LL |     println!("foo: {:?}", foo);
+   |                           ^^^ `foo` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let foo: Vec<&str> = vec![];
+   |                        ++++++++
+
+error[E0381]: used binding `my_string` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:41:31
+   |
+LL |     let my_string: String;
+   |         --------- binding declared here but left uninitialized
+LL |     println!("my_string: {}", my_string);
+   |                               ^^^^^^^^^ `my_string` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let my_string: String = Default::default();
+   |                           ++++++++++++++++++++
+
+error[E0381]: used binding `my_int` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:45:28
+   |
+LL |     let my_int: &i32;
+   |         ------ binding declared here but left uninitialized
+LL |     println!("my_int: {}", *my_int);
+   |                            ^^^^^^^ `*my_int` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let my_int: &i32 = todo!();
+   |                      +++++++++
+
+error[E0381]: used binding `hello` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:49:27
+   |
+LL |     let hello: &str;
+   |         ----- binding declared here but left uninitialized
+LL |     println!("hello: {}", hello);
+   |                           ^^^^^ `hello` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let hello: &str = todo!();
+   |                     +++++++++
+
+error[E0381]: used binding `never` isn't initialized
+  --> $DIR/suggest-assign-rvalue.rs:53:27
+   |
+LL |     let never: !;
+   |         ----- binding declared here but left uninitialized
+LL |     println!("never: {}", never);
+   |                           ^^^^^ `never` used here but it isn't initialized
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 10 previous errors
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/src/test/ui/box/issue-95036.rs b/src/test/ui/box/issue-95036.rs
index c2d4275aa49..0611fabc15c 100644
--- a/src/test/ui/box/issue-95036.rs
+++ b/src/test/ui/box/issue-95036.rs
@@ -1,7 +1,7 @@
 // compile-flags: -O
 // build-pass
 
-#![feature(allocator_api, bench_black_box)]
+#![feature(allocator_api)]
 
 #[inline(never)]
 pub fn by_ref(node: &mut Box<[u8; 1], &std::alloc::Global>) {
diff --git a/src/test/ui/check-static-values-constraints.rs b/src/test/ui/check-static-values-constraints.rs
index eb4ecd8baca..f6a577d0d9c 100644
--- a/src/test/ui/check-static-values-constraints.rs
+++ b/src/test/ui/check-static-values-constraints.rs
@@ -63,7 +63,7 @@ static STATIC8: SafeStruct = SafeStruct{field1: SafeEnum::Variant1,
 // This example should fail because field1 in the base struct is not safe
 static STATIC9: SafeStruct = SafeStruct{field1: SafeEnum::Variant1,
                                         ..SafeStruct{field1: SafeEnum::Variant3(WithDtor),
-//~^ ERROR destructors cannot be evaluated at compile-time
+//~^ ERROR destructor of
                                                      field2: SafeEnum::Variant1}};
 
 struct UnsafeStruct;
diff --git a/src/test/ui/check-static-values-constraints.stderr b/src/test/ui/check-static-values-constraints.stderr
index 3c193ca34ac..31939f7f6db 100644
--- a/src/test/ui/check-static-values-constraints.stderr
+++ b/src/test/ui/check-static-values-constraints.stderr
@@ -1,4 +1,4 @@
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `SafeStruct` cannot be evaluated at compile-time
   --> $DIR/check-static-values-constraints.rs:65:43
    |
 LL |                                           ..SafeStruct{field1: SafeEnum::Variant3(WithDtor),
@@ -7,7 +7,7 @@ LL | |
 LL | |                                                      field2: SafeEnum::Variant1}};
    | |                                                                                ^- value is dropped here
    | |________________________________________________________________________________|
-   |                                                                                  statics cannot evaluate destructors
+   |                                                                                  the destructor for this type cannot be evaluated in statics
 
 error[E0010]: allocations are not allowed in statics
   --> $DIR/check-static-values-constraints.rs:79:33
diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr b/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr
index 284fc1c21f5..e6ddc606897 100644
--- a/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr
+++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr
@@ -26,7 +26,7 @@ LL |     with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
    |                                                 ^ one type is more general than the other
    |
    = note: expected fn pointer `fn(&u32)`
-              found fn pointer `for<'r> fn(&'r u32)`
+              found fn pointer `for<'a> fn(&'a u32)`
 
 error[E0308]: mismatched types
   --> $DIR/expect-fn-supply-fn.rs:39:50
@@ -34,7 +34,7 @@ error[E0308]: mismatched types
 LL |     with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {});
    |                                                  ^ one type is more general than the other
    |
-   = note: expected fn pointer `for<'r> fn(&'r u32)`
+   = note: expected fn pointer `for<'a> fn(&'a u32)`
               found fn pointer `fn(&u32)`
 
 error[E0308]: mismatched types
@@ -43,7 +43,7 @@ error[E0308]: mismatched types
 LL |     with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| {
    |                                                  ^ one type is more general than the other
    |
-   = note: expected fn pointer `for<'r> fn(&'r u32)`
+   = note: expected fn pointer `for<'a> fn(&'a u32)`
               found fn pointer `fn(&u32)`
 
 error: aborting due to 5 previous errors
diff --git a/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr b/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr
index fea5441ec67..ad061d93cb2 100644
--- a/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr
@@ -76,6 +76,11 @@ LL |     let x: u8;
    |         - binding declared here but left uninitialized
 LL |     let c1 = || match x { };
    |                       ^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: u8 = 0;
+   |               +++
 
 error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/closures/closure-reform-bad.stderr b/src/test/ui/closures/closure-reform-bad.stderr
index 9dfff8499fd..4c40f70b9d0 100644
--- a/src/test/ui/closures/closure-reform-bad.stderr
+++ b/src/test/ui/closures/closure-reform-bad.stderr
@@ -8,7 +8,7 @@ LL |     call_bare(f)
    |     |
    |     arguments to this function are incorrect
    |
-   = note: expected fn pointer `for<'r> fn(&'r str)`
+   = note: expected fn pointer `for<'a> fn(&'a str)`
                  found closure `[closure@$DIR/closure-reform-bad.rs:10:13: 10:22]`
 note: closures can only be coerced to `fn` types if they do not capture any variables
   --> $DIR/closure-reform-bad.rs:10:43
diff --git a/src/test/ui/coherence/coherence-negative-impls-copy-bad.rs b/src/test/ui/coherence/coherence-negative-impls-copy-bad.rs
new file mode 100644
index 00000000000..563f28e2291
--- /dev/null
+++ b/src/test/ui/coherence/coherence-negative-impls-copy-bad.rs
@@ -0,0 +1,11 @@
+#![feature(negative_impls)]
+#![crate_type = "lib"]
+
+impl !Copy for str {}
+//~^ ERROR only traits defined in the current crate can be implemented
+
+impl !Copy for fn() {}
+//~^ ERROR only traits defined in the current crate can be implemented
+
+impl !Copy for () {}
+//~^ ERROR only traits defined in the current crate can be implemented
diff --git a/src/test/ui/coherence/coherence-negative-impls-copy-bad.stderr b/src/test/ui/coherence/coherence-negative-impls-copy-bad.stderr
new file mode 100644
index 00000000000..2295d6315d1
--- /dev/null
+++ b/src/test/ui/coherence/coherence-negative-impls-copy-bad.stderr
@@ -0,0 +1,36 @@
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/coherence-negative-impls-copy-bad.rs:4:1
+   |
+LL | impl !Copy for str {}
+   | ^^^^^^^^^^^^^^^---
+   | |              |
+   | |              `str` is not defined in the current crate
+   | impl doesn't use only types from inside the current crate
+   |
+   = note: define and implement a trait or new type instead
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/coherence-negative-impls-copy-bad.rs:7:1
+   |
+LL | impl !Copy for fn() {}
+   | ^^^^^^^^^^^^^^^----
+   | |              |
+   | |              `fn()` is not defined in the current crate
+   | impl doesn't use only types from inside the current crate
+   |
+   = note: define and implement a trait or new type instead
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/coherence-negative-impls-copy-bad.rs:10:1
+   |
+LL | impl !Copy for () {}
+   | ^^^^^^^^^^^^^^^--
+   | |              |
+   | |              this is not defined in the current crate because tuples are always foreign
+   | impl doesn't use only types from inside the current crate
+   |
+   = note: define and implement a trait or new type instead
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0117`.
diff --git a/src/test/ui/coherence/coherence-negative-impls-copy.rs b/src/test/ui/coherence/coherence-negative-impls-copy.rs
new file mode 100644
index 00000000000..7b29aade413
--- /dev/null
+++ b/src/test/ui/coherence/coherence-negative-impls-copy.rs
@@ -0,0 +1,29 @@
+// check-pass
+// regression test for issue #101836
+
+#![feature(negative_impls, extern_types)]
+#![crate_type = "lib"]
+
+struct NonCopy;
+struct NeverCopy(NonCopy);
+
+impl !Copy for NeverCopy {}
+
+
+struct WithDrop;
+impl Drop for WithDrop { fn drop(&mut self) {} }
+
+impl !Copy for WithDrop {}
+
+
+struct Type;
+trait Trait {}
+extern {
+    type ExternType;
+}
+
+impl !Copy for &mut Type {}
+
+impl !Copy for dyn Trait {}
+
+impl !Copy for ExternType {}
diff --git a/src/test/ui/coherence/deep-bad-copy-reason.stderr b/src/test/ui/coherence/deep-bad-copy-reason.stderr
index 295538cee60..168ee57263d 100644
--- a/src/test/ui/coherence/deep-bad-copy-reason.stderr
+++ b/src/test/ui/coherence/deep-bad-copy-reason.stderr
@@ -1,11 +1,11 @@
 error[E0204]: the trait `Copy` may not be implemented for this type
-  --> $DIR/deep-bad-copy-reason.rs:33:15
+  --> $DIR/deep-bad-copy-reason.rs:33:24
    |
 LL | pub struct List<'tcx, T>(Interned<'tcx, ListS<T>>);
    |                          ------------------------ this field does not implement `Copy`
 ...
 LL | impl<'tcx, T> Copy for List<'tcx, T> {}
-   |               ^^^^
+   |                        ^^^^^^^^^^^^^
    |
 note: the `Copy` impl for `Interned<'tcx, ListS<T>>` requires that `OpaqueListContents: Sized`
   --> $DIR/deep-bad-copy-reason.rs:23:26
diff --git a/src/test/ui/compare-method/issue-90444.stderr b/src/test/ui/compare-method/issue-90444.stderr
index 84bbec0623f..ee63f34b799 100644
--- a/src/test/ui/compare-method/issue-90444.stderr
+++ b/src/test/ui/compare-method/issue-90444.stderr
@@ -5,10 +5,10 @@ LL |     fn from(_: fn((), (), &mut ())) -> Self {
    |                ^^^^^^^^^^^^^^^^^^^
    |                |
    |                types differ in mutability
-   |                help: change the parameter type to match the trait: `for<'r> fn((), (), &'r ())`
+   |                help: change the parameter type to match the trait: `for<'a> fn((), (), &'a ())`
    |
-   = note: expected fn pointer `fn(for<'r> fn((), (), &'r ())) -> A`
-              found fn pointer `fn(for<'r> fn((), (), &'r mut ())) -> A`
+   = note: expected fn pointer `fn(for<'a> fn((), (), &'a ())) -> A`
+              found fn pointer `fn(for<'a> fn((), (), &'a mut ())) -> A`
 
 error[E0053]: method `from` has an incompatible type for trait
   --> $DIR/issue-90444.rs:11:16
diff --git a/src/test/ui/const-generics/const-generic-default-wont-borrowck.stderr b/src/test/ui/const-generics/const-generic-default-wont-borrowck.stderr
index c62f1d1d230..0ed370b83c5 100644
--- a/src/test/ui/const-generics/const-generic-default-wont-borrowck.stderr
+++ b/src/test/ui/const-generics/const-generic-default-wont-borrowck.stderr
@@ -5,6 +5,11 @@ LL |     let s: &'static str; s.len()
    |         -                ^^^^^^^ `*s` used here but it isn't initialized
    |         |
    |         binding declared here but left uninitialized
+   |
+help: consider assigning a value
+   |
+LL |     let s: &'static str = todo!(); s.len()
+   |                         +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/cast-discriminant-zst-enum.rs b/src/test/ui/consts/cast-discriminant-zst-enum.rs
index e59ae297da1..2767f178fb6 100644
--- a/src/test/ui/consts/cast-discriminant-zst-enum.rs
+++ b/src/test/ui/consts/cast-discriminant-zst-enum.rs
@@ -1,6 +1,5 @@
 // run-pass
 // Test a ZST enum whose dicriminant is ~0i128. This caused an ICE when casting to an i32.
-#![feature(bench_black_box)]
 use std::hint::black_box;
 
 #[derive(Copy, Clone)]
diff --git a/src/test/ui/consts/const-eval/const_let.rs b/src/test/ui/consts/const-eval/const_let.rs
index 18692dbced6..1e2bcc55b6b 100644
--- a/src/test/ui/consts/const-eval/const_let.rs
+++ b/src/test/ui/consts/const-eval/const_let.rs
@@ -14,16 +14,16 @@ const X2: FakeNeedsDrop = { let x; x = FakeNeedsDrop; x };
 
 // error
 const Y: FakeNeedsDrop = { let mut x = FakeNeedsDrop; x = FakeNeedsDrop; x };
-//~^ ERROR destructors cannot be evaluated at compile-time
+//~^ ERROR destructor of
 
 // error
 const Y2: FakeNeedsDrop = { let mut x; x = FakeNeedsDrop; x = FakeNeedsDrop; x };
-//~^ ERROR destructors cannot be evaluated at compile-time
+//~^ ERROR destructor of
 
 // error
 const Z: () = { let mut x = None; x = Some(FakeNeedsDrop); };
-//~^ ERROR destructors cannot be evaluated at compile-time
+//~^ ERROR destructor of
 
 // error
 const Z2: () = { let mut x; x = None; x = Some(FakeNeedsDrop); };
-//~^ ERROR destructors cannot be evaluated at compile-time
+//~^ ERROR destructor of
diff --git a/src/test/ui/consts/const-eval/const_let.stderr b/src/test/ui/consts/const-eval/const_let.stderr
index 47f39b703e4..63442f55718 100644
--- a/src/test/ui/consts/const-eval/const_let.stderr
+++ b/src/test/ui/consts/const-eval/const_let.stderr
@@ -1,34 +1,34 @@
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `FakeNeedsDrop` cannot be evaluated at compile-time
   --> $DIR/const_let.rs:16:32
    |
 LL | const Y: FakeNeedsDrop = { let mut x = FakeNeedsDrop; x = FakeNeedsDrop; x };
    |                                ^^^^^                  - value is dropped here
    |                                |
-   |                                constants cannot evaluate destructors
+   |                                the destructor for this type cannot be evaluated in constants
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `FakeNeedsDrop` cannot be evaluated at compile-time
   --> $DIR/const_let.rs:20:33
    |
 LL | const Y2: FakeNeedsDrop = { let mut x; x = FakeNeedsDrop; x = FakeNeedsDrop; x };
    |                                 ^^^^^                     - value is dropped here
    |                                 |
-   |                                 constants cannot evaluate destructors
+   |                                 the destructor for this type cannot be evaluated in constants
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `Option<FakeNeedsDrop>` cannot be evaluated at compile-time
   --> $DIR/const_let.rs:24:21
    |
 LL | const Z: () = { let mut x = None; x = Some(FakeNeedsDrop); };
    |                     ^^^^^                                  - value is dropped here
    |                     |
-   |                     constants cannot evaluate destructors
+   |                     the destructor for this type cannot be evaluated in constants
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `Option<FakeNeedsDrop>` cannot be evaluated at compile-time
   --> $DIR/const_let.rs:28:22
    |
 LL | const Z2: () = { let mut x; x = None; x = Some(FakeNeedsDrop); };
    |                      ^^^^^                                     - value is dropped here
    |                      |
-   |                      constants cannot evaluate destructors
+   |                      the destructor for this type cannot be evaluated in constants
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/consts/const-eval/issue-100878.rs b/src/test/ui/consts/const-eval/issue-100878.rs
new file mode 100644
index 00000000000..353ce505035
--- /dev/null
+++ b/src/test/ui/consts/const-eval/issue-100878.rs
@@ -0,0 +1,8 @@
+// This checks that the const-eval ICE in issue #100878 does not recur.
+//
+// build-pass
+pub fn bitshift_data(data: [u8; 1]) -> u8 {
+    data[0] << 8
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/const-eval/issue-65394.rs b/src/test/ui/consts/const-eval/issue-65394.rs
index 2518e4ed40b..e6639826cb2 100644
--- a/src/test/ui/consts/const-eval/issue-65394.rs
+++ b/src/test/ui/consts/const-eval/issue-65394.rs
@@ -4,7 +4,7 @@
 // We will likely have to change this behavior before we allow `&mut` in a `const`.
 
 const _: Vec<i32> = {
-    let mut x = Vec::<i32>::new(); //~ ERROR destructors cannot be evaluated at compile-time
+    let mut x = Vec::<i32>::new(); //~ ERROR destructor of
     let r = &mut x; //~ ERROR mutable references are not allowed in constants
     let y = x;
     y
diff --git a/src/test/ui/consts/const-eval/issue-65394.stderr b/src/test/ui/consts/const-eval/issue-65394.stderr
index ec229d7f53a..ae6f0e93716 100644
--- a/src/test/ui/consts/const-eval/issue-65394.stderr
+++ b/src/test/ui/consts/const-eval/issue-65394.stderr
@@ -7,11 +7,11 @@ LL |     let r = &mut x;
    = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `Vec<i32>` cannot be evaluated at compile-time
   --> $DIR/issue-65394.rs:7:9
    |
 LL |     let mut x = Vec::<i32>::new();
-   |         ^^^^^ constants cannot evaluate destructors
+   |         ^^^^^ the destructor for this type cannot be evaluated in constants
 ...
 LL | };
    | - value is dropped here
diff --git a/src/test/ui/consts/const-eval/livedrop.rs b/src/test/ui/consts/const-eval/livedrop.rs
index 66b7d058080..543f1f0ecee 100644
--- a/src/test/ui/consts/const-eval/livedrop.rs
+++ b/src/test/ui/consts/const-eval/livedrop.rs
@@ -1,6 +1,6 @@
 const _: Option<Vec<i32>> = {
     let mut never_returned = Some(Vec::new());
-    let mut always_returned = None; //~ ERROR destructors cannot be evaluated at compile-time
+    let mut always_returned = None; //~ ERROR destructor of
 
     let mut i = 0;
     loop {
diff --git a/src/test/ui/consts/const-eval/livedrop.stderr b/src/test/ui/consts/const-eval/livedrop.stderr
index 1e8b4230c6f..d04fdb70ed3 100644
--- a/src/test/ui/consts/const-eval/livedrop.stderr
+++ b/src/test/ui/consts/const-eval/livedrop.stderr
@@ -1,8 +1,8 @@
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `Option<Vec<i32>>` cannot be evaluated at compile-time
   --> $DIR/livedrop.rs:3:9
    |
 LL |     let mut always_returned = None;
-   |         ^^^^^^^^^^^^^^^^^^^ constants cannot evaluate destructors
+   |         ^^^^^^^^^^^^^^^^^^^ the destructor for this type cannot be evaluated in constants
 ...
 LL |         always_returned = never_returned;
    |         --------------- value is dropped here
diff --git a/src/test/ui/consts/const-eval/ub-enum.32bit.stderr b/src/test/ui/consts/const-eval/ub-enum.32bit.stderr
index 752fd01f338..80395e32db0 100644
--- a/src/test/ui/consts/const-eval/ub-enum.32bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-enum.32bit.stderr
@@ -1,5 +1,5 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-enum.rs:23:1
+  --> $DIR/ub-enum.rs:24:1
    |
 LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) };
    | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x00000001, but expected a valid enum tag
@@ -10,7 +10,7 @@ LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) };
            }
 
 error: any use of this value will cause an error
-  --> $DIR/ub-enum.rs:26:1
+  --> $DIR/ub-enum.rs:27:1
    |
 LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -22,7 +22,7 @@ LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error: any use of this value will cause an error
-  --> $DIR/ub-enum.rs:30:1
+  --> $DIR/ub-enum.rs:31:1
    |
 LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -33,7 +33,7 @@ LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-enum.rs:43:1
+  --> $DIR/ub-enum.rs:44:1
    |
 LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x00000000, but expected a valid enum tag
@@ -44,7 +44,7 @@ LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
            }
 
 error: any use of this value will cause an error
-  --> $DIR/ub-enum.rs:45:1
+  --> $DIR/ub-enum.rs:46:1
    |
 LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -55,7 +55,7 @@ LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error: any use of this value will cause an error
-  --> $DIR/ub-enum.rs:49:1
+  --> $DIR/ub-enum.rs:50:1
    |
 LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -66,13 +66,13 @@ LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-enum.rs:59:42
+  --> $DIR/ub-enum.rs:60:42
    |
 LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init };
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
 
 error: any use of this value will cause an error
-  --> $DIR/ub-enum.rs:64:1
+  --> $DIR/ub-enum.rs:65:1
    |
 LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -83,7 +83,7 @@ LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-enum.rs:82:1
+  --> $DIR/ub-enum.rs:83:1
    |
 LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(B)>.0: encountered a value of the never type `!`
@@ -94,7 +94,7 @@ LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-enum.rs:84:1
+  --> $DIR/ub-enum.rs:85:1
    |
 LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(D)>.0: encountered a value of uninhabited type Never
@@ -105,7 +105,7 @@ LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-enum.rs:92:1
+  --> $DIR/ub-enum.rs:93:1
    |
 LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) }));
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Some)>.0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
@@ -116,13 +116,13 @@ LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::tran
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-enum.rs:97:77
+  --> $DIR/ub-enum.rs:98:77
    |
 LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
    |                                                                             ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-enum.rs:99:77
+  --> $DIR/ub-enum.rs:100:77
    |
 LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
    |                                                                             ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
@@ -132,7 +132,7 @@ error: aborting due to 13 previous errors
 For more information about this error, try `rustc --explain E0080`.
 Future incompatibility report: Future breakage diagnostic:
 error: any use of this value will cause an error
-  --> $DIR/ub-enum.rs:26:1
+  --> $DIR/ub-enum.rs:27:1
    |
 LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -145,7 +145,7 @@ LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
-  --> $DIR/ub-enum.rs:30:1
+  --> $DIR/ub-enum.rs:31:1
    |
 LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -158,7 +158,7 @@ LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
-  --> $DIR/ub-enum.rs:45:1
+  --> $DIR/ub-enum.rs:46:1
    |
 LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -171,7 +171,7 @@ LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
-  --> $DIR/ub-enum.rs:49:1
+  --> $DIR/ub-enum.rs:50:1
    |
 LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -184,7 +184,7 @@ LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
-  --> $DIR/ub-enum.rs:64:1
+  --> $DIR/ub-enum.rs:65:1
    |
 LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
diff --git a/src/test/ui/consts/const-eval/ub-enum.64bit.stderr b/src/test/ui/consts/const-eval/ub-enum.64bit.stderr
index 3f1546a2786..d20f63a7289 100644
--- a/src/test/ui/consts/const-eval/ub-enum.64bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-enum.64bit.stderr
@@ -1,5 +1,5 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-enum.rs:23:1
+  --> $DIR/ub-enum.rs:24:1
    |
 LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) };
    | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x0000000000000001, but expected a valid enum tag
@@ -10,7 +10,7 @@ LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) };
            }
 
 error: any use of this value will cause an error
-  --> $DIR/ub-enum.rs:26:1
+  --> $DIR/ub-enum.rs:27:1
    |
 LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -22,7 +22,7 @@ LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error: any use of this value will cause an error
-  --> $DIR/ub-enum.rs:30:1
+  --> $DIR/ub-enum.rs:31:1
    |
 LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -33,7 +33,7 @@ LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-enum.rs:43:1
+  --> $DIR/ub-enum.rs:44:1
    |
 LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x0000000000000000, but expected a valid enum tag
@@ -44,7 +44,7 @@ LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
            }
 
 error: any use of this value will cause an error
-  --> $DIR/ub-enum.rs:45:1
+  --> $DIR/ub-enum.rs:46:1
    |
 LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -55,7 +55,7 @@ LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error: any use of this value will cause an error
-  --> $DIR/ub-enum.rs:49:1
+  --> $DIR/ub-enum.rs:50:1
    |
 LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -66,13 +66,13 @@ LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-enum.rs:59:42
+  --> $DIR/ub-enum.rs:60:42
    |
 LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init };
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
 
 error: any use of this value will cause an error
-  --> $DIR/ub-enum.rs:64:1
+  --> $DIR/ub-enum.rs:65:1
    |
 LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -83,7 +83,7 @@ LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-enum.rs:82:1
+  --> $DIR/ub-enum.rs:83:1
    |
 LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(B)>.0: encountered a value of the never type `!`
@@ -94,7 +94,7 @@ LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-enum.rs:84:1
+  --> $DIR/ub-enum.rs:85:1
    |
 LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(D)>.0: encountered a value of uninhabited type Never
@@ -105,7 +105,7 @@ LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-enum.rs:92:1
+  --> $DIR/ub-enum.rs:93:1
    |
 LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) }));
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Some)>.0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
@@ -116,13 +116,13 @@ LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::tran
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-enum.rs:97:77
+  --> $DIR/ub-enum.rs:98:77
    |
 LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
    |                                                                             ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-enum.rs:99:77
+  --> $DIR/ub-enum.rs:100:77
    |
 LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
    |                                                                             ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
@@ -132,7 +132,7 @@ error: aborting due to 13 previous errors
 For more information about this error, try `rustc --explain E0080`.
 Future incompatibility report: Future breakage diagnostic:
 error: any use of this value will cause an error
-  --> $DIR/ub-enum.rs:26:1
+  --> $DIR/ub-enum.rs:27:1
    |
 LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -145,7 +145,7 @@ LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
-  --> $DIR/ub-enum.rs:30:1
+  --> $DIR/ub-enum.rs:31:1
    |
 LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -158,7 +158,7 @@ LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
-  --> $DIR/ub-enum.rs:45:1
+  --> $DIR/ub-enum.rs:46:1
    |
 LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -171,7 +171,7 @@ LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
-  --> $DIR/ub-enum.rs:49:1
+  --> $DIR/ub-enum.rs:50:1
    |
 LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -184,7 +184,7 @@ LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
-  --> $DIR/ub-enum.rs:64:1
+  --> $DIR/ub-enum.rs:65:1
    |
 LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
diff --git a/src/test/ui/consts/const-eval/ub-enum.rs b/src/test/ui/consts/const-eval/ub-enum.rs
index d8dc6d057a7..9e1c28e2351 100644
--- a/src/test/ui/consts/const-eval/ub-enum.rs
+++ b/src/test/ui/consts/const-eval/ub-enum.rs
@@ -1,5 +1,6 @@
 // stderr-per-bitwidth
 #![feature(never_type)]
+#![allow(invalid_value)]
 
 use std::mem;
 
diff --git a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr
index bdaeb4a0fbe..b568518b449 100644
--- a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr
+++ b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr
@@ -40,11 +40,11 @@ LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
    |                                          this code causes undefined behavior when executed
    |                                          help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
    |
-note: enums with no variants have no valid value (in this struct field)
-  --> $DIR/validate_uninhabited_zsts.rs:16:22
+note: enums with no inhabited variants have no valid value
+  --> $DIR/validate_uninhabited_zsts.rs:13:5
    |
-LL |     pub struct Empty(Void);
-   |                      ^^^^
+LL |     enum Void {}
+   |     ^^^^^^^^^
 
 error: aborting due to 2 previous errors; 2 warnings emitted
 
diff --git a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr
index bdaeb4a0fbe..b568518b449 100644
--- a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr
+++ b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr
@@ -40,11 +40,11 @@ LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
    |                                          this code causes undefined behavior when executed
    |                                          help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
    |
-note: enums with no variants have no valid value (in this struct field)
-  --> $DIR/validate_uninhabited_zsts.rs:16:22
+note: enums with no inhabited variants have no valid value
+  --> $DIR/validate_uninhabited_zsts.rs:13:5
    |
-LL |     pub struct Empty(Void);
-   |                      ^^^^
+LL |     enum Void {}
+   |     ^^^^^^^^^
 
 error: aborting due to 2 previous errors; 2 warnings emitted
 
diff --git a/src/test/ui/consts/const_discriminant.rs b/src/test/ui/consts/const_discriminant.rs
index f623c5101f4..79e68590e85 100644
--- a/src/test/ui/consts/const_discriminant.rs
+++ b/src/test/ui/consts/const_discriminant.rs
@@ -1,6 +1,5 @@
 // run-pass
 #![feature(const_discriminant)]
-#![feature(bench_black_box)]
 #![allow(dead_code)]
 
 use std::mem::{discriminant, Discriminant};
diff --git a/src/test/ui/consts/control-flow/drop-fail.precise.stderr b/src/test/ui/consts/control-flow/drop-fail.precise.stderr
index 0b0b2443a4a..93b5f257efb 100644
--- a/src/test/ui/consts/control-flow/drop-fail.precise.stderr
+++ b/src/test/ui/consts/control-flow/drop-fail.precise.stderr
@@ -1,14 +1,14 @@
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `Option<Vec<i32>>` cannot be evaluated at compile-time
   --> $DIR/drop-fail.rs:8:9
    |
 LL |     let x = Some(Vec::new());
-   |         ^ constants cannot evaluate destructors
+   |         ^ the destructor for this type cannot be evaluated in constants
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `Option<Vec<i32>>` cannot be evaluated at compile-time
   --> $DIR/drop-fail.rs:39:9
    |
 LL |     let mut tmp = None;
-   |         ^^^^^^^ constants cannot evaluate destructors
+   |         ^^^^^^^ the destructor for this type cannot be evaluated in constants
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/consts/control-flow/drop-fail.rs b/src/test/ui/consts/control-flow/drop-fail.rs
index efa5a11c941..41341f3121e 100644
--- a/src/test/ui/consts/control-flow/drop-fail.rs
+++ b/src/test/ui/consts/control-flow/drop-fail.rs
@@ -6,7 +6,7 @@
 const _: Option<Vec<i32>> = {
     let y: Option<Vec<i32>> = None;
     let x = Some(Vec::new());
-    //[stock,precise]~^ ERROR destructors cannot be evaluated at compile-time
+    //[stock,precise]~^ ERROR destructor of
 
     if true {
         x
@@ -19,7 +19,7 @@ const _: Option<Vec<i32>> = {
 // existing analysis.
 const _: Vec<i32> = {
     let vec_tuple = (Vec::new(),);
-    //[stock]~^ ERROR destructors cannot be evaluated at compile-time
+    //[stock]~^ ERROR destructor of
 
     vec_tuple.0
 };
@@ -27,7 +27,7 @@ const _: Vec<i32> = {
 // This applies to single-field enum variants as well.
 const _: Vec<i32> = {
     let x: Result<_, Vec<i32>> = Ok(Vec::new());
-    //[stock]~^ ERROR destructors cannot be evaluated at compile-time
+    //[stock]~^ ERROR destructor of
 
     match x {
         Ok(x) | Err(x) => x,
@@ -37,7 +37,7 @@ const _: Vec<i32> = {
 const _: Option<Vec<i32>> = {
     let mut some = Some(Vec::new());
     let mut tmp = None;
-    //[stock,precise]~^ ERROR destructors cannot be evaluated at compile-time
+    //[stock,precise]~^ ERROR destructor of
 
     let mut i = 0;
     while i < 10 {
diff --git a/src/test/ui/consts/control-flow/drop-fail.stock.stderr b/src/test/ui/consts/control-flow/drop-fail.stock.stderr
index 72ca4fa08bc..2cc8568026e 100644
--- a/src/test/ui/consts/control-flow/drop-fail.stock.stderr
+++ b/src/test/ui/consts/control-flow/drop-fail.stock.stderr
@@ -1,35 +1,35 @@
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `Option<Vec<i32>>` cannot be evaluated at compile-time
   --> $DIR/drop-fail.rs:8:9
    |
 LL |     let x = Some(Vec::new());
-   |         ^ constants cannot evaluate destructors
+   |         ^ the destructor for this type cannot be evaluated in constants
 ...
 LL | };
    | - value is dropped here
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `(Vec<i32>,)` cannot be evaluated at compile-time
   --> $DIR/drop-fail.rs:21:9
    |
 LL |     let vec_tuple = (Vec::new(),);
-   |         ^^^^^^^^^ constants cannot evaluate destructors
+   |         ^^^^^^^^^ the destructor for this type cannot be evaluated in constants
 ...
 LL | };
    | - value is dropped here
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `Result<Vec<i32>, Vec<i32>>` cannot be evaluated at compile-time
   --> $DIR/drop-fail.rs:29:9
    |
 LL |     let x: Result<_, Vec<i32>> = Ok(Vec::new());
-   |         ^ constants cannot evaluate destructors
+   |         ^ the destructor for this type cannot be evaluated in constants
 ...
 LL | };
    | - value is dropped here
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `Option<Vec<i32>>` cannot be evaluated at compile-time
   --> $DIR/drop-fail.rs:39:9
    |
 LL |     let mut tmp = None;
-   |         ^^^^^^^ constants cannot evaluate destructors
+   |         ^^^^^^^ the destructor for this type cannot be evaluated in constants
 ...
 LL | };
    | - value is dropped here
diff --git a/src/test/ui/consts/drop_box.rs b/src/test/ui/consts/drop_box.rs
index 58a373a9673..67997413078 100644
--- a/src/test/ui/consts/drop_box.rs
+++ b/src/test/ui/consts/drop_box.rs
@@ -1,4 +1,4 @@
 const fn f<T>(_: Box<T>) {}
-//~^ ERROR destructors cannot be evaluated at compile-time
+//~^ ERROR destructor of
 
 fn main() {}
diff --git a/src/test/ui/consts/drop_box.stderr b/src/test/ui/consts/drop_box.stderr
index b9d6581e8ec..62324939b08 100644
--- a/src/test/ui/consts/drop_box.stderr
+++ b/src/test/ui/consts/drop_box.stderr
@@ -1,10 +1,10 @@
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `Box<T>` cannot be evaluated at compile-time
   --> $DIR/drop_box.rs:1:15
    |
 LL | const fn f<T>(_: Box<T>) {}
    |               ^           - value is dropped here
    |               |
-   |               constant functions cannot evaluate destructors
+   |               the destructor for this type cannot be evaluated in constant functions
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/drop_zst.stderr b/src/test/ui/consts/drop_zst.stderr
index d4be5aa56d9..37758a4cbda 100644
--- a/src/test/ui/consts/drop_zst.stderr
+++ b/src/test/ui/consts/drop_zst.stderr
@@ -1,8 +1,8 @@
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `S` cannot be evaluated at compile-time
   --> $DIR/drop_zst.rs:14:9
    |
 LL |     let s = S;
-   |         ^ constant functions cannot evaluate destructors
+   |         ^ the destructor for this type cannot be evaluated in constant functions
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/issue-78655.stderr b/src/test/ui/consts/issue-78655.stderr
index f5b1123e7f3..6b83fa0e5a0 100644
--- a/src/test/ui/consts/issue-78655.stderr
+++ b/src/test/ui/consts/issue-78655.stderr
@@ -5,6 +5,11 @@ LL |     let x;
    |         - binding declared here but left uninitialized
 LL |     &x
    |     ^^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x = 0;
+   |           +++
 
 error: could not evaluate constant pattern
   --> $DIR/issue-78655.rs:7:9
diff --git a/src/test/ui/consts/issue-88071.rs b/src/test/ui/consts/issue-88071.rs
index 1c38c43e6c0..f58cdb5945e 100644
--- a/src/test/ui/consts/issue-88071.rs
+++ b/src/test/ui/consts/issue-88071.rs
@@ -2,8 +2,6 @@
 //
 // regression test for #88071
 
-#![feature(const_btree_new)]
-
 use std::collections::BTreeMap;
 
 pub struct CustomMap<K, V>(BTreeMap<K, V>);
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.rs b/src/test/ui/consts/min_const_fn/min_const_fn.rs
index 0bafaf2e81f..c2891488c7f 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_fn.rs
@@ -34,7 +34,7 @@ const fn foo35(a: bool, b: bool) -> bool { a ^ b }
 struct Foo<T: ?Sized>(T);
 impl<T> Foo<T> {
     const fn new(t: T) -> Self { Foo(t) }
-    const fn into_inner(self) -> T { self.0 } //~ destructors cannot be evaluated
+    const fn into_inner(self) -> T { self.0 } //~ destructor of
     const fn get(&self) -> &T { &self.0 }
     const fn get_mut(&mut self) -> &mut T { &mut self.0 }
     //~^ mutable references
@@ -43,7 +43,7 @@ impl<T> Foo<T> {
 }
 impl<'a, T> Foo<T> {
     const fn new_lt(t: T) -> Self { Foo(t) }
-    const fn into_inner_lt(self) -> T { self.0 } //~ destructors cannot be evaluated
+    const fn into_inner_lt(self) -> T { self.0 } //~ destructor of
     const fn get_lt(&'a self) -> &T { &self.0 }
     const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 }
     //~^ mutable references
@@ -52,7 +52,7 @@ impl<'a, T> Foo<T> {
 }
 impl<T: Sized> Foo<T> {
     const fn new_s(t: T) -> Self { Foo(t) }
-    const fn into_inner_s(self) -> T { self.0 } //~ ERROR destructors
+    const fn into_inner_s(self) -> T { self.0 } //~ ERROR destructor
     const fn get_s(&self) -> &T { &self.0 }
     const fn get_mut_s(&mut self) -> &mut T { &mut self.0 }
     //~^ mutable references
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.stderr
index 4ad17602c84..11c79e8e2d6 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_fn.stderr
@@ -1,10 +1,10 @@
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `Foo<T>` cannot be evaluated at compile-time
   --> $DIR/min_const_fn.rs:37:25
    |
 LL |     const fn into_inner(self) -> T { self.0 }
    |                         ^^^^                - value is dropped here
    |                         |
-   |                         constant functions cannot evaluate destructors
+   |                         the destructor for this type cannot be evaluated in constant functions
 
 error[E0658]: mutable references are not allowed in constant functions
   --> $DIR/min_const_fn.rs:39:22
@@ -33,13 +33,13 @@ LL |     const fn get_mut(&mut self) -> &mut T { &mut self.0 }
    = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `Foo<T>` cannot be evaluated at compile-time
   --> $DIR/min_const_fn.rs:46:28
    |
 LL |     const fn into_inner_lt(self) -> T { self.0 }
    |                            ^^^^                - value is dropped here
    |                            |
-   |                            constant functions cannot evaluate destructors
+   |                            the destructor for this type cannot be evaluated in constant functions
 
 error[E0658]: mutable references are not allowed in constant functions
   --> $DIR/min_const_fn.rs:48:25
@@ -68,13 +68,13 @@ LL |     const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 }
    = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `Foo<T>` cannot be evaluated at compile-time
   --> $DIR/min_const_fn.rs:55:27
    |
 LL |     const fn into_inner_s(self) -> T { self.0 }
    |                           ^^^^                - value is dropped here
    |                           |
-   |                           constant functions cannot evaluate destructors
+   |                           the destructor for this type cannot be evaluated in constant functions
 
 error[E0658]: mutable references are not allowed in constant functions
   --> $DIR/min_const_fn.rs:57:24
@@ -191,21 +191,21 @@ LL | const fn inc(x: &mut i32) { *x += 1 }
    = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `AlanTuring<impl std::fmt::Debug>` cannot be evaluated at compile-time
   --> $DIR/min_const_fn.rs:122:19
    |
 LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
    |                   ^^                                     - value is dropped here
    |                   |
-   |                   constant functions cannot evaluate destructors
+   |                   the destructor for this type cannot be evaluated in constant functions
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `impl std::fmt::Debug` cannot be evaluated at compile-time
   --> $DIR/min_const_fn.rs:124:18
    |
 LL | const fn no_apit(_x: impl std::fmt::Debug) {}
    |                  ^^                         - value is dropped here
    |                  |
-   |                  constant functions cannot evaluate destructors
+   |                  the destructor for this type cannot be evaluated in constant functions
 
 error: aborting due to 24 previous errors
 
diff --git a/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.rs b/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.rs
index 8b17f6885ad..4466f097ef4 100644
--- a/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.rs
+++ b/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.rs
@@ -8,7 +8,7 @@ trait Foo<T> {
 }
 
 trait Bar<T, U: Foo<T>> {
-    const F: u32 = (U::X, 42).1; //~ ERROR destructors cannot be evaluated at compile-time
+    const F: u32 = (U::X, 42).1; //~ ERROR destructor of
 }
 
 impl Foo<u32> for () {
diff --git a/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr b/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr
index 0b6cb2fab46..c91c72d1fbf 100644
--- a/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr
+++ b/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr
@@ -1,10 +1,10 @@
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `(T, u32)` cannot be evaluated at compile-time
   --> $DIR/feature-gate-unleash_the_miri_inside_of_you.rs:11:20
    |
 LL |     const F: u32 = (U::X, 42).1;
    |                    ^^^^^^^^^^ - value is dropped here
    |                    |
-   |                    constants cannot evaluate destructors
+   |                    the destructor for this type cannot be evaluated in constants
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/qualif-indirect-mutation-fail.rs b/src/test/ui/consts/qualif-indirect-mutation-fail.rs
index f74a25a346f..a6d2934044a 100644
--- a/src/test/ui/consts/qualif-indirect-mutation-fail.rs
+++ b/src/test/ui/consts/qualif-indirect-mutation-fail.rs
@@ -6,13 +6,13 @@
 
 // Mutable borrow of a field with drop impl.
 pub const fn f() {
-    let mut a: (u32, Option<String>) = (0, None); //~ ERROR destructors cannot be evaluated
+    let mut a: (u32, Option<String>) = (0, None); //~ ERROR destructor of
     let _ = &mut a.1;
 }
 
 // Mutable borrow of a type with drop impl.
 pub const A1: () = {
-    let mut x = None; //~ ERROR destructors cannot be evaluated
+    let mut x = None; //~ ERROR destructor of
     let mut y = Some(String::new());
     let a = &mut x;
     let b = &mut y;
@@ -28,12 +28,12 @@ pub const A2: () = {
     let b = &mut y;
     std::mem::swap(a, b);
     std::mem::forget(y);
-    let _z = x; //~ ERROR destructors cannot be evaluated
+    let _z = x; //~ ERROR destructor of
 };
 
 // Shared borrow of a type that might be !Freeze and Drop.
 pub const fn g1<T>() {
-    let x: Option<T> = None; //~ ERROR destructors cannot be evaluated
+    let x: Option<T> = None; //~ ERROR destructor of
     let _ = x.is_some();
 }
 
@@ -41,24 +41,24 @@ pub const fn g1<T>() {
 pub const fn g2<T>() {
     let x: Option<T> = None;
     let _ = x.is_some();
-    let _y = x; //~ ERROR destructors cannot be evaluated
+    let _y = x; //~ ERROR destructor of
 }
 
 // Mutable raw reference to a Drop type.
 pub const fn address_of_mut() {
-    let mut x: Option<String> = None; //~ ERROR destructors cannot be evaluated
+    let mut x: Option<String> = None; //~ ERROR destructor of
     &raw mut x;
 
-    let mut y: Option<String> = None; //~ ERROR destructors cannot be evaluated
+    let mut y: Option<String> = None; //~ ERROR destructor of
     std::ptr::addr_of_mut!(y);
 }
 
 // Const raw reference to a Drop type. Conservatively assumed to allow mutation
 // until resolution of https://github.com/rust-lang/rust/issues/56604.
 pub const fn address_of_const() {
-    let x: Option<String> = None; //~ ERROR destructors cannot be evaluated
+    let x: Option<String> = None; //~ ERROR destructor of
     &raw const x;
 
-    let y: Option<String> = None; //~ ERROR destructors cannot be evaluated
+    let y: Option<String> = None; //~ ERROR destructor of
     std::ptr::addr_of!(y);
 }
diff --git a/src/test/ui/consts/qualif-indirect-mutation-fail.stderr b/src/test/ui/consts/qualif-indirect-mutation-fail.stderr
index 713df12b7a5..6379c00e4b4 100644
--- a/src/test/ui/consts/qualif-indirect-mutation-fail.stderr
+++ b/src/test/ui/consts/qualif-indirect-mutation-fail.stderr
@@ -1,56 +1,56 @@
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `(u32, Option<String>)` cannot be evaluated at compile-time
   --> $DIR/qualif-indirect-mutation-fail.rs:9:9
    |
 LL |     let mut a: (u32, Option<String>) = (0, None);
-   |         ^^^^^ constant functions cannot evaluate destructors
+   |         ^^^^^ the destructor for this type cannot be evaluated in constant functions
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time
   --> $DIR/qualif-indirect-mutation-fail.rs:15:9
    |
 LL |     let mut x = None;
-   |         ^^^^^ constants cannot evaluate destructors
+   |         ^^^^^ the destructor for this type cannot be evaluated in constants
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time
   --> $DIR/qualif-indirect-mutation-fail.rs:31:9
    |
 LL |     let _z = x;
-   |         ^^ constants cannot evaluate destructors
+   |         ^^ the destructor for this type cannot be evaluated in constants
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `Option<T>` cannot be evaluated at compile-time
   --> $DIR/qualif-indirect-mutation-fail.rs:36:9
    |
 LL |     let x: Option<T> = None;
-   |         ^ constant functions cannot evaluate destructors
+   |         ^ the destructor for this type cannot be evaluated in constant functions
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `Option<T>` cannot be evaluated at compile-time
   --> $DIR/qualif-indirect-mutation-fail.rs:44:9
    |
 LL |     let _y = x;
-   |         ^^ constant functions cannot evaluate destructors
+   |         ^^ the destructor for this type cannot be evaluated in constant functions
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time
   --> $DIR/qualif-indirect-mutation-fail.rs:52:9
    |
 LL |     let mut y: Option<String> = None;
-   |         ^^^^^ constant functions cannot evaluate destructors
+   |         ^^^^^ the destructor for this type cannot be evaluated in constant functions
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time
   --> $DIR/qualif-indirect-mutation-fail.rs:49:9
    |
 LL |     let mut x: Option<String> = None;
-   |         ^^^^^ constant functions cannot evaluate destructors
+   |         ^^^^^ the destructor for this type cannot be evaluated in constant functions
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time
   --> $DIR/qualif-indirect-mutation-fail.rs:62:9
    |
 LL |     let y: Option<String> = None;
-   |         ^ constant functions cannot evaluate destructors
+   |         ^ the destructor for this type cannot be evaluated in constant functions
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time
   --> $DIR/qualif-indirect-mutation-fail.rs:59:9
    |
 LL |     let x: Option<String> = None;
-   |         ^ constant functions cannot evaluate destructors
+   |         ^ the destructor for this type cannot be evaluated in constant functions
 
 error: aborting due to 9 previous errors
 
diff --git a/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs b/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs
index 2b970390f03..7cd3dbec931 100644
--- a/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs
+++ b/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs
@@ -11,7 +11,7 @@ impl<T> Either<T, T> {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "foo", since = "1.0.0")]
     pub const fn unwrap(self) -> T {
-        //~^ ERROR destructors cannot be evaluated at compile-time
+        //~^ ERROR destructor of
         match self {
             Self::Left(t) => t,
             Self::Right(t) => t,
diff --git a/src/test/ui/consts/stable-precise-live-drops-in-libcore.stderr b/src/test/ui/consts/stable-precise-live-drops-in-libcore.stderr
index a3f513541dd..5f70391eec2 100644
--- a/src/test/ui/consts/stable-precise-live-drops-in-libcore.stderr
+++ b/src/test/ui/consts/stable-precise-live-drops-in-libcore.stderr
@@ -1,8 +1,8 @@
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `Either<T, T>` cannot be evaluated at compile-time
   --> $DIR/stable-precise-live-drops-in-libcore.rs:13:25
    |
 LL |     pub const fn unwrap(self) -> T {
-   |                         ^^^^ constant functions cannot evaluate destructors
+   |                         ^^^^ the destructor for this type cannot be evaluated in constant functions
 ...
 LL |     }
    |     - value is dropped here
diff --git a/src/test/ui/consts/unstable-const-fn-in-libcore.rs b/src/test/ui/consts/unstable-const-fn-in-libcore.rs
index b9e7e1405f9..ca4ed8f0b47 100644
--- a/src/test/ui/consts/unstable-const-fn-in-libcore.rs
+++ b/src/test/ui/consts/unstable-const-fn-in-libcore.rs
@@ -15,8 +15,8 @@ impl<T> Opt<T> {
     #[rustc_const_unstable(feature = "foo", issue = "none")]
     #[stable(feature = "rust1", since = "1.0.0")]
     const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T {
-    //~^ ERROR destructors cannot be evaluated at compile-time
-    //~| ERROR destructors cannot be evaluated at compile-time
+    //~^ ERROR destructor of
+    //~| ERROR destructor of
         match self {
             Opt::Some(t) => t,
             Opt::None => f(),
diff --git a/src/test/ui/consts/unstable-const-fn-in-libcore.stderr b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr
index fee74bd0a6c..e5b00dd07ab 100644
--- a/src/test/ui/consts/unstable-const-fn-in-libcore.stderr
+++ b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr
@@ -1,17 +1,17 @@
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `F` cannot be evaluated at compile-time
   --> $DIR/unstable-const-fn-in-libcore.rs:17:60
    |
 LL |     const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T {
-   |                                                            ^ constant functions cannot evaluate destructors
+   |                                                            ^ the destructor for this type cannot be evaluated in constant functions
 ...
 LL |     }
    |     - value is dropped here
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `Opt<T>` cannot be evaluated at compile-time
   --> $DIR/unstable-const-fn-in-libcore.rs:17:54
    |
 LL |     const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T {
-   |                                                      ^^^^ constant functions cannot evaluate destructors
+   |                                                      ^^^^ the destructor for this type cannot be evaluated in constant functions
 ...
 LL |     }
    |     - value is dropped here
diff --git a/src/test/ui/drop/repeat-drop-2.rs b/src/test/ui/drop/repeat-drop-2.rs
index 59d5ef20205..3cfacea5e17 100644
--- a/src/test/ui/drop/repeat-drop-2.rs
+++ b/src/test/ui/drop/repeat-drop-2.rs
@@ -5,7 +5,7 @@ fn borrowck_catch() {
 }
 
 const _: [String; 0] = [String::new(); 0];
-//~^ ERROR destructors cannot be evaluated at compile-time [E0493]
+//~^ ERROR destructor of `String` cannot be evaluated at compile-time [E0493]
 
 fn must_be_init() {
     let x: u8;
diff --git a/src/test/ui/drop/repeat-drop-2.stderr b/src/test/ui/drop/repeat-drop-2.stderr
index 48fa2bfa975..7357551c4a7 100644
--- a/src/test/ui/drop/repeat-drop-2.stderr
+++ b/src/test/ui/drop/repeat-drop-2.stderr
@@ -8,13 +8,13 @@ LL |     let _bar = foo;
 LL |     let _baz = [foo; 0];
    |                 ^^^ value used here after move
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `String` cannot be evaluated at compile-time
   --> $DIR/repeat-drop-2.rs:7:25
    |
 LL | const _: [String; 0] = [String::new(); 0];
    |                        -^^^^^^^^^^^^^----
    |                        ||
-   |                        |constants cannot evaluate destructors
+   |                        |the destructor for this type cannot be evaluated in constants
    |                        value is dropped here
 
 error[E0381]: used binding `x` isn't initialized
@@ -24,6 +24,11 @@ LL |     let x: u8;
    |         - binding declared here but left uninitialized
 LL |     let _ = [x; 0];
    |              ^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x: u8 = 0;
+   |               +++
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/error-codes/E0094.rs b/src/test/ui/error-codes/E0094.rs
index 0d58e5a2862..a2ec932c124 100644
--- a/src/test/ui/error-codes/E0094.rs
+++ b/src/test/ui/error-codes/E0094.rs
@@ -1,5 +1,7 @@
 #![feature(intrinsics)]
+
 extern "rust-intrinsic" {
+    #[rustc_safe_intrinsic]
     fn size_of<T, U>() -> usize; //~ ERROR E0094
 }
 
diff --git a/src/test/ui/error-codes/E0094.stderr b/src/test/ui/error-codes/E0094.stderr
index da97f3a014b..531cd4c784d 100644
--- a/src/test/ui/error-codes/E0094.stderr
+++ b/src/test/ui/error-codes/E0094.stderr
@@ -1,5 +1,5 @@
 error[E0094]: intrinsic has wrong number of type parameters: found 2, expected 1
-  --> $DIR/E0094.rs:3:15
+  --> $DIR/E0094.rs:5:15
    |
 LL |     fn size_of<T, U>() -> usize;
    |               ^^^^^^ expected 1 type parameter
diff --git a/src/test/ui/error-codes/E0308.rs b/src/test/ui/error-codes/E0308.rs
index fa79bee570e..dd9e0b284ea 100644
--- a/src/test/ui/error-codes/E0308.rs
+++ b/src/test/ui/error-codes/E0308.rs
@@ -1,6 +1,8 @@
 #![feature(intrinsics)]
+#![feature(rustc_attrs)]
 
 extern "rust-intrinsic" {
+    #[rustc_safe_intrinsic]
     fn size_of<T>(); //~ ERROR E0308
 }
 
diff --git a/src/test/ui/error-codes/E0308.stderr b/src/test/ui/error-codes/E0308.stderr
index b71fb95e706..187b775f92d 100644
--- a/src/test/ui/error-codes/E0308.stderr
+++ b/src/test/ui/error-codes/E0308.stderr
@@ -1,5 +1,5 @@
 error[E0308]: intrinsic has wrong type
-  --> $DIR/E0308.rs:4:5
+  --> $DIR/E0308.rs:6:5
    |
 LL |     fn size_of<T>();
    |     ^^^^^^^^^^^^^^^^ expected `()`, found `usize`
diff --git a/src/test/ui/error-codes/E0311.rs b/src/test/ui/error-codes/E0311.rs
new file mode 100644
index 00000000000..566b518b433
--- /dev/null
+++ b/src/test/ui/error-codes/E0311.rs
@@ -0,0 +1,9 @@
+fn no_restriction<T>(x: &()) -> &() {
+    with_restriction::<T>(x) //~ ERROR E0311
+}
+
+fn with_restriction<'a, T: 'a>(x: &'a ()) -> &'a () {
+    x
+}
+
+fn main() {}
diff --git a/src/test/ui/error-codes/E0311.stderr b/src/test/ui/error-codes/E0311.stderr
new file mode 100644
index 00000000000..9873b5ae6ff
--- /dev/null
+++ b/src/test/ui/error-codes/E0311.stderr
@@ -0,0 +1,24 @@
+error[E0311]: the parameter type `T` may not live long enough
+  --> $DIR/E0311.rs:2:5
+   |
+LL |     with_restriction::<T>(x)
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the parameter type `T` must be valid for the anonymous lifetime defined here...
+  --> $DIR/E0311.rs:1:25
+   |
+LL | fn no_restriction<T>(x: &()) -> &() {
+   |                         ^^^
+note: ...so that the type `T` will meet its required lifetime bounds
+  --> $DIR/E0311.rs:2:5
+   |
+LL |     with_restriction::<T>(x)
+   |     ^^^^^^^^^^^^^^^^^^^^^
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn no_restriction<'a, T: 'a>(x: &()) -> &() {
+   |                   +++  ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0311`.
diff --git a/src/test/ui/error-codes/E0585.stderr b/src/test/ui/error-codes/E0585.stderr
index 7a31c4896ee..53c82fb416b 100644
--- a/src/test/ui/error-codes/E0585.stderr
+++ b/src/test/ui/error-codes/E0585.stderr
@@ -4,7 +4,7 @@ error[E0585]: found a documentation comment that doesn't document anything
 LL |     /// Hello! I'm useless...
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: doc comments must come before what they document, maybe a comment was intended with `//`?
+   = help: doc comments must come before what they document, if a comment was intended use `//`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/extenv/issue-55897.rs b/src/test/ui/extenv/issue-55897.rs
index 64c4107e898..b7533f41351 100644
--- a/src/test/ui/extenv/issue-55897.rs
+++ b/src/test/ui/extenv/issue-55897.rs
@@ -14,7 +14,7 @@ mod nonexistent_env {
 
 mod erroneous_literal {
     include!(concat!("NON_EXISTENT"suffix, "/data.rs"));
-    //~^ ERROR suffixes on a string literal are invalid
+    //~^ ERROR suffixes on string literals are invalid
 }
 
 fn main() {}
diff --git a/src/test/ui/extenv/issue-55897.stderr b/src/test/ui/extenv/issue-55897.stderr
index d2ac0b83016..e2afe6f34c1 100644
--- a/src/test/ui/extenv/issue-55897.stderr
+++ b/src/test/ui/extenv/issue-55897.stderr
@@ -6,7 +6,7 @@ LL |     include!(concat!(env!("NON_EXISTENT"), "/data.rs"));
    |
    = note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: suffixes on a string literal are invalid
+error: suffixes on string literals are invalid
   --> $DIR/issue-55897.rs:16:22
    |
 LL |     include!(concat!("NON_EXISTENT"suffix, "/data.rs"));
diff --git a/src/test/ui/extern/extern-with-type-bounds.rs b/src/test/ui/extern/extern-with-type-bounds.rs
index 8f9683e4a74..a72aa4171a1 100644
--- a/src/test/ui/extern/extern-with-type-bounds.rs
+++ b/src/test/ui/extern/extern-with-type-bounds.rs
@@ -2,6 +2,7 @@
 
 extern "rust-intrinsic" {
     // Real example from libcore
+    #[rustc_safe_intrinsic]
     fn type_id<T: ?Sized + 'static>() -> u64;
 
     // Silent bounds made explicit to make sure they are actually
@@ -10,6 +11,7 @@ extern "rust-intrinsic" {
 
     // Bounds aren't checked right now, so this should work
     // even though it's incorrect.
+    #[rustc_safe_intrinsic]
     fn size_of<T: Clone>() -> usize;
 
     // Unresolved bounds should still error.
diff --git a/src/test/ui/extern/extern-with-type-bounds.stderr b/src/test/ui/extern/extern-with-type-bounds.stderr
index acd0596422f..88be1e5dd3d 100644
--- a/src/test/ui/extern/extern-with-type-bounds.stderr
+++ b/src/test/ui/extern/extern-with-type-bounds.stderr
@@ -1,5 +1,5 @@
 error[E0405]: cannot find trait `NoSuchTrait` in this scope
-  --> $DIR/extern-with-type-bounds.rs:16:20
+  --> $DIR/extern-with-type-bounds.rs:18:20
    |
 LL |     fn align_of<T: NoSuchTrait>() -> usize;
    |                    ^^^^^^^^^^^ not found in this scope
diff --git a/src/test/ui/fmt/format-args-capture-issue-102057.rs b/src/test/ui/fmt/format-args-capture-issue-102057.rs
new file mode 100644
index 00000000000..b8089d49bcb
--- /dev/null
+++ b/src/test/ui/fmt/format-args-capture-issue-102057.rs
@@ -0,0 +1,19 @@
+fn main() {
+    format!("\x7Ba}");
+    //~^ ERROR cannot find value `a` in this scope
+    format!("\x7Ba\x7D");
+    //~^ ERROR cannot find value `a` in this scope
+
+    let a = 0;
+
+    format!("\x7Ba} {b}");
+    //~^ ERROR cannot find value `b` in this scope
+    format!("\x7Ba\x7D {b}");
+    //~^ ERROR cannot find value `b` in this scope
+    format!("\x7Ba} \x7Bb}");
+    //~^ ERROR cannot find value `b` in this scope
+    format!("\x7Ba\x7D \x7Bb}");
+    //~^ ERROR cannot find value `b` in this scope
+    format!("\x7Ba\x7D \x7Bb\x7D");
+    //~^ ERROR cannot find value `b` in this scope
+}
diff --git a/src/test/ui/fmt/format-args-capture-issue-102057.stderr b/src/test/ui/fmt/format-args-capture-issue-102057.stderr
new file mode 100644
index 00000000000..f2d625e7f8d
--- /dev/null
+++ b/src/test/ui/fmt/format-args-capture-issue-102057.stderr
@@ -0,0 +1,45 @@
+error[E0425]: cannot find value `a` in this scope
+  --> $DIR/format-args-capture-issue-102057.rs:2:18
+   |
+LL |     format!("\x7Ba}");
+   |                  ^ not found in this scope
+
+error[E0425]: cannot find value `a` in this scope
+  --> $DIR/format-args-capture-issue-102057.rs:4:18
+   |
+LL |     format!("\x7Ba\x7D");
+   |                  ^ not found in this scope
+
+error[E0425]: cannot find value `b` in this scope
+  --> $DIR/format-args-capture-issue-102057.rs:9:22
+   |
+LL |     format!("\x7Ba} {b}");
+   |                      ^ help: a local variable with a similar name exists: `a`
+
+error[E0425]: cannot find value `b` in this scope
+  --> $DIR/format-args-capture-issue-102057.rs:11:25
+   |
+LL |     format!("\x7Ba\x7D {b}");
+   |                         ^ help: a local variable with a similar name exists: `a`
+
+error[E0425]: cannot find value `b` in this scope
+  --> $DIR/format-args-capture-issue-102057.rs:13:25
+   |
+LL |     format!("\x7Ba} \x7Bb}");
+   |                         ^ help: a local variable with a similar name exists: `a`
+
+error[E0425]: cannot find value `b` in this scope
+  --> $DIR/format-args-capture-issue-102057.rs:15:28
+   |
+LL |     format!("\x7Ba\x7D \x7Bb}");
+   |                            ^ help: a local variable with a similar name exists: `a`
+
+error[E0425]: cannot find value `b` in this scope
+  --> $DIR/format-args-capture-issue-102057.rs:17:28
+   |
+LL |     format!("\x7Ba\x7D \x7Bb\x7D");
+   |                            ^ help: a local variable with a similar name exists: `a`
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/fmt/format-args-capture-issue-93378.rs b/src/test/ui/fmt/format-args-capture-issue-93378.rs
index 67444444264..9d722a0287a 100644
--- a/src/test/ui/fmt/format-args-capture-issue-93378.rs
+++ b/src/test/ui/fmt/format-args-capture-issue-93378.rs
@@ -3,9 +3,9 @@ fn main() {
     let b = "b";
 
     println!("{a} {b} {} {} {c} {}", c = "c");
-    //~^ ERROR: invalid reference to positional arguments 1 and 2 (there is 1 argument)
+    //~^ ERROR: 3 positional arguments in format string, but there is 1 argument
 
     let n = 1;
     println!("{a:.n$} {b:.*}");
-    //~^ ERROR: invalid reference to positional argument 0 (no arguments were given)
+    //~^ ERROR: 1 positional argument in format string, but no arguments were given
 }
diff --git a/src/test/ui/fmt/format-args-capture-issue-93378.stderr b/src/test/ui/fmt/format-args-capture-issue-93378.stderr
index b8e2b2afb38..6429b0d46f6 100644
--- a/src/test/ui/fmt/format-args-capture-issue-93378.stderr
+++ b/src/test/ui/fmt/format-args-capture-issue-93378.stderr
@@ -1,19 +1,14 @@
-error: invalid reference to positional arguments 1 and 2 (there is 1 argument)
-  --> $DIR/format-args-capture-issue-93378.rs:5:26
+error: 3 positional arguments in format string, but there is 1 argument
+  --> $DIR/format-args-capture-issue-93378.rs:5:23
    |
 LL |     println!("{a} {b} {} {} {c} {}", c = "c");
-   |                          ^^     ^^
-   |
-   = note: positional arguments are zero-based
+   |                       ^^ ^^     ^^       ---
 
-error: invalid reference to positional argument 0 (no arguments were given)
-  --> $DIR/format-args-capture-issue-93378.rs:9:23
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/format-args-capture-issue-93378.rs:9:26
    |
 LL |     println!("{a:.n$} {b:.*}");
-   |                   -   ^^^--^
-   |                   |      |
-   |                   |      this precision flag adds an extra required argument at position 0, which is why there are 3 arguments expected
-   |                   this parameter corresponds to the precision flag
+   |                          ^^ this precision flag adds an extra required argument at position 0, which is why there is 1 argument expected
    |
    = note: positional arguments are zero-based
    = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
diff --git a/src/test/ui/fmt/ifmt-bad-arg.rs b/src/test/ui/fmt/ifmt-bad-arg.rs
index f00cb05c9eb..68861d7bf3f 100644
--- a/src/test/ui/fmt/ifmt-bad-arg.rs
+++ b/src/test/ui/fmt/ifmt-bad-arg.rs
@@ -20,9 +20,9 @@ fn main() {
     //~^ ERROR: invalid reference to positional argument 2 (there are 2 arguments)
 
     format!("{} {value} {} {}", 1, value=2);
-    //~^ ERROR: invalid reference to positional argument 2 (there are 2 arguments)
+    //~^ ERROR: 3 positional arguments in format string, but there are 2 arguments
     format!("{name} {value} {} {} {} {} {} {}", 0, name=1, value=2);
-    //~^ ERROR: invalid reference to positional arguments 3, 4 and 5 (there are 3 arguments)
+    //~^ ERROR: 6 positional arguments in format string, but there are 3 arguments
 
     format!("{} {foo} {} {bar} {}", 1, 2, 3);
     //~^ ERROR: cannot find value `foo` in this scope
@@ -79,7 +79,7 @@ tenth number: {}",
     //~^ ERROR 4 positional arguments in format string, but there are 3 arguments
     //~| ERROR mismatched types
     println!("{} {:07$.*} {}", 1, 3.2, 4);
-    //~^ ERROR 4 positional arguments in format string, but there are 3 arguments
+    //~^ ERROR invalid reference to positional arguments 3 and 7 (there are 3 arguments)
     //~| ERROR mismatched types
     println!("{} {:07$} {}", 1, 3.2, 4);
     //~^ ERROR invalid reference to positional argument 7 (there are 3 arguments)
@@ -95,5 +95,5 @@ tenth number: {}",
     println!("{:.*}");
     //~^ ERROR 2 positional arguments in format string, but no arguments were given
     println!("{:.0$}");
-    //~^ ERROR 1 positional argument in format string, but no arguments were given
+    //~^ ERROR invalid reference to positional argument 0 (no arguments were given)
 }
diff --git a/src/test/ui/fmt/ifmt-bad-arg.stderr b/src/test/ui/fmt/ifmt-bad-arg.stderr
index dbb4bc6d937..1b595a50e99 100644
--- a/src/test/ui/fmt/ifmt-bad-arg.stderr
+++ b/src/test/ui/fmt/ifmt-bad-arg.stderr
@@ -5,10 +5,10 @@ LL |     format!("{}");
    |              ^^
 
 error: invalid reference to positional argument 1 (there is 1 argument)
-  --> $DIR/ifmt-bad-arg.rs:9:14
+  --> $DIR/ifmt-bad-arg.rs:9:15
    |
 LL |     format!("{1}", 1);
-   |              ^^^
+   |               ^
    |
    = note: positional arguments are zero-based
 
@@ -27,36 +27,32 @@ LL |     format!("{} {}");
    |              ^^ ^^
 
 error: invalid reference to positional argument 1 (there is 1 argument)
-  --> $DIR/ifmt-bad-arg.rs:16:18
+  --> $DIR/ifmt-bad-arg.rs:16:19
    |
 LL |     format!("{0} {1}", 1);
-   |                  ^^^
+   |                   ^
    |
    = note: positional arguments are zero-based
 
 error: invalid reference to positional argument 2 (there are 2 arguments)
-  --> $DIR/ifmt-bad-arg.rs:19:22
+  --> $DIR/ifmt-bad-arg.rs:19:23
    |
 LL |     format!("{0} {1} {2}", 1, 2);
-   |                      ^^^
+   |                       ^
    |
    = note: positional arguments are zero-based
 
-error: invalid reference to positional argument 2 (there are 2 arguments)
-  --> $DIR/ifmt-bad-arg.rs:22:28
+error: 3 positional arguments in format string, but there are 2 arguments
+  --> $DIR/ifmt-bad-arg.rs:22:14
    |
 LL |     format!("{} {value} {} {}", 1, value=2);
-   |                            ^^
-   |
-   = note: positional arguments are zero-based
+   |              ^^         ^^ ^^   -        -
 
-error: invalid reference to positional arguments 3, 4 and 5 (there are 3 arguments)
-  --> $DIR/ifmt-bad-arg.rs:24:38
+error: 6 positional arguments in format string, but there are 3 arguments
+  --> $DIR/ifmt-bad-arg.rs:24:29
    |
 LL |     format!("{name} {value} {} {} {} {} {} {}", 0, name=1, value=2);
-   |                                      ^^ ^^ ^^
-   |
-   = note: positional arguments are zero-based
+   |                             ^^ ^^ ^^ ^^ ^^ ^^   -       -        -
 
 error: multiple unused formatting arguments
   --> $DIR/ifmt-bad-arg.rs:32:17
@@ -117,20 +113,20 @@ LL |     format!("{} {}", 1, 2, foo=1, bar=2);
    |             multiple missing formatting specifiers
 
 error: duplicate argument named `foo`
-  --> $DIR/ifmt-bad-arg.rs:40:33
+  --> $DIR/ifmt-bad-arg.rs:40:29
    |
 LL |     format!("{foo}", foo=1, foo=2);
-   |                          -      ^ duplicate argument
-   |                          |
-   |                          previously here
+   |                      ---    ^^^ duplicate argument
+   |                      |
+   |                      previously here
 
 error: positional arguments cannot follow named arguments
   --> $DIR/ifmt-bad-arg.rs:41:35
    |
 LL |     format!("{foo} {} {}", foo=1, 2);
-   |                                -  ^ positional arguments must be before named arguments
-   |                                |
-   |                                named argument
+   |                            -----  ^ positional arguments must be before named arguments
+   |                            |
+   |                            named argument
 
 error: named argument never used
   --> $DIR/ifmt-bad-arg.rs:45:51
@@ -191,33 +187,26 @@ error: 4 positional arguments in format string, but there are 3 arguments
    |
 LL |     println!("{} {:.*} {}", 1, 3.2, 4);
    |               ^^ ^^--^ ^^   -  ---  -
-   |                    |           |
-   |                    |           this parameter corresponds to the precision flag
+   |                    |
    |                    this precision flag adds an extra required argument at position 1, which is why there are 4 arguments expected
    |
    = note: positional arguments are zero-based
    = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
 
-error: 4 positional arguments in format string, but there are 3 arguments
-  --> $DIR/ifmt-bad-arg.rs:81:15
+error: invalid reference to positional arguments 3 and 7 (there are 3 arguments)
+  --> $DIR/ifmt-bad-arg.rs:81:21
    |
 LL |     println!("{} {:07$.*} {}", 1, 3.2, 4);
-   |               ^^ ^^^----^ ^^   -  ---  -
-   |                     | |           |
-   |                     | |           this parameter corresponds to the precision flag
-   |                     | this precision flag adds an extra required argument at position 1, which is why there are 4 arguments expected
-   |                     this width flag expects an `usize` argument at position 7, but there are 3 arguments
+   |                     ^^     ^
    |
    = note: positional arguments are zero-based
    = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
 
 error: invalid reference to positional argument 7 (there are 3 arguments)
-  --> $DIR/ifmt-bad-arg.rs:84:18
+  --> $DIR/ifmt-bad-arg.rs:84:21
    |
 LL |     println!("{} {:07$} {}", 1, 3.2, 4);
-   |                  ^^^--^
-   |                     |
-   |                     this width flag expects an `usize` argument at position 7, but there are 3 arguments
+   |                     ^^
    |
    = note: positional arguments are zero-based
    = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
@@ -240,24 +229,19 @@ LL |     println!("{:foo}", 1);
            - `X`, which uses the `UpperHex` trait
 
 error: invalid reference to positional arguments 4, 5, 6 and 7 (there is 1 argument)
-  --> $DIR/ifmt-bad-arg.rs:87:15
+  --> $DIR/ifmt-bad-arg.rs:87:16
    |
 LL |     println!("{5} {:4$} {6:7$}", 1);
-   |               ^^^ ^^--^ ^^^--^
-   |                     |      |
-   |                     |      this width flag expects an `usize` argument at position 7, but there is 1 argument
-   |                     this width flag expects an `usize` argument at position 4, but there is 1 argument
+   |                ^    ^^   ^ ^^
    |
    = note: positional arguments are zero-based
    = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
 
 error: invalid reference to positional argument 0 (no arguments were given)
-  --> $DIR/ifmt-bad-arg.rs:90:15
+  --> $DIR/ifmt-bad-arg.rs:90:20
    |
 LL |     println!("{foo:0$}");
-   |               ^^^^^--^
-   |                    |
-   |                    this width flag expects an `usize` argument at position 0, but no arguments were given
+   |                    ^^
    |
    = note: positional arguments are zero-based
    = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
@@ -273,13 +257,11 @@ LL |     println!("{:.*}");
    = note: positional arguments are zero-based
    = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
 
-error: 1 positional argument in format string, but no arguments were given
-  --> $DIR/ifmt-bad-arg.rs:97:15
+error: invalid reference to positional argument 0 (no arguments were given)
+  --> $DIR/ifmt-bad-arg.rs:97:16
    |
 LL |     println!("{:.0$}");
-   |               ^^---^
-   |                 |
-   |                 this precision flag expects an `usize` argument at position 0, but no arguments were given
+   |                ^^^^
    |
    = note: positional arguments are zero-based
    = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
@@ -318,10 +300,10 @@ error[E0308]: mismatched types
   --> $DIR/ifmt-bad-arg.rs:78:32
    |
 LL |     println!("{} {:.*} {}", 1, 3.2, 4);
-   |     ---------------------------^^^----
-   |     |                          |
-   |     |                          expected `usize`, found floating-point number
-   |     arguments to this function are incorrect
+   |                                ^^^
+   |                                |
+   |                                expected `usize`, found floating-point number
+   |                                arguments to this function are incorrect
    |
    = note: expected reference `&usize`
               found reference `&{float}`
@@ -336,10 +318,10 @@ error[E0308]: mismatched types
   --> $DIR/ifmt-bad-arg.rs:81:35
    |
 LL |     println!("{} {:07$.*} {}", 1, 3.2, 4);
-   |     ------------------------------^^^----
-   |     |                             |
-   |     |                             expected `usize`, found floating-point number
-   |     arguments to this function are incorrect
+   |                                   ^^^
+   |                                   |
+   |                                   expected `usize`, found floating-point number
+   |                                   arguments to this function are incorrect
    |
    = note: expected reference `&usize`
               found reference `&{float}`
diff --git a/src/test/ui/function-pointer/issue-102289.rs b/src/test/ui/function-pointer/issue-102289.rs
new file mode 100644
index 00000000000..de394ca9ad6
--- /dev/null
+++ b/src/test/ui/function-pointer/issue-102289.rs
@@ -0,0 +1,54 @@
+// check-pass
+
+pub(crate) trait Parser: Sized {
+    type Output;
+    fn parse(&mut self, _input: &str) -> Result<(), ()> {
+        loop {}
+    }
+    fn map<F, B>(self, _f: F) -> Map<Self, F>
+    where
+        F: FnMut(Self::Output) -> B,
+    {
+        todo!()
+    }
+}
+
+pub(crate) struct Chainl1<P, Op>(P, Op);
+impl<P, Op> Parser for Chainl1<P, Op>
+where
+    P: Parser,
+    Op: Parser,
+    Op::Output: FnOnce(P::Output, P::Output) -> P::Output,
+{
+    type Output = P::Output;
+}
+pub(crate) fn chainl1<P, Op>(_parser: P, _op: Op) -> Chainl1<P, Op>
+where
+    P: Parser,
+    Op: Parser,
+    Op::Output: FnOnce(P::Output, P::Output) -> P::Output,
+{
+    loop {}
+}
+
+pub(crate) struct Map<P, F>(P, F);
+impl<A, B, P, F> Parser for Map<P, F>
+where
+    P: Parser<Output = A>,
+    F: FnMut(A) -> B,
+{
+    type Output = B;
+}
+
+impl Parser for u32 {
+    type Output = ();
+}
+
+pub fn chainl1_error_consume() {
+    fn first<T, U>(t: T, _: U) -> T {
+        t
+    }
+    let _ = chainl1(1, 1.map(|_| first)).parse("");
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/bugs/issue-86218.stderr b/src/test/ui/generic-associated-types/bugs/issue-86218.stderr
deleted file mode 100644
index de1b464a41d..00000000000
--- a/src/test/ui/generic-associated-types/bugs/issue-86218.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-error[E0477]: the type `<() as Yay<&'a ()>>::InnerStream<'s>` does not fulfill the required lifetime
-  --> $DIR/issue-86218.rs:22:28
-   |
-LL |     type InnerStream<'s> = impl Stream<Item = i32> + 's;
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: type must outlive the lifetime `'s` as defined here as required by this binding
-  --> $DIR/issue-86218.rs:22:22
-   |
-LL |     type InnerStream<'s> = impl Stream<Item = i32> + 's;
-   |                      ^^
-
-error: unconstrained opaque type
-  --> $DIR/issue-86218.rs:22:28
-   |
-LL |     type InnerStream<'s> = impl Stream<Item = i32> + 's;
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `InnerStream` must be used in combination with a concrete type within the same module
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0477`.
diff --git a/src/test/ui/generic-associated-types/bugs/issue-88382.stderr b/src/test/ui/generic-associated-types/bugs/issue-88382.stderr
index c5fd58096b7..a9a70bb7130 100644
--- a/src/test/ui/generic-associated-types/bugs/issue-88382.stderr
+++ b/src/test/ui/generic-associated-types/bugs/issue-88382.stderr
@@ -9,8 +9,8 @@ LL |     do_something(SomeImplementation(), test);
 LL | fn test<'a, I: Iterable>(_: &mut I::Iterator<'a>) {}
    | ------------------------------------------------- found signature defined here
    |
-   = note: expected function signature `for<'r> fn(&'r mut std::iter::Empty<usize>) -> _`
-              found function signature `for<'a, 'r> fn(&'r mut <_ as Iterable>::Iterator<'a>) -> _`
+   = note: expected function signature `for<'a> fn(&'a mut std::iter::Empty<usize>) -> _`
+              found function signature `for<'a, 'b> fn(&'b mut <_ as Iterable>::Iterator<'a>) -> _`
 note: required by a bound in `do_something`
   --> $DIR/issue-88382.rs:20:48
    |
diff --git a/src/test/ui/generic-associated-types/issue-102333.rs b/src/test/ui/generic-associated-types/issue-102333.rs
new file mode 100644
index 00000000000..6c72563322f
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-102333.rs
@@ -0,0 +1,15 @@
+// check-pass
+
+trait A {
+    type T: B<U<1i32> = ()>;
+}
+
+trait B {
+    type U<const C: i32>;
+}
+
+fn f<T: A>() {
+    let _: <<T as A>::T as B>::U<1i32> = ();
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-102335-gat.rs b/src/test/ui/generic-associated-types/issue-102335-gat.rs
new file mode 100644
index 00000000000..a7255fdcbf5
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-102335-gat.rs
@@ -0,0 +1,12 @@
+trait T {
+    type A: S<C<(), i32 = ()> = ()>;
+    //~^ ERROR associated type bindings are not allowed here
+}
+
+trait Q {}
+
+trait S {
+    type C<T>: Q;
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-102335-gat.stderr b/src/test/ui/generic-associated-types/issue-102335-gat.stderr
new file mode 100644
index 00000000000..7a7900a1e65
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-102335-gat.stderr
@@ -0,0 +1,9 @@
+error[E0229]: associated type bindings are not allowed here
+  --> $DIR/issue-102335-gat.rs:2:21
+   |
+LL |     type A: S<C<(), i32 = ()> = ()>;
+   |                     ^^^^^^^^ associated type not allowed here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0229`.
diff --git a/src/test/ui/generic-associated-types/issue-86218-2.rs b/src/test/ui/generic-associated-types/issue-86218-2.rs
new file mode 100644
index 00000000000..63c839ea871
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-86218-2.rs
@@ -0,0 +1,23 @@
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+
+pub trait Stream {
+    type Item;
+}
+
+impl Stream for () {
+    type Item = i32;
+}
+
+trait Yay<AdditionalValue> {
+    type InnerStream<'s>: Stream<Item = i32> + 's;
+    fn foo<'s>() -> Self::InnerStream<'s>;
+}
+
+impl<T> Yay<T> for () {
+    type InnerStream<'s> = impl Stream<Item = i32> + 's;
+    fn foo<'s>() -> Self::InnerStream<'s> { () }
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/bugs/issue-86218.rs b/src/test/ui/generic-associated-types/issue-86218.rs
index 3a2d758e7d6..b2c3071f06b 100644
--- a/src/test/ui/generic-associated-types/bugs/issue-86218.rs
+++ b/src/test/ui/generic-associated-types/issue-86218.rs
@@ -1,7 +1,4 @@
-// check-fail
-// known-bug: #86218
-
-// This should pass, but seems to run into a TAIT issue.
+// check-pass
 
 #![feature(type_alias_impl_trait)]
 
@@ -20,7 +17,8 @@ trait Yay<AdditionalValue> {
 
 impl<'a> Yay<&'a ()> for () {
     type InnerStream<'s> = impl Stream<Item = i32> + 's;
-    fn foo<'s>() -> Self::InnerStream<'s> { todo!() }
+    //^ ERROR does not fulfill the required lifetime
+    fn foo<'s>() -> Self::InnerStream<'s> { () }
 }
 
 fn main() {}
diff --git a/src/test/ui/generics/issue-94923.rs b/src/test/ui/generics/issue-94923.rs
new file mode 100644
index 00000000000..d337a5dffc9
--- /dev/null
+++ b/src/test/ui/generics/issue-94923.rs
@@ -0,0 +1,49 @@
+// run-pass
+// regression test for issue #94923
+// min-llvm-version: 15.0.0
+// compile-flags: -C opt-level=3
+
+fn f0<T>(mut x: usize) -> usize {
+    for _ in 0..1000 {
+        x *= 123;
+        x %= 99
+    }
+    x + 321 // function composition is not just longer iteration
+}
+
+fn f1<T>(x: usize) -> usize {
+    f0::<(i8, T)>(f0::<(u8, T)>(x))
+}
+
+fn f2<T>(x: usize) -> usize {
+    f1::<(i8, T)>(f1::<(u8, T)>(x))
+}
+
+fn f3<T>(x: usize) -> usize {
+    f2::<(i8, T)>(f2::<(u8, T)>(x))
+}
+
+fn f4<T>(x: usize) -> usize {
+    f3::<(i8, T)>(f3::<(u8, T)>(x))
+}
+
+fn f5<T>(x: usize) -> usize {
+    f4::<(i8, T)>(f4::<(u8, T)>(x))
+}
+
+fn f6<T>(x: usize) -> usize {
+    f5::<(i8, T)>(f5::<(u8, T)>(x))
+}
+
+fn f7<T>(x: usize) -> usize {
+    f6::<(i8, T)>(f6::<(u8, T)>(x))
+}
+
+fn f8<T>(x: usize) -> usize {
+    f7::<(i8, T)>(f7::<(u8, T)>(x))
+}
+
+fn main() {
+    let y = f8::<()>(1);
+    assert_eq!(y, 348);
+}
diff --git a/src/test/ui/higher-rank-trait-bounds/issue-30786.stderr b/src/test/ui/higher-rank-trait-bounds/issue-30786.stderr
index ffe3d7b81f5..c1e235441d6 100644
--- a/src/test/ui/higher-rank-trait-bounds/issue-30786.stderr
+++ b/src/test/ui/higher-rank-trait-bounds/issue-30786.stderr
@@ -19,7 +19,7 @@ note: the following trait bounds were not satisfied:
 LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
    |         ---------     -                          ^^^^^^ unsatisfied trait bound introduced here
 
-error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>`, but its trait bounds were not satisfied
+error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>`, but its trait bounds were not satisfied
   --> $DIR/issue-30786.rs:130:24
    |
 LL | pub struct Filter<S, F> {
@@ -29,12 +29,12 @@ LL | pub struct Filter<S, F> {
    | doesn't satisfy `_: StreamExt`
 ...
 LL |     let count = filter.countx();
-   |                        ^^^^^^ method cannot be called on `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>` due to unsatisfied trait bounds
+   |                        ^^^^^^ method cannot be called on `Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>` due to unsatisfied trait bounds
    |
 note: the following trait bounds were not satisfied:
-      `&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>: Stream`
-      `&'a mut &mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>: Stream`
-      `&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>: Stream`
+      `&'a mut &Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>: Stream`
+      `&'a mut &mut Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>: Stream`
+      `&'a mut Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>: Stream`
   --> $DIR/issue-30786.rs:96:50
    |
 LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
diff --git a/src/test/ui/higher-rank-trait-bounds/issue-46989.stderr b/src/test/ui/higher-rank-trait-bounds/issue-46989.stderr
index 309e1a676ed..3f874220a27 100644
--- a/src/test/ui/higher-rank-trait-bounds/issue-46989.stderr
+++ b/src/test/ui/higher-rank-trait-bounds/issue-46989.stderr
@@ -4,7 +4,7 @@ error: implementation of `Foo` is not general enough
 LL |     assert_foo::<fn(&i32)>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
-   = note: `Foo` would have to be implemented for the type `for<'r> fn(&'r i32)`
+   = note: `Foo` would have to be implemented for the type `for<'a> fn(&'a i32)`
    = note: ...but `Foo` is actually implemented for the type `fn(&'0 i32)`, for some specific lifetime `'0`
 
 error: aborting due to previous error
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr
index eebce827d1c..4ef96cd9541 100644
--- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr
+++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr
@@ -4,8 +4,8 @@ error[E0308]: mismatched types
 LL |     foo(bar, "string", |s| s.len() == 5);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
    |
-   = note: expected trait `for<'r, 's> FnOnce<(&'r &'s str,)>`
-              found trait `for<'r> FnOnce<(&'r &str,)>`
+   = note: expected trait `for<'a, 'b> FnOnce<(&'a &'b str,)>`
+              found trait `for<'a> FnOnce<(&'a &str,)>`
 note: this closure does not fulfill the lifetime requirements
   --> $DIR/issue-71955.rs:45:24
    |
@@ -23,8 +23,8 @@ error[E0308]: mismatched types
 LL |     foo(bar, "string", |s| s.len() == 5);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
    |
-   = note: expected trait `for<'r, 's> FnOnce<(&'r &'s str,)>`
-              found trait `for<'r> FnOnce<(&'r &str,)>`
+   = note: expected trait `for<'a, 'b> FnOnce<(&'a &'b str,)>`
+              found trait `for<'a> FnOnce<(&'a &str,)>`
 note: this closure does not fulfill the lifetime requirements
   --> $DIR/issue-71955.rs:45:24
    |
@@ -42,8 +42,8 @@ error[E0308]: mismatched types
 LL |     foo(baz, "string", |s| s.0.len() == 5);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
    |
-   = note: expected trait `for<'r, 's> FnOnce<(&'r Wrapper<'s>,)>`
-              found trait `for<'r> FnOnce<(&'r Wrapper<'_>,)>`
+   = note: expected trait `for<'a, 'b> FnOnce<(&'a Wrapper<'b>,)>`
+              found trait `for<'a> FnOnce<(&'a Wrapper<'_>,)>`
 note: this closure does not fulfill the lifetime requirements
   --> $DIR/issue-71955.rs:48:24
    |
@@ -61,8 +61,8 @@ error[E0308]: mismatched types
 LL |     foo(baz, "string", |s| s.0.len() == 5);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
    |
-   = note: expected trait `for<'r, 's> FnOnce<(&'r Wrapper<'s>,)>`
-              found trait `for<'r> FnOnce<(&'r Wrapper<'_>,)>`
+   = note: expected trait `for<'a, 'b> FnOnce<(&'a Wrapper<'b>,)>`
+              found trait `for<'a> FnOnce<(&'a Wrapper<'_>,)>`
 note: this closure does not fulfill the lifetime requirements
   --> $DIR/issue-71955.rs:48:24
    |
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs
index de9348f5397..c10a0888a4f 100644
--- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs
+++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs
@@ -6,7 +6,7 @@ trait SomeTrait<'a> {
 
 fn give_me_ice<T>() {
     callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
-    //~^ ERROR the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied [E0277]
+    //~^ ERROR the trait bound `for<'a> T: SomeTrait<'a>` is not satisfied [E0277]
 }
 
 fn callee<T: Fn<(&'static (),)>>() {
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr
index 6a948a116e0..25a4f6088de 100644
--- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr
+++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr
@@ -1,12 +1,12 @@
-error[E0277]: the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied
+error[E0277]: the trait bound `for<'a> T: SomeTrait<'a>` is not satisfied
   --> $DIR/issue-85455.rs:8:5
    |
 LL |     callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'r> SomeTrait<'r>` is not implemented for `T`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> SomeTrait<'a>` is not implemented for `T`
    |
 help: consider restricting type parameter `T`
    |
-LL | fn give_me_ice<T: for<'r> SomeTrait<'r>>() {
+LL | fn give_me_ice<T: for<'a> SomeTrait<'a>>() {
    |                 +++++++++++++++++++++++
 
 error: aborting due to previous error
diff --git a/src/test/ui/hygiene/impl_items.rs b/src/test/ui/hygiene/impl_items.rs
index 37794c6e077..ddb25c06b1b 100644
--- a/src/test/ui/hygiene/impl_items.rs
+++ b/src/test/ui/hygiene/impl_items.rs
@@ -9,7 +9,7 @@ mod foo {
     }
 
     pub macro m() {
-        let _: () = S.f(); //~ ERROR type `for<'r> fn(&'r foo::S) {foo::S::f}` is private
+        let _: () = S.f(); //~ ERROR type `for<'a> fn(&'a foo::S) {foo::S::f}` is private
     }
 }
 
diff --git a/src/test/ui/hygiene/impl_items.stderr b/src/test/ui/hygiene/impl_items.stderr
index 523309f4325..46a2500386e 100644
--- a/src/test/ui/hygiene/impl_items.stderr
+++ b/src/test/ui/hygiene/impl_items.stderr
@@ -1,4 +1,4 @@
-error: type `for<'r> fn(&'r foo::S) {foo::S::f}` is private
+error: type `for<'a> fn(&'a foo::S) {foo::S::f}` is private
   --> $DIR/impl_items.rs:12:23
    |
 LL |         let _: () = S.f();
diff --git a/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2015.stderr b/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2015.stderr
index fd2e454e7e4..edf3911e2a0 100644
--- a/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2015.stderr
+++ b/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2015.stderr
@@ -1,8 +1,8 @@
-error[E0277]: the trait bound `(): AsRef<(dyn for<'r> Fn(&'r ()) + 'static)>` is not satisfied
+error[E0277]: the trait bound `(): AsRef<(dyn for<'a> Fn(&'a ()) + 'static)>` is not satisfied
   --> $DIR/generic-with-implicit-hrtb-without-dyn.rs:6:13
    |
 LL | fn ice() -> impl AsRef<Fn(&())> {
-   |             ^^^^^^^^^^^^^^^^^^^ the trait `AsRef<(dyn for<'r> Fn(&'r ()) + 'static)>` is not implemented for `()`
+   |             ^^^^^^^^^^^^^^^^^^^ the trait `AsRef<(dyn for<'a> Fn(&'a ()) + 'static)>` is not implemented for `()`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr b/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr
index 8f409227324..88e2520bf4b 100644
--- a/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr
+++ b/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr
@@ -9,11 +9,11 @@ help: add `dyn` keyword before this trait
 LL | fn ice() -> impl AsRef<dyn Fn(&())> {
    |                        +++
 
-error[E0277]: the trait bound `(): AsRef<(dyn for<'r> Fn(&'r ()) + 'static)>` is not satisfied
+error[E0277]: the trait bound `(): AsRef<(dyn for<'a> Fn(&'a ()) + 'static)>` is not satisfied
   --> $DIR/generic-with-implicit-hrtb-without-dyn.rs:6:13
    |
 LL | fn ice() -> impl AsRef<Fn(&())> {
-   |             ^^^^^^^^^^^^^^^^^^^ the trait `AsRef<(dyn for<'r> Fn(&'r ()) + 'static)>` is not implemented for `()`
+   |             ^^^^^^^^^^^^^^^^^^^ the trait `AsRef<(dyn for<'a> Fn(&'a ()) + 'static)>` is not implemented for `()`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs b/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs
index 856dc7a3f5a..5a922697f6f 100644
--- a/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs
+++ b/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs
@@ -4,7 +4,7 @@
 #![allow(warnings)]
 
 fn ice() -> impl AsRef<Fn(&())> {
-    //~^ ERROR: the trait bound `(): AsRef<(dyn for<'r> Fn(&'r ()) + 'static)>` is not satisfied [E0277]
+    //~^ ERROR: the trait bound `(): AsRef<(dyn for<'a> Fn(&'a ()) + 'static)>` is not satisfied [E0277]
     //[edition2021]~| ERROR: trait objects must include the `dyn` keyword [E0782]
     todo!()
 }
diff --git a/src/test/ui/impl-trait/in-trait/auxiliary/rpitit.rs b/src/test/ui/impl-trait/in-trait/auxiliary/rpitit.rs
new file mode 100644
index 00000000000..74df300f85a
--- /dev/null
+++ b/src/test/ui/impl-trait/in-trait/auxiliary/rpitit.rs
@@ -0,0 +1,11 @@
+#![feature(return_position_impl_trait_in_trait)]
+
+pub trait Foo {
+    fn bar() -> impl Sized;
+}
+
+pub struct Foreign;
+
+impl Foo for Foreign {
+    fn bar() {}
+}
diff --git a/src/test/ui/impl-trait/in-trait/foreign.rs b/src/test/ui/impl-trait/in-trait/foreign.rs
new file mode 100644
index 00000000000..6341f5b4284
--- /dev/null
+++ b/src/test/ui/impl-trait/in-trait/foreign.rs
@@ -0,0 +1,9 @@
+// check-pass
+// aux-build: rpitit.rs
+
+extern crate rpitit;
+
+fn main() {
+    // Witness an RPITIT from another crate
+    let () = <rpitit::Foreign as rpitit::Foo>::bar();
+}
diff --git a/src/test/ui/impl-trait/issues/issue-78722.rs b/src/test/ui/impl-trait/issues/issue-78722.rs
index 90d1cd3798a..9ee1ba3d3b4 100644
--- a/src/test/ui/impl-trait/issues/issue-78722.rs
+++ b/src/test/ui/impl-trait/issues/issue-78722.rs
@@ -12,7 +12,7 @@ struct Bug {
         }
         let f: F = async { 1 };
         //~^ ERROR `async` blocks are not allowed in constants
-        //~| ERROR destructors cannot be evaluated at compile-time
+        //~| ERROR destructor of
         1
     }],
 }
diff --git a/src/test/ui/impl-trait/issues/issue-78722.stderr b/src/test/ui/impl-trait/issues/issue-78722.stderr
index 9a0ffbc89d9..a96994f5a7f 100644
--- a/src/test/ui/impl-trait/issues/issue-78722.stderr
+++ b/src/test/ui/impl-trait/issues/issue-78722.stderr
@@ -7,11 +7,11 @@ LL |         let f: F = async { 1 };
    = note: see issue #85368 <https://github.com/rust-lang/rust/issues/85368> for more information
    = help: add `#![feature(const_async_blocks)]` to the crate attributes to enable
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `F` cannot be evaluated at compile-time
   --> $DIR/issue-78722.rs:13:13
    |
 LL |         let f: F = async { 1 };
-   |             ^ constants cannot evaluate destructors
+   |             ^ the destructor for this type cannot be evaluated in constants
 ...
 LL |     }],
    |     - value is dropped here
diff --git a/src/test/ui/impl-trait/unactionable_diagnostic.fixed b/src/test/ui/impl-trait/unactionable_diagnostic.fixed
new file mode 100644
index 00000000000..6c2505177fe
--- /dev/null
+++ b/src/test/ui/impl-trait/unactionable_diagnostic.fixed
@@ -0,0 +1,25 @@
+// run-rustfix
+
+pub trait Trait {}
+
+pub struct Foo;
+
+impl Trait for Foo {}
+
+fn foo<'x, P>(
+    _post: P,
+    x: &'x Foo,
+) -> &'x impl Trait {
+    x
+}
+
+pub fn bar<'t, T: 't>(
+    //~^ HELP: consider adding an explicit lifetime bound...
+    post: T,
+    x: &'t Foo,
+) -> &'t impl Trait {
+    foo(post, x)
+    //~^ ERROR: the parameter type `T` may not live long enough
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/unactionable_diagnostic.rs b/src/test/ui/impl-trait/unactionable_diagnostic.rs
new file mode 100644
index 00000000000..bce35cbdd0d
--- /dev/null
+++ b/src/test/ui/impl-trait/unactionable_diagnostic.rs
@@ -0,0 +1,25 @@
+// run-rustfix
+
+pub trait Trait {}
+
+pub struct Foo;
+
+impl Trait for Foo {}
+
+fn foo<'x, P>(
+    _post: P,
+    x: &'x Foo,
+) -> &'x impl Trait {
+    x
+}
+
+pub fn bar<'t, T>(
+    //~^ HELP: consider adding an explicit lifetime bound...
+    post: T,
+    x: &'t Foo,
+) -> &'t impl Trait {
+    foo(post, x)
+    //~^ ERROR: the parameter type `T` may not live long enough
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/unactionable_diagnostic.stderr b/src/test/ui/impl-trait/unactionable_diagnostic.stderr
new file mode 100644
index 00000000000..a32004cda1a
--- /dev/null
+++ b/src/test/ui/impl-trait/unactionable_diagnostic.stderr
@@ -0,0 +1,14 @@
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/unactionable_diagnostic.rs:21:5
+   |
+LL |     foo(post, x)
+   |     ^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | pub fn bar<'t, T: 't>(
+   |                 ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/implied-bounds/issue-101951.rs b/src/test/ui/implied-bounds/issue-101951.rs
new file mode 100644
index 00000000000..108fef8a15f
--- /dev/null
+++ b/src/test/ui/implied-bounds/issue-101951.rs
@@ -0,0 +1,50 @@
+// Taken directly from that issue.
+//
+// This test detected that we didn't correctly resolve
+// inference variables when computing implied bounds.
+//
+// check-pass
+pub trait BuilderFn<'a> {
+    type Output;
+}
+
+impl<'a, F, Out> BuilderFn<'a> for F
+where
+    F: FnOnce(&'a mut ()) -> Out,
+{
+    type Output = Out;
+}
+
+pub trait ConstructionFirm {
+    type Builder: for<'a> BuilderFn<'a>;
+}
+
+pub trait Campus<T>
+where
+    T: ConstructionFirm,
+{
+    fn add_building(
+        &mut self,
+        building: &mut <<T as ConstructionFirm>::Builder as BuilderFn<'_>>::Output,
+    );
+}
+
+struct ArchitectsInc {}
+
+impl ConstructionFirm for ArchitectsInc {
+    type Builder = fn(&mut ()) -> PrettyCondo<'_>;
+}
+
+struct PrettyCondo<'a> {
+    _marker: &'a mut (),
+}
+
+struct CondoEstate {}
+
+impl Campus<ArchitectsInc> for CondoEstate {
+    fn add_building(&mut self, _building: &mut PrettyCondo<'_>) {
+        todo!()
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/intrinsics/intrinsic-alignment.rs b/src/test/ui/intrinsics/intrinsic-alignment.rs
index 6007eba8c09..c8b1ff1dbce 100644
--- a/src/test/ui/intrinsics/intrinsic-alignment.rs
+++ b/src/test/ui/intrinsics/intrinsic-alignment.rs
@@ -6,6 +6,7 @@
 mod rusti {
     extern "rust-intrinsic" {
         pub fn pref_align_of<T>() -> usize;
+        #[rustc_safe_intrinsic]
         pub fn min_align_of<T>() -> usize;
     }
 }
diff --git a/src/test/ui/intrinsics/intrinsics-integer.rs b/src/test/ui/intrinsics/intrinsics-integer.rs
index bac6c8d872b..88bf42b685f 100644
--- a/src/test/ui/intrinsics/intrinsics-integer.rs
+++ b/src/test/ui/intrinsics/intrinsics-integer.rs
@@ -1,15 +1,21 @@
 // run-pass
 
 #![feature(intrinsics)]
+#![feature(rustc_attrs)]
 
 mod rusti {
     extern "rust-intrinsic" {
+        #[rustc_safe_intrinsic]
         pub fn ctpop<T>(x: T) -> T;
+        #[rustc_safe_intrinsic]
         pub fn ctlz<T>(x: T) -> T;
         pub fn ctlz_nonzero<T>(x: T) -> T;
+        #[rustc_safe_intrinsic]
         pub fn cttz<T>(x: T) -> T;
         pub fn cttz_nonzero<T>(x: T) -> T;
+        #[rustc_safe_intrinsic]
         pub fn bswap<T>(x: T) -> T;
+        #[rustc_safe_intrinsic]
         pub fn bitreverse<T>(x: T) -> T;
     }
 }
diff --git a/src/test/ui/intrinsics/safe-intrinsic-mismatch.rs b/src/test/ui/intrinsics/safe-intrinsic-mismatch.rs
new file mode 100644
index 00000000000..50e12eaeb5c
--- /dev/null
+++ b/src/test/ui/intrinsics/safe-intrinsic-mismatch.rs
@@ -0,0 +1,11 @@
+#![feature(intrinsics)]
+#![feature(rustc_attrs)]
+
+extern "rust-intrinsic" {
+    fn size_of<T>() -> usize; //~ ERROR intrinsic safety mismatch
+
+    #[rustc_safe_intrinsic]
+    fn assume(b: bool); //~ ERROR intrinsic safety mismatch
+}
+
+fn main() {}
diff --git a/src/test/ui/intrinsics/safe-intrinsic-mismatch.stderr b/src/test/ui/intrinsics/safe-intrinsic-mismatch.stderr
new file mode 100644
index 00000000000..0c2f3be491d
--- /dev/null
+++ b/src/test/ui/intrinsics/safe-intrinsic-mismatch.stderr
@@ -0,0 +1,14 @@
+error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `size_of`
+  --> $DIR/safe-intrinsic-mismatch.rs:5:5
+   |
+LL |     fn size_of<T>() -> usize;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `assume`
+  --> $DIR/safe-intrinsic-mismatch.rs:8:5
+   |
+LL |     fn assume(b: bool);
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/invalid/invalid-llvm-passes.rs b/src/test/ui/invalid/invalid-llvm-passes.rs
index ca3c6230af0..ee28f5eb6d6 100644
--- a/src/test/ui/invalid/invalid-llvm-passes.rs
+++ b/src/test/ui/invalid/invalid-llvm-passes.rs
@@ -1,4 +1,4 @@
 // build-fail
-// compile-flags: -Cpasses=unknown-pass -Z new-llvm-pass-manager=yes
+// compile-flags: -Cpasses=unknown-pass
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-18919.stderr b/src/test/ui/issues/issue-18919.stderr
index d7dbb8299b9..b0b03a0eea6 100644
--- a/src/test/ui/issues/issue-18919.stderr
+++ b/src/test/ui/issues/issue-18919.stderr
@@ -1,10 +1,10 @@
-error[E0277]: the size for values of type `dyn for<'r> Fn(&'r isize) -> isize` cannot be known at compilation time
+error[E0277]: the size for values of type `dyn for<'a> Fn(&'a isize) -> isize` cannot be known at compilation time
   --> $DIR/issue-18919.rs:3:15
    |
 LL | fn ho_func(f: Option<FuncType>) {
    |               ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: the trait `Sized` is not implemented for `dyn for<'r> Fn(&'r isize) -> isize`
+   = help: the trait `Sized` is not implemented for `dyn for<'a> Fn(&'a isize) -> isize`
 note: required by a bound in `Option`
   --> $DIR/issue-18919.rs:7:13
    |
diff --git a/src/test/ui/issues/issue-22644.rs b/src/test/ui/issues/issue-22644.rs
index 9244ff5931d..b1d69dcd862 100644
--- a/src/test/ui/issues/issue-22644.rs
+++ b/src/test/ui/issues/issue-22644.rs
@@ -29,7 +29,7 @@ fn main() {
                    < //~ ERROR `<` is interpreted as a start of generic
                    5);
 
-    println!("{}", a as usize << long_name); //~ ERROR `<` is interpreted as a start of generic
+    println!("{}", a as usize << long_name); //~ ERROR `<<` is interpreted as a start of generic
 
     println!("{}", a: &mut 4); //~ ERROR expected type, found `4`
 }
diff --git a/src/test/ui/issues/issue-22644.stderr b/src/test/ui/issues/issue-22644.stderr
index 039ffbfd3d8..45027afa7b6 100644
--- a/src/test/ui/issues/issue-22644.stderr
+++ b/src/test/ui/issues/issue-22644.stderr
@@ -95,7 +95,7 @@ LL |
 LL ~                    usize)
    |
 
-error: `<` is interpreted as a start of generic arguments for `usize`, not a shift
+error: `<<` is interpreted as a start of generic arguments for `usize`, not a shift
   --> $DIR/issue-22644.rs:32:31
    |
 LL |     println!("{}", a as usize << long_name);
diff --git a/src/test/ui/issues/issue-24322.stderr b/src/test/ui/issues/issue-24322.stderr
index 1a4fab16540..1e4c8ac7c35 100644
--- a/src/test/ui/issues/issue-24322.stderr
+++ b/src/test/ui/issues/issue-24322.stderr
@@ -6,8 +6,8 @@ LL |     let x: &fn(&B) -> u32 = &B::func;
    |            |
    |            expected due to this
    |
-   = note: expected reference `&for<'r> fn(&'r B) -> u32`
-              found reference `&for<'r> fn(&'r B) -> u32 {B::func}`
+   = note: expected reference `&for<'a> fn(&'a B) -> u32`
+              found reference `&for<'a> fn(&'a B) -> u32 {B::func}`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-40000.stderr b/src/test/ui/issues/issue-40000.stderr
index e6f0b5fbfba..c41fbb9d2ec 100644
--- a/src/test/ui/issues/issue-40000.stderr
+++ b/src/test/ui/issues/issue-40000.stderr
@@ -4,7 +4,7 @@ error[E0308]: mismatched types
 LL |     foo(bar);
    |         ^^^ one type is more general than the other
    |
-   = note: expected trait object `dyn for<'r> Fn(&'r i32)`
+   = note: expected trait object `dyn for<'a> Fn(&'a i32)`
               found trait object `dyn Fn(&i32)`
 
 error[E0308]: mismatched types
@@ -13,7 +13,7 @@ error[E0308]: mismatched types
 LL |     foo(bar);
    |         ^^^ one type is more general than the other
    |
-   = note: expected trait object `dyn for<'r> Fn(&'r i32)`
+   = note: expected trait object `dyn for<'a> Fn(&'a i32)`
               found trait object `dyn Fn(&i32)`
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/issues/issue-57362-2.stderr b/src/test/ui/issues/issue-57362-2.stderr
index 3b6cffeafe4..7d08c4643ff 100644
--- a/src/test/ui/issues/issue-57362-2.stderr
+++ b/src/test/ui/issues/issue-57362-2.stderr
@@ -1,11 +1,11 @@
-error[E0599]: the function or associated item `make_g` exists for fn pointer `for<'r> fn(&'r ())`, but its trait bounds were not satisfied
+error[E0599]: the function or associated item `make_g` exists for fn pointer `for<'a> fn(&'a ())`, but its trait bounds were not satisfied
   --> $DIR/issue-57362-2.rs:22:25
    |
 LL |     let x = <fn (&())>::make_g();
-   |                         ^^^^^^ function or associated item cannot be called on `for<'r> fn(&'r ())` due to unsatisfied trait bounds
+   |                         ^^^^^^ function or associated item cannot be called on `for<'a> fn(&'a ())` due to unsatisfied trait bounds
    |
    = note: the following trait bounds were not satisfied:
-           `for<'r> fn(&'r ()): X`
+           `for<'a> fn(&'a ()): X`
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `X` defines an item `make_g`, perhaps you need to implement it
   --> $DIR/issue-57362-2.rs:8:1
diff --git a/src/test/ui/issues/issue-75307.rs b/src/test/ui/issues/issue-75307.rs
index 2fe112a3b95..cffa6bea8ed 100644
--- a/src/test/ui/issues/issue-75307.rs
+++ b/src/test/ui/issues/issue-75307.rs
@@ -1,3 +1,3 @@
 fn main() {
-    format!(r"{}{}{}", named_arg=1); //~ ERROR invalid reference to positional arguments 1 and 2
+    format!(r"{}{}{}", named_arg=1); //~ ERROR 3 positional arguments in format string, but there is 1 argument
 }
diff --git a/src/test/ui/issues/issue-75307.stderr b/src/test/ui/issues/issue-75307.stderr
index 10c952006c2..c5b0b11e7d0 100644
--- a/src/test/ui/issues/issue-75307.stderr
+++ b/src/test/ui/issues/issue-75307.stderr
@@ -1,10 +1,8 @@
-error: invalid reference to positional arguments 1 and 2 (there is 1 argument)
-  --> $DIR/issue-75307.rs:2:17
+error: 3 positional arguments in format string, but there is 1 argument
+  --> $DIR/issue-75307.rs:2:15
    |
 LL |     format!(r"{}{}{}", named_arg=1);
-   |                 ^^^^
-   |
-   = note: positional arguments are zero-based
+   |               ^^^^^^             -
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-99838.rs b/src/test/ui/issues/issue-99838.rs
index eaeeac72b25..2e81d5e8221 100644
--- a/src/test/ui/issues/issue-99838.rs
+++ b/src/test/ui/issues/issue-99838.rs
@@ -1,5 +1,5 @@
 // run-pass
-#![feature(bench_black_box)]
+
 use std::hint;
 
 struct U16(u16);
diff --git a/src/test/ui/let-else/const-fn.rs b/src/test/ui/let-else/const-fn.rs
index 336b0b4b72a..a3921b8033f 100644
--- a/src/test/ui/let-else/const-fn.rs
+++ b/src/test/ui/let-else/const-fn.rs
@@ -1,7 +1,6 @@
 // run-pass
 // issue #101932
 
-#![cfg_attr(bootstrap, feature(let_else))]
 
 const fn foo(a: Option<i32>) -> i32 {
     let Some(a) = a else {
diff --git a/src/test/ui/let-else/let-else-brace-before-else.stderr b/src/test/ui/let-else/let-else-brace-before-else.stderr
index 51051bbd4d8..cb01e4c18a1 100644
--- a/src/test/ui/let-else/let-else-brace-before-else.stderr
+++ b/src/test/ui/let-else/let-else-brace-before-else.stderr
@@ -4,7 +4,7 @@ error: right curly brace `}` before `else` in a `let...else` statement not allow
 LL |     let Some(1) = { Some(1) } else {
    |                             ^
    |
-help: try wrapping the expression in parentheses
+help: wrap the expression in parentheses
    |
 LL |     let Some(1) = ({ Some(1) }) else {
    |                   +           +
@@ -15,7 +15,7 @@ error: right curly brace `}` before `else` in a `let...else` statement not allow
 LL |     let Some(1) = loop { break Some(1) } else {
    |                                        ^
    |
-help: try wrapping the expression in parentheses
+help: wrap the expression in parentheses
    |
 LL |     let Some(1) = (loop { break Some(1) }) else {
    |                   +                      +
@@ -26,7 +26,7 @@ error: right curly brace `}` before `else` in a `let...else` statement not allow
 LL |     let 2 = 1 + match 1 { n => n } else {
    |                                  ^
    |
-help: try wrapping the expression in parentheses
+help: wrap the expression in parentheses
    |
 LL |     let 2 = 1 + (match 1 { n => n }) else {
    |                 +                  +
@@ -37,7 +37,7 @@ error: right curly brace `}` before `else` in a `let...else` statement not allow
 LL |     let Some(1) = unsafe { unsafe_fn() } else {
    |                                        ^
    |
-help: try wrapping the expression in parentheses
+help: wrap the expression in parentheses
    |
 LL |     let Some(1) = (unsafe { unsafe_fn() }) else {
    |                   +                      +
diff --git a/src/test/ui/lifetimes/issue-79187-2.stderr b/src/test/ui/lifetimes/issue-79187-2.stderr
index 9322e617176..c5f654b37bf 100644
--- a/src/test/ui/lifetimes/issue-79187-2.stderr
+++ b/src/test/ui/lifetimes/issue-79187-2.stderr
@@ -31,7 +31,7 @@ error[E0308]: mismatched types
 LL |     take_foo(|a| a);
    |     ^^^^^^^^^^^^^^^ one type is more general than the other
    |
-   = note: expected trait `for<'r> Fn<(&'r i32,)>`
+   = note: expected trait `for<'a> Fn<(&'a i32,)>`
               found trait `Fn<(&i32,)>`
 note: this closure does not fulfill the lifetime requirements
   --> $DIR/issue-79187-2.rs:8:14
diff --git a/src/test/ui/lifetimes/issue-79187.stderr b/src/test/ui/lifetimes/issue-79187.stderr
index 3e75e7fed2c..ee6e7b89d5f 100644
--- a/src/test/ui/lifetimes/issue-79187.stderr
+++ b/src/test/ui/lifetimes/issue-79187.stderr
@@ -4,7 +4,7 @@ error[E0308]: mismatched types
 LL |     thing(f);
    |     ^^^^^^^^ one type is more general than the other
    |
-   = note: expected trait `for<'r> FnOnce<(&'r u32,)>`
+   = note: expected trait `for<'a> FnOnce<(&'a u32,)>`
               found trait `FnOnce<(&u32,)>`
 note: this closure does not fulfill the lifetime requirements
   --> $DIR/issue-79187.rs:4:13
diff --git a/src/test/ui/lifetimes/lifetime-errors/issue_74400.stderr b/src/test/ui/lifetimes/lifetime-errors/issue_74400.stderr
index d82b2684cce..7049f28e2f6 100644
--- a/src/test/ui/lifetimes/lifetime-errors/issue_74400.stderr
+++ b/src/test/ui/lifetimes/lifetime-errors/issue_74400.stderr
@@ -15,7 +15,7 @@ error[E0308]: mismatched types
 LL |     f(data, identity)
    |     ^^^^^^^^^^^^^^^^^ one type is more general than the other
    |
-   = note: expected trait `for<'r> Fn<(&'r T,)>`
+   = note: expected trait `for<'a> Fn<(&'a T,)>`
               found trait `Fn<(&T,)>`
 note: the lifetime requirement is introduced here
   --> $DIR/issue_74400.rs:8:34
diff --git a/src/test/ui/lifetimes/re-empty-in-error.stderr b/src/test/ui/lifetimes/re-empty-in-error.stderr
index 72bb0782f4b..840707d9470 100644
--- a/src/test/ui/lifetimes/re-empty-in-error.stderr
+++ b/src/test/ui/lifetimes/re-empty-in-error.stderr
@@ -4,7 +4,7 @@ error: higher-ranked lifetime error
 LL |     foo(&10);
    |     ^^^^^^^^
    |
-   = note: could not prove `for<'b, 'r> &'b (): 'r`
+   = note: could not prove `for<'b, 'a> &'b (): 'a`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.stderr b/src/test/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.stderr
index a8b0996d8b0..31fd8a4d633 100644
--- a/src/test/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.stderr
+++ b/src/test/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.stderr
@@ -21,3 +21,4 @@ LL | fn no_restriction<'a, T: 'a>(x: &()) -> &() {
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0311`.
diff --git a/src/test/ui/lint/uninitialized-zeroed.rs b/src/test/ui/lint/invalid_value.rs
index dae258407eb..51edb2b7baf 100644
--- a/src/test/ui/lint/uninitialized-zeroed.rs
+++ b/src/test/ui/lint/invalid_value.rs
@@ -34,6 +34,16 @@ enum OneFruit {
     Banana,
 }
 
+enum OneFruitNonZero {
+    Apple(!),
+    Banana(NonZeroU32),
+}
+
+enum TwoUninhabited {
+    A(!),
+    B(Void),
+}
+
 #[allow(unused)]
 fn generic<T: 'static>() {
     unsafe {
@@ -84,6 +94,12 @@ fn main() {
         let _val: [fn(); 2] = mem::zeroed(); //~ ERROR: does not permit zero-initialization
         let _val: [fn(); 2] = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
 
+        let _val: TwoUninhabited = mem::zeroed(); //~ ERROR: does not permit zero-initialization
+        let _val: TwoUninhabited = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
+
+        let _val: OneFruitNonZero = mem::zeroed(); //~ ERROR: does not permit zero-initialization
+        let _val: OneFruitNonZero = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
+
         // Things that can be zero, but not uninit.
         let _val: bool = mem::zeroed();
         let _val: bool = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
@@ -112,6 +128,16 @@ fn main() {
         let _val: *const [()] = mem::zeroed();
         let _val: *const [()] = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
 
+        // Things where 0 is okay due to rustc implementation details,
+        // but that are not guaranteed to keep working.
+        let _val: Result<i32, i32> = mem::zeroed();
+        let _val: Result<i32, i32> = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
+
+        // Some things that happen to work due to rustc implementation details,
+        // but are not guaranteed to keep working.
+        let _val: OneFruit = mem::zeroed();
+        let _val: OneFruit = mem::uninitialized();
+
         // Transmute-from-0
         let _val: &'static i32 = mem::transmute(0usize); //~ ERROR: does not permit zero-initialization
         let _val: &'static [i32] = mem::transmute((0usize, 0usize)); //~ ERROR: does not permit zero-initialization
@@ -129,9 +155,5 @@ fn main() {
         let _val: bool = MaybeUninit::zeroed().assume_init();
         let _val: [bool; 0] = MaybeUninit::uninit().assume_init();
         let _val: [!; 0] = MaybeUninit::zeroed().assume_init();
-
-        // Some things that happen to work due to rustc implementation details,
-        // but are not guaranteed to keep working.
-        let _val: OneFruit = mem::uninitialized();
     }
 }
diff --git a/src/test/ui/lint/uninitialized-zeroed.stderr b/src/test/ui/lint/invalid_value.stderr
index b46042e7be4..750b3c76c44 100644
--- a/src/test/ui/lint/uninitialized-zeroed.stderr
+++ b/src/test/ui/lint/invalid_value.stderr
@@ -1,5 +1,5 @@
 error: the type `&T` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:40:32
+  --> $DIR/invalid_value.rs:50:32
    |
 LL |         let _val: &'static T = mem::zeroed();
    |                                ^^^^^^^^^^^^^
@@ -8,14 +8,14 @@ LL |         let _val: &'static T = mem::zeroed();
    |                                help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
    |
 note: the lint level is defined here
-  --> $DIR/uninitialized-zeroed.rs:6:9
+  --> $DIR/invalid_value.rs:6:9
    |
 LL | #![deny(invalid_value)]
    |         ^^^^^^^^^^^^^
    = note: references must be non-null
 
 error: the type `&T` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:41:32
+  --> $DIR/invalid_value.rs:51:32
    |
 LL |         let _val: &'static T = mem::uninitialized();
    |                                ^^^^^^^^^^^^^^^^^^^^
@@ -26,7 +26,7 @@ LL |         let _val: &'static T = mem::uninitialized();
    = note: references must be non-null
 
 error: the type `Wrap<&T>` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:43:38
+  --> $DIR/invalid_value.rs:53:38
    |
 LL |         let _val: Wrap<&'static T> = mem::zeroed();
    |                                      ^^^^^^^^^^^^^
@@ -35,13 +35,13 @@ LL |         let _val: Wrap<&'static T> = mem::zeroed();
    |                                      help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
    |
 note: references must be non-null (in this struct field)
-  --> $DIR/uninitialized-zeroed.rs:17:18
+  --> $DIR/invalid_value.rs:17:18
    |
 LL | struct Wrap<T> { wrapped: T }
    |                  ^^^^^^^^^^
 
 error: the type `Wrap<&T>` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:44:38
+  --> $DIR/invalid_value.rs:54:38
    |
 LL |         let _val: Wrap<&'static T> = mem::uninitialized();
    |                                      ^^^^^^^^^^^^^^^^^^^^
@@ -50,13 +50,13 @@ LL |         let _val: Wrap<&'static T> = mem::uninitialized();
    |                                      help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
    |
 note: references must be non-null (in this struct field)
-  --> $DIR/uninitialized-zeroed.rs:17:18
+  --> $DIR/invalid_value.rs:17:18
    |
 LL | struct Wrap<T> { wrapped: T }
    |                  ^^^^^^^^^^
 
 error: the type `!` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:51:23
+  --> $DIR/invalid_value.rs:61:23
    |
 LL |         let _val: ! = mem::zeroed();
    |                       ^^^^^^^^^^^^^
@@ -67,7 +67,7 @@ LL |         let _val: ! = mem::zeroed();
    = note: the `!` type has no valid value
 
 error: the type `!` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:52:23
+  --> $DIR/invalid_value.rs:62:23
    |
 LL |         let _val: ! = mem::uninitialized();
    |                       ^^^^^^^^^^^^^^^^^^^^
@@ -78,7 +78,7 @@ LL |         let _val: ! = mem::uninitialized();
    = note: the `!` type has no valid value
 
 error: the type `(i32, !)` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:54:30
+  --> $DIR/invalid_value.rs:64:30
    |
 LL |         let _val: (i32, !) = mem::zeroed();
    |                              ^^^^^^^^^^^^^
@@ -89,7 +89,7 @@ LL |         let _val: (i32, !) = mem::zeroed();
    = note: the `!` type has no valid value
 
 error: the type `(i32, !)` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:55:30
+  --> $DIR/invalid_value.rs:65:30
    |
 LL |         let _val: (i32, !) = mem::uninitialized();
    |                              ^^^^^^^^^^^^^^^^^^^^
@@ -100,7 +100,7 @@ LL |         let _val: (i32, !) = mem::uninitialized();
    = note: integers must not be uninitialized
 
 error: the type `Void` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:57:26
+  --> $DIR/invalid_value.rs:67:26
    |
 LL |         let _val: Void = mem::zeroed();
    |                          ^^^^^^^^^^^^^
@@ -108,10 +108,14 @@ LL |         let _val: Void = mem::zeroed();
    |                          this code causes undefined behavior when executed
    |                          help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
    |
-   = note: enums with no variants have no valid value
+note: enums with no inhabited variants have no valid value
+  --> $DIR/invalid_value.rs:12:1
+   |
+LL | enum Void {}
+   | ^^^^^^^^^
 
 error: the type `Void` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:58:26
+  --> $DIR/invalid_value.rs:68:26
    |
 LL |         let _val: Void = mem::uninitialized();
    |                          ^^^^^^^^^^^^^^^^^^^^
@@ -119,10 +123,14 @@ LL |         let _val: Void = mem::uninitialized();
    |                          this code causes undefined behavior when executed
    |                          help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
    |
-   = note: enums with no variants have no valid value
+note: enums with no inhabited variants have no valid value
+  --> $DIR/invalid_value.rs:12:1
+   |
+LL | enum Void {}
+   | ^^^^^^^^^
 
 error: the type `&i32` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:60:34
+  --> $DIR/invalid_value.rs:70:34
    |
 LL |         let _val: &'static i32 = mem::zeroed();
    |                                  ^^^^^^^^^^^^^
@@ -133,7 +141,7 @@ LL |         let _val: &'static i32 = mem::zeroed();
    = note: references must be non-null
 
 error: the type `&i32` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:61:34
+  --> $DIR/invalid_value.rs:71:34
    |
 LL |         let _val: &'static i32 = mem::uninitialized();
    |                                  ^^^^^^^^^^^^^^^^^^^^
@@ -144,7 +152,7 @@ LL |         let _val: &'static i32 = mem::uninitialized();
    = note: references must be non-null
 
 error: the type `Ref` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:63:25
+  --> $DIR/invalid_value.rs:73:25
    |
 LL |         let _val: Ref = mem::zeroed();
    |                         ^^^^^^^^^^^^^
@@ -153,13 +161,13 @@ LL |         let _val: Ref = mem::zeroed();
    |                         help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
    |
 note: references must be non-null (in this struct field)
-  --> $DIR/uninitialized-zeroed.rs:14:12
+  --> $DIR/invalid_value.rs:14:12
    |
 LL | struct Ref(&'static i32);
    |            ^^^^^^^^^^^^
 
 error: the type `Ref` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:64:25
+  --> $DIR/invalid_value.rs:74:25
    |
 LL |         let _val: Ref = mem::uninitialized();
    |                         ^^^^^^^^^^^^^^^^^^^^
@@ -168,13 +176,13 @@ LL |         let _val: Ref = mem::uninitialized();
    |                         help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
    |
 note: references must be non-null (in this struct field)
-  --> $DIR/uninitialized-zeroed.rs:14:12
+  --> $DIR/invalid_value.rs:14:12
    |
 LL | struct Ref(&'static i32);
    |            ^^^^^^^^^^^^
 
 error: the type `fn()` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:66:26
+  --> $DIR/invalid_value.rs:76:26
    |
 LL |         let _val: fn() = mem::zeroed();
    |                          ^^^^^^^^^^^^^
@@ -185,7 +193,7 @@ LL |         let _val: fn() = mem::zeroed();
    = note: function pointers must be non-null
 
 error: the type `fn()` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:67:26
+  --> $DIR/invalid_value.rs:77:26
    |
 LL |         let _val: fn() = mem::uninitialized();
    |                          ^^^^^^^^^^^^^^^^^^^^
@@ -196,7 +204,7 @@ LL |         let _val: fn() = mem::uninitialized();
    = note: function pointers must be non-null
 
 error: the type `Wrap<fn()>` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:69:32
+  --> $DIR/invalid_value.rs:79:32
    |
 LL |         let _val: Wrap<fn()> = mem::zeroed();
    |                                ^^^^^^^^^^^^^
@@ -205,13 +213,13 @@ LL |         let _val: Wrap<fn()> = mem::zeroed();
    |                                help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
    |
 note: function pointers must be non-null (in this struct field)
-  --> $DIR/uninitialized-zeroed.rs:17:18
+  --> $DIR/invalid_value.rs:17:18
    |
 LL | struct Wrap<T> { wrapped: T }
    |                  ^^^^^^^^^^
 
 error: the type `Wrap<fn()>` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:70:32
+  --> $DIR/invalid_value.rs:80:32
    |
 LL |         let _val: Wrap<fn()> = mem::uninitialized();
    |                                ^^^^^^^^^^^^^^^^^^^^
@@ -220,13 +228,13 @@ LL |         let _val: Wrap<fn()> = mem::uninitialized();
    |                                help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
    |
 note: function pointers must be non-null (in this struct field)
-  --> $DIR/uninitialized-zeroed.rs:17:18
+  --> $DIR/invalid_value.rs:17:18
    |
 LL | struct Wrap<T> { wrapped: T }
    |                  ^^^^^^^^^^
 
 error: the type `WrapEnum<fn()>` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:72:36
+  --> $DIR/invalid_value.rs:82:36
    |
 LL |         let _val: WrapEnum<fn()> = mem::zeroed();
    |                                    ^^^^^^^^^^^^^
@@ -234,14 +242,14 @@ LL |         let _val: WrapEnum<fn()> = mem::zeroed();
    |                                    this code causes undefined behavior when executed
    |                                    help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
    |
-note: function pointers must be non-null (in this enum field)
-  --> $DIR/uninitialized-zeroed.rs:18:28
+note: function pointers must be non-null (in this field of the only potentially inhabited enum variant)
+  --> $DIR/invalid_value.rs:18:28
    |
 LL | enum WrapEnum<T> { Wrapped(T) }
    |                            ^
 
 error: the type `WrapEnum<fn()>` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:73:36
+  --> $DIR/invalid_value.rs:83:36
    |
 LL |         let _val: WrapEnum<fn()> = mem::uninitialized();
    |                                    ^^^^^^^^^^^^^^^^^^^^
@@ -249,14 +257,14 @@ LL |         let _val: WrapEnum<fn()> = mem::uninitialized();
    |                                    this code causes undefined behavior when executed
    |                                    help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
    |
-note: function pointers must be non-null (in this enum field)
-  --> $DIR/uninitialized-zeroed.rs:18:28
+note: function pointers must be non-null (in this field of the only potentially inhabited enum variant)
+  --> $DIR/invalid_value.rs:18:28
    |
 LL | enum WrapEnum<T> { Wrapped(T) }
    |                            ^
 
 error: the type `Wrap<(RefPair, i32)>` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:75:42
+  --> $DIR/invalid_value.rs:85:42
    |
 LL |         let _val: Wrap<(RefPair, i32)> = mem::zeroed();
    |                                          ^^^^^^^^^^^^^
@@ -265,13 +273,13 @@ LL |         let _val: Wrap<(RefPair, i32)> = mem::zeroed();
    |                                          help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
    |
 note: references must be non-null (in this struct field)
-  --> $DIR/uninitialized-zeroed.rs:15:16
+  --> $DIR/invalid_value.rs:15:16
    |
 LL | struct RefPair((&'static i32, i32));
    |                ^^^^^^^^^^^^^^^^^^^
 
 error: the type `Wrap<(RefPair, i32)>` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:76:42
+  --> $DIR/invalid_value.rs:86:42
    |
 LL |         let _val: Wrap<(RefPair, i32)> = mem::uninitialized();
    |                                          ^^^^^^^^^^^^^^^^^^^^
@@ -280,13 +288,13 @@ LL |         let _val: Wrap<(RefPair, i32)> = mem::uninitialized();
    |                                          help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
    |
 note: references must be non-null (in this struct field)
-  --> $DIR/uninitialized-zeroed.rs:15:16
+  --> $DIR/invalid_value.rs:15:16
    |
 LL | struct RefPair((&'static i32, i32));
    |                ^^^^^^^^^^^^^^^^^^^
 
 error: the type `NonNull<i32>` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:78:34
+  --> $DIR/invalid_value.rs:88:34
    |
 LL |         let _val: NonNull<i32> = mem::zeroed();
    |                                  ^^^^^^^^^^^^^
@@ -297,7 +305,7 @@ LL |         let _val: NonNull<i32> = mem::zeroed();
    = note: `std::ptr::NonNull<i32>` must be non-null
 
 error: the type `NonNull<i32>` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:79:34
+  --> $DIR/invalid_value.rs:89:34
    |
 LL |         let _val: NonNull<i32> = mem::uninitialized();
    |                                  ^^^^^^^^^^^^^^^^^^^^
@@ -308,7 +316,7 @@ LL |         let _val: NonNull<i32> = mem::uninitialized();
    = note: `std::ptr::NonNull<i32>` must be non-null
 
 error: the type `*const dyn Send` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:81:37
+  --> $DIR/invalid_value.rs:91:37
    |
 LL |         let _val: *const dyn Send = mem::zeroed();
    |                                     ^^^^^^^^^^^^^
@@ -319,7 +327,7 @@ LL |         let _val: *const dyn Send = mem::zeroed();
    = note: the vtable of a wide raw pointer must be non-null
 
 error: the type `*const dyn Send` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:82:37
+  --> $DIR/invalid_value.rs:92:37
    |
 LL |         let _val: *const dyn Send = mem::uninitialized();
    |                                     ^^^^^^^^^^^^^^^^^^^^
@@ -330,7 +338,7 @@ LL |         let _val: *const dyn Send = mem::uninitialized();
    = note: the vtable of a wide raw pointer must be non-null
 
 error: the type `[fn(); 2]` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:84:31
+  --> $DIR/invalid_value.rs:94:31
    |
 LL |         let _val: [fn(); 2] = mem::zeroed();
    |                               ^^^^^^^^^^^^^
@@ -341,7 +349,7 @@ LL |         let _val: [fn(); 2] = mem::zeroed();
    = note: function pointers must be non-null
 
 error: the type `[fn(); 2]` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:85:31
+  --> $DIR/invalid_value.rs:95:31
    |
 LL |         let _val: [fn(); 2] = mem::uninitialized();
    |                               ^^^^^^^^^^^^^^^^^^^^
@@ -351,8 +359,68 @@ LL |         let _val: [fn(); 2] = mem::uninitialized();
    |
    = note: function pointers must be non-null
 
+error: the type `TwoUninhabited` does not permit zero-initialization
+  --> $DIR/invalid_value.rs:97:36
+   |
+LL |         let _val: TwoUninhabited = mem::zeroed();
+   |                                    ^^^^^^^^^^^^^
+   |                                    |
+   |                                    this code causes undefined behavior when executed
+   |                                    help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+   |
+note: enums with no inhabited variants have no valid value
+  --> $DIR/invalid_value.rs:42:1
+   |
+LL | enum TwoUninhabited {
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: the type `TwoUninhabited` does not permit being left uninitialized
+  --> $DIR/invalid_value.rs:98:36
+   |
+LL |         let _val: TwoUninhabited = mem::uninitialized();
+   |                                    ^^^^^^^^^^^^^^^^^^^^
+   |                                    |
+   |                                    this code causes undefined behavior when executed
+   |                                    help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+   |
+note: enums with no inhabited variants have no valid value
+  --> $DIR/invalid_value.rs:42:1
+   |
+LL | enum TwoUninhabited {
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: the type `OneFruitNonZero` does not permit zero-initialization
+  --> $DIR/invalid_value.rs:100:37
+   |
+LL |         let _val: OneFruitNonZero = mem::zeroed();
+   |                                     ^^^^^^^^^^^^^
+   |                                     |
+   |                                     this code causes undefined behavior when executed
+   |                                     help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+   |
+note: `std::num::NonZeroU32` must be non-null (in this field of the only potentially inhabited enum variant)
+  --> $DIR/invalid_value.rs:39:12
+   |
+LL |     Banana(NonZeroU32),
+   |            ^^^^^^^^^^
+
+error: the type `OneFruitNonZero` does not permit being left uninitialized
+  --> $DIR/invalid_value.rs:101:37
+   |
+LL |         let _val: OneFruitNonZero = mem::uninitialized();
+   |                                     ^^^^^^^^^^^^^^^^^^^^
+   |                                     |
+   |                                     this code causes undefined behavior when executed
+   |                                     help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+   |
+note: `std::num::NonZeroU32` must be non-null (in this field of the only potentially inhabited enum variant)
+  --> $DIR/invalid_value.rs:39:12
+   |
+LL |     Banana(NonZeroU32),
+   |            ^^^^^^^^^^
+
 error: the type `bool` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:89:26
+  --> $DIR/invalid_value.rs:105:26
    |
 LL |         let _val: bool = mem::uninitialized();
    |                          ^^^^^^^^^^^^^^^^^^^^
@@ -363,7 +431,7 @@ LL |         let _val: bool = mem::uninitialized();
    = note: booleans must be either `true` or `false`
 
 error: the type `Wrap<char>` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:92:32
+  --> $DIR/invalid_value.rs:108:32
    |
 LL |         let _val: Wrap<char> = mem::uninitialized();
    |                                ^^^^^^^^^^^^^^^^^^^^
@@ -372,13 +440,13 @@ LL |         let _val: Wrap<char> = mem::uninitialized();
    |                                help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
    |
 note: characters must be a valid Unicode codepoint (in this struct field)
-  --> $DIR/uninitialized-zeroed.rs:17:18
+  --> $DIR/invalid_value.rs:17:18
    |
 LL | struct Wrap<T> { wrapped: T }
    |                  ^^^^^^^^^^
 
 error: the type `NonBig` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:95:28
+  --> $DIR/invalid_value.rs:111:28
    |
 LL |         let _val: NonBig = mem::uninitialized();
    |                            ^^^^^^^^^^^^^^^^^^^^
@@ -389,7 +457,7 @@ LL |         let _val: NonBig = mem::uninitialized();
    = note: `NonBig` must be initialized inside its custom valid range
 
 error: the type `Fruit` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:98:27
+  --> $DIR/invalid_value.rs:114:27
    |
 LL |         let _val: Fruit = mem::uninitialized();
    |                           ^^^^^^^^^^^^^^^^^^^^
@@ -397,14 +465,14 @@ LL |         let _val: Fruit = mem::uninitialized();
    |                           this code causes undefined behavior when executed
    |                           help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
    |
-note: enums have to be initialized to a variant
-  --> $DIR/uninitialized-zeroed.rs:26:1
+note: enums with multiple inhabited variants have to be initialized to a variant
+  --> $DIR/invalid_value.rs:26:1
    |
 LL | enum Fruit {
    | ^^^^^^^^^^
 
 error: the type `[bool; 2]` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:101:31
+  --> $DIR/invalid_value.rs:117:31
    |
 LL |         let _val: [bool; 2] = mem::uninitialized();
    |                               ^^^^^^^^^^^^^^^^^^^^
@@ -415,7 +483,7 @@ LL |         let _val: [bool; 2] = mem::uninitialized();
    = note: booleans must be either `true` or `false`
 
 error: the type `i32` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:104:25
+  --> $DIR/invalid_value.rs:120:25
    |
 LL |         let _val: i32 = mem::uninitialized();
    |                         ^^^^^^^^^^^^^^^^^^^^
@@ -426,7 +494,7 @@ LL |         let _val: i32 = mem::uninitialized();
    = note: integers must not be uninitialized
 
 error: the type `f32` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:107:25
+  --> $DIR/invalid_value.rs:123:25
    |
 LL |         let _val: f32 = mem::uninitialized();
    |                         ^^^^^^^^^^^^^^^^^^^^
@@ -437,7 +505,7 @@ LL |         let _val: f32 = mem::uninitialized();
    = note: floats must not be uninitialized
 
 error: the type `*const ()` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:110:31
+  --> $DIR/invalid_value.rs:126:31
    |
 LL |         let _val: *const () = mem::uninitialized();
    |                               ^^^^^^^^^^^^^^^^^^^^
@@ -448,7 +516,7 @@ LL |         let _val: *const () = mem::uninitialized();
    = note: raw pointers must not be uninitialized
 
 error: the type `*const [()]` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:113:33
+  --> $DIR/invalid_value.rs:129:33
    |
 LL |         let _val: *const [()] = mem::uninitialized();
    |                                 ^^^^^^^^^^^^^^^^^^^^
@@ -458,8 +526,23 @@ LL |         let _val: *const [()] = mem::uninitialized();
    |
    = note: raw pointers must not be uninitialized
 
+error: the type `Result<i32, i32>` does not permit being left uninitialized
+  --> $DIR/invalid_value.rs:134:38
+   |
+LL |         let _val: Result<i32, i32> = mem::uninitialized();
+   |                                      ^^^^^^^^^^^^^^^^^^^^
+   |                                      |
+   |                                      this code causes undefined behavior when executed
+   |                                      help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+   |
+note: enums with multiple inhabited variants have to be initialized to a variant
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+   |
+LL | pub enum Result<T, E> {
+   | ^^^^^^^^^^^^^^^^^^^^^
+
 error: the type `&i32` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:116:34
+  --> $DIR/invalid_value.rs:142:34
    |
 LL |         let _val: &'static i32 = mem::transmute(0usize);
    |                                  ^^^^^^^^^^^^^^^^^^^^^^
@@ -470,7 +553,7 @@ LL |         let _val: &'static i32 = mem::transmute(0usize);
    = note: references must be non-null
 
 error: the type `&[i32]` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:117:36
+  --> $DIR/invalid_value.rs:143:36
    |
 LL |         let _val: &'static [i32] = mem::transmute((0usize, 0usize));
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -481,7 +564,7 @@ LL |         let _val: &'static [i32] = mem::transmute((0usize, 0usize));
    = note: references must be non-null
 
 error: the type `NonZeroU32` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:118:32
+  --> $DIR/invalid_value.rs:144:32
    |
 LL |         let _val: NonZeroU32 = mem::transmute(0);
    |                                ^^^^^^^^^^^^^^^^^
@@ -492,7 +575,7 @@ LL |         let _val: NonZeroU32 = mem::transmute(0);
    = note: `std::num::NonZeroU32` must be non-null
 
 error: the type `NonNull<i32>` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:121:34
+  --> $DIR/invalid_value.rs:147:34
    |
 LL |         let _val: NonNull<i32> = MaybeUninit::zeroed().assume_init();
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -503,7 +586,7 @@ LL |         let _val: NonNull<i32> = MaybeUninit::zeroed().assume_init();
    = note: `std::ptr::NonNull<i32>` must be non-null
 
 error: the type `NonNull<i32>` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:122:34
+  --> $DIR/invalid_value.rs:148:34
    |
 LL |         let _val: NonNull<i32> = MaybeUninit::uninit().assume_init();
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -514,7 +597,7 @@ LL |         let _val: NonNull<i32> = MaybeUninit::uninit().assume_init();
    = note: `std::ptr::NonNull<i32>` must be non-null
 
 error: the type `bool` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:123:26
+  --> $DIR/invalid_value.rs:149:26
    |
 LL |         let _val: bool = MaybeUninit::uninit().assume_init();
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -524,5 +607,5 @@ LL |         let _val: bool = MaybeUninit::uninit().assume_init();
    |
    = note: booleans must be either `true` or `false`
 
-error: aborting due to 43 previous errors
+error: aborting due to 48 previous errors
 
diff --git a/src/test/ui/loops/loop-proper-liveness.stderr b/src/test/ui/loops/loop-proper-liveness.stderr
index 14e86aee059..f9d94b6810c 100644
--- a/src/test/ui/loops/loop-proper-liveness.stderr
+++ b/src/test/ui/loops/loop-proper-liveness.stderr
@@ -8,6 +8,10 @@ LL |     println!("{:?}", x);
    |                      ^ `x` used here but it isn't initialized
    |
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let x: i32 = 0;
+   |                +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/macros/format-parse-errors.stderr b/src/test/ui/macros/format-parse-errors.stderr
index 1a7578e6076..f9ea4c63377 100644
--- a/src/test/ui/macros/format-parse-errors.stderr
+++ b/src/test/ui/macros/format-parse-errors.stderr
@@ -22,7 +22,7 @@ error: positional arguments cannot follow named arguments
   --> $DIR/format-parse-errors.rs:10:9
    |
 LL |         foo = foo,
-   |               --- named argument
+   |         --------- named argument
 LL |         bar,
    |         ^^^ positional arguments must be before named arguments
 
diff --git a/src/test/ui/macros/issue-99265.stderr b/src/test/ui/macros/issue-99265.stderr
index 2bfeedd7d07..9185dbff61e 100644
--- a/src/test/ui/macros/issue-99265.stderr
+++ b/src/test/ui/macros/issue-99265.stderr
@@ -77,18 +77,18 @@ help: use the named argument by name to avoid ambiguity
 LL |     println!("Hello {:width$}!", "x", width = 5);
    |                       ~~~~~~
 
-warning: named argument `width` is not used by name
-  --> $DIR/issue-99265.rs:23:46
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99265.rs:23:33
    |
 LL |     println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
-   |                       --                     ^^^^^ this named argument is referred to by position in formatting string
-   |                       |
-   |                       this formatting argument uses named argument `width` by position
+   |                     --------    ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
-LL |     println!("Hello {:width$.2$}!", f = 0.02f32, width = 5, precision = 2);
-   |                       ~~~~~~
+LL |     println!("Hello {f:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
+   |                      +
 
 warning: named argument `precision` is not used by name
   --> $DIR/issue-99265.rs:23:57
@@ -103,31 +103,31 @@ help: use the named argument by name to avoid ambiguity
 LL |     println!("Hello {:1$.precision$}!", f = 0.02f32, width = 5, precision = 2);
    |                          ~~~~~~~~~~
 
-warning: named argument `f` is not used by name
-  --> $DIR/issue-99265.rs:23:33
+warning: named argument `width` is not used by name
+  --> $DIR/issue-99265.rs:23:46
    |
 LL |     println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
-   |                     --          ^ this named argument is referred to by position in formatting string
-   |                     |
-   |                     this formatting argument uses named argument `f` by position
+   |                       --                     ^^^^^ this named argument is referred to by position in formatting string
+   |                       |
+   |                       this formatting argument uses named argument `width` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
-LL |     println!("Hello {f:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
-   |                      +
+LL |     println!("Hello {:width$.2$}!", f = 0.02f32, width = 5, precision = 2);
+   |                       ~~~~~~
 
-warning: named argument `width` is not used by name
-  --> $DIR/issue-99265.rs:31:47
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99265.rs:31:34
    |
 LL |     println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
-   |                        --                     ^^^^^ this named argument is referred to by position in formatting string
-   |                        |
-   |                        this formatting argument uses named argument `width` by position
+   |                     ---------    ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
-LL |     println!("Hello {0:width$.2$}!", f = 0.02f32, width = 5, precision = 2);
-   |                        ~~~~~~
+LL |     println!("Hello {f:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
+   |                      ~
 
 warning: named argument `precision` is not used by name
   --> $DIR/issue-99265.rs:31:58
@@ -142,32 +142,32 @@ help: use the named argument by name to avoid ambiguity
 LL |     println!("Hello {0:1$.precision$}!", f = 0.02f32, width = 5, precision = 2);
    |                           ~~~~~~~~~~
 
-warning: named argument `f` is not used by name
-  --> $DIR/issue-99265.rs:31:34
+warning: named argument `width` is not used by name
+  --> $DIR/issue-99265.rs:31:47
    |
 LL |     println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
-   |                      -           ^ this named argument is referred to by position in formatting string
-   |                      |
-   |                      this formatting argument uses named argument `f` by position
+   |                        --                     ^^^^^ this named argument is referred to by position in formatting string
+   |                        |
+   |                        this formatting argument uses named argument `width` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
-LL |     println!("Hello {f:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
-   |                      ~
+LL |     println!("Hello {0:width$.2$}!", f = 0.02f32, width = 5, precision = 2);
+   |                        ~~~~~~
 
-warning: named argument `width` is not used by name
-  --> $DIR/issue-99265.rs:52:9
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99265.rs:49:9
    |
 LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
-   |                       -- this formatting argument uses named argument `width` by position
+   |                    --------- this formatting argument uses named argument `f` by position
 ...
-LL |         width = 5,
-   |         ^^^^^ this named argument is referred to by position in formatting string
+LL |         f = 0.02f32,
+   |         ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
-LL |         "{}, Hello {1:width$.3$} {4:5$.6$}! {1}",
-   |                       ~~~~~~
+LL |         "{}, Hello {f:2$.3$} {4:5$.6$}! {1}",
+   |                     ~
 
 warning: named argument `precision` is not used by name
   --> $DIR/issue-99265.rs:54:9
@@ -183,33 +183,33 @@ help: use the named argument by name to avoid ambiguity
 LL |         "{}, Hello {1:2$.precision$} {4:5$.6$}! {1}",
    |                          ~~~~~~~~~~
 
-warning: named argument `f` is not used by name
-  --> $DIR/issue-99265.rs:49:9
+warning: named argument `width` is not used by name
+  --> $DIR/issue-99265.rs:52:9
    |
 LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
-   |                     - this formatting argument uses named argument `f` by position
+   |                       -- this formatting argument uses named argument `width` by position
 ...
-LL |         f = 0.02f32,
-   |         ^ this named argument is referred to by position in formatting string
+LL |         width = 5,
+   |         ^^^^^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
-LL |         "{}, Hello {f:2$.3$} {4:5$.6$}! {1}",
-   |                     ~
+LL |         "{}, Hello {1:width$.3$} {4:5$.6$}! {1}",
+   |                       ~~~~~~
 
-warning: named argument `width2` is not used by name
-  --> $DIR/issue-99265.rs:58:9
+warning: named argument `g` is not used by name
+  --> $DIR/issue-99265.rs:56:9
    |
 LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
-   |                                 -- this formatting argument uses named argument `width2` by position
+   |                              --------- this formatting argument uses named argument `g` by position
 ...
-LL |         width2 = 5,
-   |         ^^^^^^ this named argument is referred to by position in formatting string
+LL |         g = 0.02f32,
+   |         ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
-LL |         "{}, Hello {1:2$.3$} {4:width2$.6$}! {1}",
-   |                                 ~~~~~~~
+LL |         "{}, Hello {1:2$.3$} {g:5$.6$}! {1}",
+   |                               ~
 
 warning: named argument `precision2` is not used by name
   --> $DIR/issue-99265.rs:60:9
@@ -225,25 +225,25 @@ help: use the named argument by name to avoid ambiguity
 LL |         "{}, Hello {1:2$.3$} {4:5$.precision2$}! {1}",
    |                                    ~~~~~~~~~~~
 
-warning: named argument `g` is not used by name
-  --> $DIR/issue-99265.rs:56:9
+warning: named argument `width2` is not used by name
+  --> $DIR/issue-99265.rs:58:9
    |
 LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
-   |                               - this formatting argument uses named argument `g` by position
+   |                                 -- this formatting argument uses named argument `width2` by position
 ...
-LL |         g = 0.02f32,
-   |         ^ this named argument is referred to by position in formatting string
+LL |         width2 = 5,
+   |         ^^^^^^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
-LL |         "{}, Hello {1:2$.3$} {g:5$.6$}! {1}",
-   |                               ~
+LL |         "{}, Hello {1:2$.3$} {4:width2$.6$}! {1}",
+   |                                 ~~~~~~~
 
 warning: named argument `f` is not used by name
   --> $DIR/issue-99265.rs:49:9
    |
 LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
-   |                                          - this formatting argument uses named argument `f` by position
+   |                                         --- this formatting argument uses named argument `f` by position
 ...
 LL |         f = 0.02f32,
    |         ^ this named argument is referred to by position in formatting string
@@ -257,7 +257,7 @@ warning: named argument `f` is not used by name
   --> $DIR/issue-99265.rs:64:31
    |
 LL |     println!("Hello {:0.1}!", f = 0.02f32);
-   |                     --        ^ this named argument is referred to by position in formatting string
+   |                     ------    ^ this named argument is referred to by position in formatting string
    |                     |
    |                     this formatting argument uses named argument `f` by position
    |
@@ -270,9 +270,9 @@ warning: named argument `f` is not used by name
   --> $DIR/issue-99265.rs:68:32
    |
 LL |     println!("Hello {0:0.1}!", f = 0.02f32);
-   |                      -         ^ this named argument is referred to by position in formatting string
-   |                      |
-   |                      this formatting argument uses named argument `f` by position
+   |                     -------    ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -283,6 +283,19 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:79:23
    |
 LL |     println!("{:0$}", v = val);
+   |               -----   ^ this named argument is referred to by position in formatting string
+   |               |
+   |               this formatting argument uses named argument `v` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("{v:0$}", v = val);
+   |                +
+
+warning: named argument `v` is not used by name
+  --> $DIR/issue-99265.rs:79:23
+   |
+LL |     println!("{:0$}", v = val);
    |                 --    ^ this named argument is referred to by position in formatting string
    |                 |
    |                 this formatting argument uses named argument `v` by position
@@ -293,17 +306,17 @@ LL |     println!("{:v$}", v = val);
    |                 ~~
 
 warning: named argument `v` is not used by name
-  --> $DIR/issue-99265.rs:79:23
+  --> $DIR/issue-99265.rs:84:24
    |
-LL |     println!("{:0$}", v = val);
-   |               --      ^ this named argument is referred to by position in formatting string
+LL |     println!("{0:0$}", v = val);
+   |               ------   ^ this named argument is referred to by position in formatting string
    |               |
    |               this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
 LL |     println!("{v:0$}", v = val);
-   |                +
+   |                ~
 
 warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:84:24
@@ -319,30 +332,17 @@ LL |     println!("{0:v$}", v = val);
    |                  ~~
 
 warning: named argument `v` is not used by name
-  --> $DIR/issue-99265.rs:84:24
-   |
-LL |     println!("{0:0$}", v = val);
-   |                -       ^ this named argument is referred to by position in formatting string
-   |                |
-   |                this formatting argument uses named argument `v` by position
-   |
-help: use the named argument by name to avoid ambiguity
-   |
-LL |     println!("{v:0$}", v = val);
-   |                ~
-
-warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:89:26
    |
 LL |     println!("{:0$.0$}", v = val);
-   |                 --       ^ this named argument is referred to by position in formatting string
-   |                 |
-   |                 this formatting argument uses named argument `v` by position
+   |               --------   ^ this named argument is referred to by position in formatting string
+   |               |
+   |               this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
-LL |     println!("{:v$.0$}", v = val);
-   |                 ~~
+LL |     println!("{v:0$.0$}", v = val);
+   |                +
 
 warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:89:26
@@ -361,27 +361,27 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:89:26
    |
 LL |     println!("{:0$.0$}", v = val);
-   |               --         ^ this named argument is referred to by position in formatting string
-   |               |
-   |               this formatting argument uses named argument `v` by position
+   |                 --       ^ this named argument is referred to by position in formatting string
+   |                 |
+   |                 this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
-LL |     println!("{v:0$.0$}", v = val);
-   |                +
+LL |     println!("{:v$.0$}", v = val);
+   |                 ~~
 
 warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:96:27
    |
 LL |     println!("{0:0$.0$}", v = val);
-   |                  --       ^ this named argument is referred to by position in formatting string
-   |                  |
-   |                  this formatting argument uses named argument `v` by position
+   |               ---------   ^ this named argument is referred to by position in formatting string
+   |               |
+   |               this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
-LL |     println!("{0:v$.0$}", v = val);
-   |                  ~~
+LL |     println!("{v:0$.0$}", v = val);
+   |                ~
 
 warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:96:27
@@ -400,14 +400,14 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:96:27
    |
 LL |     println!("{0:0$.0$}", v = val);
-   |                -          ^ this named argument is referred to by position in formatting string
-   |                |
-   |                this formatting argument uses named argument `v` by position
+   |                  --       ^ this named argument is referred to by position in formatting string
+   |                  |
+   |                  this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
-LL |     println!("{v:0$.0$}", v = val);
-   |                ~
+LL |     println!("{0:v$.0$}", v = val);
+   |                  ~~
 
 warning: named argument `a` is not used by name
   --> $DIR/issue-99265.rs:104:28
@@ -426,28 +426,28 @@ warning: named argument `a` is not used by name
   --> $DIR/issue-99265.rs:104:28
    |
 LL |     println!("{} {a} {0}", a = 1);
-   |                       -    ^ this named argument is referred to by position in formatting string
-   |                       |
-   |                       this formatting argument uses named argument `a` by position
+   |                      ---   ^ this named argument is referred to by position in formatting string
+   |                      |
+   |                      this formatting argument uses named argument `a` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
 LL |     println!("{} {a} {a}", a = 1);
    |                       ~
 
-warning: named argument `b` is not used by name
-  --> $DIR/issue-99265.rs:115:23
+warning: named argument `a` is not used by name
+  --> $DIR/issue-99265.rs:115:14
    |
 LL |                 {:1$.2$}",
-   |                   -- this formatting argument uses named argument `b` by position
+   |                 -------- this formatting argument uses named argument `a` by position
 ...
 LL |              a = 1.0, b = 1, c = 2,
-   |                       ^ this named argument is referred to by position in formatting string
+   |              ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
-LL |                 {:b$.2$}",
-   |                   ~~
+LL |                 {a:1$.2$}",
+   |                  +
 
 warning: named argument `c` is not used by name
   --> $DIR/issue-99265.rs:115:30
@@ -463,33 +463,33 @@ help: use the named argument by name to avoid ambiguity
 LL |                 {:1$.c$}",
    |                      ~~
 
-warning: named argument `a` is not used by name
-  --> $DIR/issue-99265.rs:115:14
+warning: named argument `b` is not used by name
+  --> $DIR/issue-99265.rs:115:23
    |
 LL |                 {:1$.2$}",
-   |                 -- this formatting argument uses named argument `a` by position
+   |                   -- this formatting argument uses named argument `b` by position
 ...
 LL |              a = 1.0, b = 1, c = 2,
-   |              ^ this named argument is referred to by position in formatting string
+   |                       ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
-LL |                 {a:1$.2$}",
-   |                  +
+LL |                 {:b$.2$}",
+   |                   ~~
 
-warning: named argument `b` is not used by name
-  --> $DIR/issue-99265.rs:126:23
+warning: named argument `a` is not used by name
+  --> $DIR/issue-99265.rs:126:14
    |
 LL |                 {0:1$.2$}",
-   |                    -- this formatting argument uses named argument `b` by position
+   |                 --------- this formatting argument uses named argument `a` by position
 ...
 LL |              a = 1.0, b = 1, c = 2,
-   |                       ^ this named argument is referred to by position in formatting string
+   |              ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
-LL |                 {0:b$.2$}",
-   |                    ~~
+LL |                 {a:1$.2$}",
+   |                  ~
 
 warning: named argument `c` is not used by name
   --> $DIR/issue-99265.rs:126:30
@@ -505,32 +505,32 @@ help: use the named argument by name to avoid ambiguity
 LL |                 {0:1$.c$}",
    |                       ~~
 
-warning: named argument `a` is not used by name
-  --> $DIR/issue-99265.rs:126:14
+warning: named argument `b` is not used by name
+  --> $DIR/issue-99265.rs:126:23
    |
 LL |                 {0:1$.2$}",
-   |                  - this formatting argument uses named argument `a` by position
+   |                    -- this formatting argument uses named argument `b` by position
 ...
 LL |              a = 1.0, b = 1, c = 2,
-   |              ^ this named argument is referred to by position in formatting string
+   |                       ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
-LL |                 {a:1$.2$}",
-   |                  ~
+LL |                 {0:b$.2$}",
+   |                    ~~
 
-warning: named argument `width` is not used by name
-  --> $DIR/issue-99265.rs:132:39
+warning: named argument `x` is not used by name
+  --> $DIR/issue-99265.rs:132:30
    |
 LL |     println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2);
-   |                   --                  ^^^^^ this named argument is referred to by position in formatting string
-   |                   |
-   |                   this formatting argument uses named argument `width` by position
+   |                 --------     ^ this named argument is referred to by position in formatting string
+   |                 |
+   |                 this formatting argument uses named argument `x` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
-LL |     println!("{{{:width$.2$}}}", x = 1.0, width = 3, precision = 2);
-   |                   ~~~~~~
+LL |     println!("{{{x:1$.2$}}}", x = 1.0, width = 3, precision = 2);
+   |                  +
 
 warning: named argument `precision` is not used by name
   --> $DIR/issue-99265.rs:132:50
@@ -545,18 +545,18 @@ help: use the named argument by name to avoid ambiguity
 LL |     println!("{{{:1$.precision$}}}", x = 1.0, width = 3, precision = 2);
    |                      ~~~~~~~~~~
 
-warning: named argument `x` is not used by name
-  --> $DIR/issue-99265.rs:132:30
+warning: named argument `width` is not used by name
+  --> $DIR/issue-99265.rs:132:39
    |
 LL |     println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2);
-   |                 --           ^ this named argument is referred to by position in formatting string
-   |                 |
-   |                 this formatting argument uses named argument `x` by position
+   |                   --                  ^^^^^ this named argument is referred to by position in formatting string
+   |                   |
+   |                   this formatting argument uses named argument `width` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
-LL |     println!("{{{x:1$.2$}}}", x = 1.0, width = 3, precision = 2);
-   |                  +
+LL |     println!("{{{:width$.2$}}}", x = 1.0, width = 3, precision = 2);
+   |                   ~~~~~~
 
 warning: 42 warnings emitted
 
diff --git a/src/test/ui/macros/issue-99907.stderr b/src/test/ui/macros/issue-99907.stderr
index 4786ce003b4..eefb28dee35 100644
--- a/src/test/ui/macros/issue-99907.stderr
+++ b/src/test/ui/macros/issue-99907.stderr
@@ -2,7 +2,7 @@ warning: named argument `f` is not used by name
   --> $DIR/issue-99907.rs:5:30
    |
 LL |     println!("Hello {:.1}!", f = 0.02f32);
-   |                     --       ^ this named argument is referred to by position in formatting string
+   |                     -----    ^ this named argument is referred to by position in formatting string
    |                     |
    |                     this formatting argument uses named argument `f` by position
    |
@@ -16,7 +16,7 @@ warning: named argument `f` is not used by name
   --> $DIR/issue-99907.rs:9:31
    |
 LL |     println!("Hello {:1.1}!", f = 0.02f32);
-   |                     --        ^ this named argument is referred to by position in formatting string
+   |                     ------    ^ this named argument is referred to by position in formatting string
    |                     |
    |                     this formatting argument uses named argument `f` by position
    |
diff --git a/src/test/ui/mir/drop-elaboration-after-borrowck-error.rs b/src/test/ui/mir/drop-elaboration-after-borrowck-error.rs
index fc7341a563b..624b464ecef 100644
--- a/src/test/ui/mir/drop-elaboration-after-borrowck-error.rs
+++ b/src/test/ui/mir/drop-elaboration-after-borrowck-error.rs
@@ -3,9 +3,9 @@
 
 static A: () = {
     let a: [String; 1];
-    //~^ ERROR destructors cannot be evaluated at compile-time
+    //~^ ERROR destructor of
     a[0] = String::new();
-    //~^ ERROR destructors cannot be evaluated at compile-time
+    //~^ ERROR destructor of
     //~| ERROR binding `a` isn't initialized
 };
 
@@ -14,9 +14,9 @@ struct B<T>([T; 1]);
 impl<T> B<T> {
     pub const fn f(mut self, other: T) -> Self {
         let _this = self;
-        //~^ ERROR destructors cannot be evaluated at compile-time
+        //~^ ERROR destructor of
         self.0[0] = other;
-        //~^ ERROR destructors cannot be evaluated at compile-time
+        //~^ ERROR destructor of
         //~| ERROR use of moved value
         self
     }
diff --git a/src/test/ui/mir/drop-elaboration-after-borrowck-error.stderr b/src/test/ui/mir/drop-elaboration-after-borrowck-error.stderr
index d8154f8d2cb..d961061729d 100644
--- a/src/test/ui/mir/drop-elaboration-after-borrowck-error.stderr
+++ b/src/test/ui/mir/drop-elaboration-after-borrowck-error.stderr
@@ -1,17 +1,17 @@
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `String` cannot be evaluated at compile-time
   --> $DIR/drop-elaboration-after-borrowck-error.rs:7:5
    |
 LL |     a[0] = String::new();
    |     ^^^^
    |     |
-   |     statics cannot evaluate destructors
+   |     the destructor for this type cannot be evaluated in statics
    |     value is dropped here
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `[String; 1]` cannot be evaluated at compile-time
   --> $DIR/drop-elaboration-after-borrowck-error.rs:5:9
    |
 LL |     let a: [String; 1];
-   |         ^ statics cannot evaluate destructors
+   |         ^ the destructor for this type cannot be evaluated in statics
 ...
 LL | };
    | - value is dropped here
@@ -24,21 +24,26 @@ LL |     let a: [String; 1];
 LL |
 LL |     a[0] = String::new();
    |     ^^^^ `a` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let a: [String; 1] = todo!();
+   |                        +++++++++
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `T` cannot be evaluated at compile-time
   --> $DIR/drop-elaboration-after-borrowck-error.rs:18:9
    |
 LL |         self.0[0] = other;
    |         ^^^^^^^^^
    |         |
-   |         constant functions cannot evaluate destructors
+   |         the destructor for this type cannot be evaluated in constant functions
    |         value is dropped here
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `B<T>` cannot be evaluated at compile-time
   --> $DIR/drop-elaboration-after-borrowck-error.rs:16:13
    |
 LL |         let _this = self;
-   |             ^^^^^ constant functions cannot evaluate destructors
+   |             ^^^^^ the destructor for this type cannot be evaluated in constant functions
 ...
 LL |     }
    |     - value is dropped here
diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr
index 71469bfec2d..92d545b7366 100644
--- a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr
+++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr
@@ -23,7 +23,7 @@ LL |     a.iter().map(|_: &(u16, u16)| 45);
    |              expected due to this
    |
    = note: expected closure signature `fn(&(u32, u32)) -> _`
-              found closure signature `for<'r> fn(&'r (u16, u16)) -> _`
+              found closure signature `for<'a> fn(&'a (u16, u16)) -> _`
 note: required by a bound in `map`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
    |
diff --git a/src/test/ui/mismatched_types/closure-mismatch.stderr b/src/test/ui/mismatched_types/closure-mismatch.stderr
index ef76ec63fda..a7ef8fa0892 100644
--- a/src/test/ui/mismatched_types/closure-mismatch.stderr
+++ b/src/test/ui/mismatched_types/closure-mismatch.stderr
@@ -13,7 +13,7 @@ error[E0308]: mismatched types
 LL |     baz(|_| ());
    |     ^^^^^^^^^^^ one type is more general than the other
    |
-   = note: expected trait `for<'r> Fn<(&'r (),)>`
+   = note: expected trait `for<'a> Fn<(&'a (),)>`
               found trait `Fn<(&(),)>`
 note: this closure does not fulfill the lifetime requirements
   --> $DIR/closure-mismatch.rs:8:9
diff --git a/src/test/ui/mismatched_types/fn-variance-1.stderr b/src/test/ui/mismatched_types/fn-variance-1.stderr
index eec6d83fe22..5794e606eeb 100644
--- a/src/test/ui/mismatched_types/fn-variance-1.stderr
+++ b/src/test/ui/mismatched_types/fn-variance-1.stderr
@@ -10,7 +10,7 @@ LL |     apply(&3, takes_mut);
    |     required by a bound introduced by this call
    |
    = note: expected function signature `fn(&{integer}) -> _`
-              found function signature `for<'r> fn(&'r mut isize) -> _`
+              found function signature `for<'a> fn(&'a mut isize) -> _`
 note: required by a bound in `apply`
   --> $DIR/fn-variance-1.rs:5:37
    |
@@ -29,7 +29,7 @@ LL |     apply(&mut 3, takes_imm);
    |     required by a bound introduced by this call
    |
    = note: expected function signature `fn(&mut {integer}) -> _`
-              found function signature `for<'r> fn(&'r isize) -> _`
+              found function signature `for<'a> fn(&'a isize) -> _`
 note: required by a bound in `apply`
   --> $DIR/fn-variance-1.rs:5:37
    |
diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr
index b11ea97d160..906001ca1e0 100644
--- a/src/test/ui/mismatched_types/issue-36053-2.stderr
+++ b/src/test/ui/mismatched_types/issue-36053-2.stderr
@@ -6,8 +6,8 @@ LL |     once::<&str>("str").fuse().filter(|a: &str| true).count();
    |                                |
    |                                expected due to this
    |
-   = note: expected closure signature `for<'r> fn(&'r &str) -> _`
-              found closure signature `for<'r> fn(&'r str) -> _`
+   = note: expected closure signature `for<'a> fn(&'a &str) -> _`
+              found closure signature `for<'a> fn(&'a str) -> _`
 note: required by a bound in `filter`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
    |
diff --git a/src/test/ui/moves/issue-72649-uninit-in-loop.stderr b/src/test/ui/moves/issue-72649-uninit-in-loop.stderr
index c7373b5be9d..974994223a3 100644
--- a/src/test/ui/moves/issue-72649-uninit-in-loop.stderr
+++ b/src/test/ui/moves/issue-72649-uninit-in-loop.stderr
@@ -47,6 +47,11 @@ LL |         let value: NonCopy;
    |             ----- binding declared here but left uninitialized
 LL |         let _used = value;
    |                     ^^^^^ `value` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |         let value: NonCopy = todo!();
+   |                            +++++++++
 
 error[E0381]: used binding `value` isn't initialized
   --> $DIR/issue-72649-uninit-in-loop.rs:69:21
@@ -56,6 +61,11 @@ LL |     let mut value: NonCopy;
 LL |     loop {
 LL |         let _used = value;
    |                     ^^^^^ `value` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let mut value: NonCopy = todo!();
+   |                            +++++++++
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/moves/move-into-dead-array-1.stderr b/src/test/ui/moves/move-into-dead-array-1.stderr
index 344a6bbf0c9..6db0f0bcbff 100644
--- a/src/test/ui/moves/move-into-dead-array-1.stderr
+++ b/src/test/ui/moves/move-into-dead-array-1.stderr
@@ -5,6 +5,11 @@ LL |     let mut a: [D; 4];
    |         ----- binding declared here but left uninitialized
 LL |     a[i] = d();
    |     ^^^^ `a` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let mut a: [D; 4] = todo!();
+   |                       +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/moves/move-of-addr-of-mut.stderr b/src/test/ui/moves/move-of-addr-of-mut.stderr
index e75f2b1c089..ddebaa0129a 100644
--- a/src/test/ui/moves/move-of-addr-of-mut.stderr
+++ b/src/test/ui/moves/move-of-addr-of-mut.stderr
@@ -7,6 +7,10 @@ LL |     std::ptr::addr_of_mut!(x);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ `x` used here but it isn't initialized
    |
    = note: this error originates in the macro `std::ptr::addr_of_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider assigning a value
+   |
+LL |     let mut x: S = todo!();
+   |                  +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr
index 59b848ea85c..d2d26b23d64 100644
--- a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr
+++ b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr
@@ -6,7 +6,7 @@ LL |         let mut closure = expect_sig(|p, y| *p = y);
    |
    = note: defining type: test::{closure#0} with closure substs [
                i16,
-               for<'r, 's, 't0> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) mut &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrNamed('t0) }) i32)),
+               for<'a, 'b, 'c> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) mut &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrNamed('c) }) i32)),
                (),
            ]
 
diff --git a/src/test/ui/nll/closure-requirements/escape-argument.stderr b/src/test/ui/nll/closure-requirements/escape-argument.stderr
index ff4e8e590e5..6355d329524 100644
--- a/src/test/ui/nll/closure-requirements/escape-argument.stderr
+++ b/src/test/ui/nll/closure-requirements/escape-argument.stderr
@@ -6,7 +6,7 @@ LL |         let mut closure = expect_sig(|p, y| *p = y);
    |
    = note: defining type: test::{closure#0} with closure substs [
                i16,
-               for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) mut &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) i32)),
+               for<'a, 'b> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) mut &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) i32)),
                (),
            ]
 
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
index 0d94fca2823..5f9724ce3db 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
@@ -6,7 +6,7 @@ LL |         |_outlives1, _outlives2, _outlives3, x, y| {
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
-               for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) u32>)),
+               for<'a, 'b> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) u32>)),
                (),
            ]
    = note: late-bound region is '_#4r
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr
index 435a5353340..ec728ebd5ad 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr
@@ -6,7 +6,7 @@ LL |     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
-               for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrNamed('t0) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('t1) }) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrNamed('t2) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrNamed('t3) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('t1) }) u32>)),
+               for<'a, 'b, 'c, 'd, 'e, 'f> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrNamed('c) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('d) }) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrNamed('e) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrNamed('f) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('d) }) u32>)),
                (),
            ]
    = note: late-bound region is '_#3r
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
index 6aafbe42c49..01293379700 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
@@ -6,7 +6,7 @@ LL |     foo(cell, |cell_a, cell_x| {
    |
    = note: defining type: case1::{closure#0} with closure substs [
                i32,
-               for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) u32>)),
+               for<'a> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) u32>)),
                (),
            ]
 
@@ -36,7 +36,7 @@ LL |     foo(cell, |cell_a, cell_x| {
    |
    = note: defining type: case2::{closure#0} with closure substs [
                i32,
-               for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) u32>)),
+               for<'a> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) u32>)),
                (),
            ]
    = note: number of external vids: 2
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
index c95907ea75e..ce85b20b344 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
@@ -6,7 +6,7 @@ LL |     establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
-               for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrNamed('t0) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('t1) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrNamed('t2) }) u32>)),
+               for<'a, 'b, 'c, 'd, 'e> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrNamed('c) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('d) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrNamed('e) }) u32>)),
                (),
            ]
    = note: late-bound region is '_#2r
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
index db58d9d6f1a..20c7967b78b 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
@@ -6,7 +6,7 @@ LL |     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
-               for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrNamed('t0) }) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('t1) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrNamed('t2) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrNamed('t3) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('t1) }) u32>)),
+               for<'a, 'b, 'c, 'd, 'e, 'f> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrNamed('c) }) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('d) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrNamed('e) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrNamed('f) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('d) }) u32>)),
                (),
            ]
    = note: late-bound region is '_#3r
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr
index be5f1e5ef1a..f7db5ab1f27 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr
@@ -6,7 +6,7 @@ LL |     establish_relationships(cell_a, cell_b, |outlives1, outlives2, x, y| {
    |
    = note: defining type: test::{closure#0} with closure substs [
                i16,
-               for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) u32>)),
+               for<'a, 'b> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) u32>)),
                (),
            ]
    = note: late-bound region is '_#3r
diff --git a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
index d18db97be57..3488edc75e1 100644
--- a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
@@ -6,7 +6,7 @@ LL |         |_outlives1, _outlives2, x, y| {
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
-               for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) u32>)),
+               for<'a, 'b> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) u32>)),
                (),
            ]
    = note: late-bound region is '_#3r
diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
index e6f88de4ee8..0dc2d0de98f 100644
--- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
@@ -6,7 +6,7 @@ LL |     establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
-               for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrNamed('t0) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('t1) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrNamed('t2) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) u32>)),
+               for<'a, 'b, 'c, 'd, 'e> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrNamed('c) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('d) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrNamed('e) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) u32>)),
                (),
            ]
    = note: late-bound region is '_#2r
diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
index 5f5fce77137..4c9e026ea52 100644
--- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
@@ -6,7 +6,7 @@ LL |     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
-               for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrNamed('t0) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('t1) }) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrNamed('t2) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrNamed('t3) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('t1) }) u32>)),
+               for<'a, 'b, 'c, 'd, 'e, 'f> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrNamed('c) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('d) }) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrNamed('e) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrNamed('f) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrNamed('d) }) u32>)),
                (),
            ]
    = note: late-bound region is '_#3r
diff --git a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr
index da89071eabd..68429142ede 100644
--- a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr
+++ b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr
@@ -6,7 +6,7 @@ LL |     expect_sig(|a, b| b); // ought to return `a`
    |
    = note: defining type: test::{closure#0} with closure substs [
                i16,
-               for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) i32)) -> &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) i32,
+               for<'a, 'b> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) i32)) -> &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) i32,
                (),
            ]
 
diff --git a/src/test/ui/nll/issue-57642-higher-ranked-subtype.stderr b/src/test/ui/nll/issue-57642-higher-ranked-subtype.stderr
index 0ae6b7c1d7f..6e96f40c0e0 100644
--- a/src/test/ui/nll/issue-57642-higher-ranked-subtype.stderr
+++ b/src/test/ui/nll/issue-57642-higher-ranked-subtype.stderr
@@ -1,11 +1,11 @@
-error[E0599]: the function or associated item `make_g` exists for fn pointer `for<'r> fn(&'r ())`, but its trait bounds were not satisfied
+error[E0599]: the function or associated item `make_g` exists for fn pointer `for<'a> fn(&'a ())`, but its trait bounds were not satisfied
   --> $DIR/issue-57642-higher-ranked-subtype.rs:31:25
    |
 LL |     let x = <fn (&())>::make_g();
-   |                         ^^^^^^ function or associated item cannot be called on `for<'r> fn(&'r ())` due to unsatisfied trait bounds
+   |                         ^^^^^^ function or associated item cannot be called on `for<'a> fn(&'a ())` due to unsatisfied trait bounds
    |
    = note: the following trait bounds were not satisfied:
-           `for<'r> fn(&'r ()): X`
+           `for<'a> fn(&'a ()): X`
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `X` defines an item `make_g`, perhaps you need to implement it
   --> $DIR/issue-57642-higher-ranked-subtype.rs:4:1
@@ -13,11 +13,11 @@ note: `X` defines an item `make_g`, perhaps you need to implement it
 LL | trait X {
    | ^^^^^^^
 
-error[E0599]: no function or associated item named `make_f` found for fn pointer `for<'r> fn(&'r ())` in the current scope
+error[E0599]: no function or associated item named `make_f` found for fn pointer `for<'a> fn(&'a ())` in the current scope
   --> $DIR/issue-57642-higher-ranked-subtype.rs:35:25
    |
 LL |     let x = <fn (&())>::make_f();
-   |                         ^^^^^^ function or associated item not found in `for<'r> fn(&'r ())`
+   |                         ^^^^^^ function or associated item not found in `for<'a> fn(&'a ())`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `Y` defines an item `make_f`, perhaps you need to implement it
diff --git a/src/test/ui/nll/issue-97997.stderr b/src/test/ui/nll/issue-97997.stderr
index 78401bbf654..46440c021f5 100644
--- a/src/test/ui/nll/issue-97997.stderr
+++ b/src/test/ui/nll/issue-97997.stderr
@@ -4,7 +4,7 @@ error: implementation of `Foo` is not general enough
 LL |     <fn(&u8) as Foo>::ASSOC;
    |     ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
-   = note: `Foo` would have to be implemented for the type `for<'r> fn(&'r u8)`
+   = note: `Foo` would have to be implemented for the type `for<'a> fn(&'a u8)`
    = note: ...but `Foo` is actually implemented for the type `fn(&'0 u8)`, for some specific lifetime `'0`
 
 error: implementation of `Foo` is not general enough
@@ -13,7 +13,7 @@ error: implementation of `Foo` is not general enough
 LL |     <fn(&u8) as Foo>::ASSOC;
    |     ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
-   = note: `Foo` would have to be implemented for the type `for<'r> fn(&'r u8)`
+   = note: `Foo` would have to be implemented for the type `for<'a> fn(&'a u8)`
    = note: ...but `Foo` is actually implemented for the type `fn(&'0 u8)`, for some specific lifetime `'0`
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/nll/match-cfg-fake-edges.stderr b/src/test/ui/nll/match-cfg-fake-edges.stderr
index 250aa482e5c..2d48a914218 100644
--- a/src/test/ui/nll/match-cfg-fake-edges.stderr
+++ b/src/test/ui/nll/match-cfg-fake-edges.stderr
@@ -9,6 +9,11 @@ LL |         _ if { x = 2; true } => 1,
 LL |         _ if {
 LL |             x;
    |             ^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x = 0;
+   |           +++
 
 error[E0382]: use of moved value: `x`
   --> $DIR/match-cfg-fake-edges.rs:35:13
diff --git a/src/test/ui/nll/match-on-borrowed.stderr b/src/test/ui/nll/match-on-borrowed.stderr
index 664f36f695c..32666529f3f 100644
--- a/src/test/ui/nll/match-on-borrowed.stderr
+++ b/src/test/ui/nll/match-on-borrowed.stderr
@@ -40,6 +40,11 @@ LL |     let n: Never;
    |         - binding declared here but left uninitialized
 LL |     match n {}
    |           ^ `n` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let n: Never = todo!();
+   |                  +++++++++
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr b/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr
index 8c47379886d..b945ffedda5 100644
--- a/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr
+++ b/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr
@@ -4,7 +4,7 @@ error: implementation of `Y` is not general enough
 LL |     let _x = <fn(&())>::make_f();
    |              ^^^^^^^^^^^^^^^^^^^ implementation of `Y` is not general enough
    |
-   = note: `Y` would have to be implemented for the type `for<'r> fn(&'r ())`
+   = note: `Y` would have to be implemented for the type `for<'a> fn(&'a ())`
    = note: ...but `Y` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0`
 
 error: implementation of `Y` is not general enough
@@ -13,7 +13,7 @@ error: implementation of `Y` is not general enough
 LL |     let _x = <fn(&())>::make_f();
    |              ^^^^^^^^^^^^^^^^^^^ implementation of `Y` is not general enough
    |
-   = note: `Y` would have to be implemented for the type `for<'r> fn(&'r ())`
+   = note: `Y` would have to be implemented for the type `for<'a> fn(&'a ())`
    = note: ...but `Y` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0`
 
 error: implementation of `Y` is not general enough
@@ -22,7 +22,7 @@ error: implementation of `Y` is not general enough
 LL |     let _x = <fn(&())>::make_f();
    |              ^^^^^^^^^^^^^^^^^^^ implementation of `Y` is not general enough
    |
-   = note: `Y` would have to be implemented for the type `for<'r> fn(&'r ())`
+   = note: `Y` would have to be implemented for the type `for<'a> fn(&'a ())`
    = note: ...but `Y` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0`
 
 error: aborting due to 3 previous errors
diff --git a/src/test/ui/nll/relate_tys/universe-violation.stderr b/src/test/ui/nll/relate_tys/universe-violation.stderr
index 6f38154e379..fe801b42c0a 100644
--- a/src/test/ui/nll/relate_tys/universe-violation.stderr
+++ b/src/test/ui/nll/relate_tys/universe-violation.stderr
@@ -4,7 +4,7 @@ error[E0308]: mismatched types
 LL |     let b: fn(&u32) -> &u32 = a;
    |                               ^ one type is more general than the other
    |
-   = note: expected fn pointer `for<'r> fn(&'r u32) -> &'r u32`
+   = note: expected fn pointer `for<'a> fn(&'a u32) -> &'a u32`
               found fn pointer `fn(&u32) -> &u32`
 
 error: aborting due to previous error
diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
index 5d9a044d107..61c7d2550ca 100644
--- a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
+++ b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
@@ -6,7 +6,7 @@ LL |     twice(cell, value, |a, b| invoke(a, b));
    |
    = note: defining type: generic::<T>::{closure#0} with closure substs [
                i16,
-               for<'r, 's> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) ()>>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) T)),
+               for<'a, 'b> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) ()>>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) T)),
                (),
            ]
    = note: number of external vids: 2
@@ -28,7 +28,7 @@ LL |     twice(cell, value, |a, b| invoke(a, b));
    |
    = note: defining type: generic_fail::<T>::{closure#0} with closure substs [
                i16,
-               for<'r, 's> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) ()>>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('s) }) T)),
+               for<'a, 'b> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('a) }) ()>>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrNamed('b) }) T)),
                (),
            ]
    = note: late-bound region is '_#2r
diff --git a/src/test/ui/oom_unwind.rs b/src/test/ui/oom_unwind.rs
index d036c817a0e..21a8fb2b22b 100644
--- a/src/test/ui/oom_unwind.rs
+++ b/src/test/ui/oom_unwind.rs
@@ -4,8 +4,6 @@
 // needs-unwind
 // only-linux
 
-#![feature(bench_black_box)]
-
 use std::hint::black_box;
 use std::mem::forget;
 use std::panic::catch_unwind;
diff --git a/src/test/ui/opt-in-copy.stderr b/src/test/ui/opt-in-copy.stderr
index 0a275f1aa41..4461567df0a 100644
--- a/src/test/ui/opt-in-copy.stderr
+++ b/src/test/ui/opt-in-copy.stderr
@@ -1,20 +1,20 @@
 error[E0204]: the trait `Copy` may not be implemented for this type
-  --> $DIR/opt-in-copy.rs:7:6
+  --> $DIR/opt-in-copy.rs:7:15
    |
 LL |     but_i_cant: CantCopyThis,
    |     ------------------------ this field does not implement `Copy`
 ...
 LL | impl Copy for IWantToCopyThis {}
-   |      ^^^^
+   |               ^^^^^^^^^^^^^^^
 
 error[E0204]: the trait `Copy` may not be implemented for this type
-  --> $DIR/opt-in-copy.rs:19:6
+  --> $DIR/opt-in-copy.rs:19:15
    |
 LL |     ButICant(CantCopyThisEither),
    |              ------------------ this field does not implement `Copy`
 ...
 LL | impl Copy for IWantToCopyThisToo {}
-   |      ^^^^
+   |               ^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/parser/bad-lit-suffixes.rs b/src/test/ui/parser/bad-lit-suffixes.rs
index 446a0940559..9724533c420 100644
--- a/src/test/ui/parser/bad-lit-suffixes.rs
+++ b/src/test/ui/parser/bad-lit-suffixes.rs
@@ -1,18 +1,18 @@
 extern
-    "C"suffix //~ ERROR suffixes on a string literal are invalid
+    "C"suffix //~ ERROR suffixes on string literals are invalid
     fn foo() {}
 
 extern
-    "C"suffix //~ ERROR suffixes on a string literal are invalid
+    "C"suffix //~ ERROR suffixes on string literals are invalid
 {}
 
 fn main() {
-    ""suffix; //~ ERROR suffixes on a string literal are invalid
-    b""suffix; //~ ERROR suffixes on a byte string literal are invalid
-    r#""#suffix; //~ ERROR suffixes on a string literal are invalid
-    br#""#suffix; //~ ERROR suffixes on a byte string literal are invalid
-    'a'suffix; //~ ERROR suffixes on a char literal are invalid
-    b'a'suffix; //~ ERROR suffixes on a byte literal are invalid
+    ""suffix; //~ ERROR suffixes on string literals are invalid
+    b""suffix; //~ ERROR suffixes on byte string literals are invalid
+    r#""#suffix; //~ ERROR suffixes on string literals are invalid
+    br#""#suffix; //~ ERROR suffixes on byte string literals are invalid
+    'a'suffix; //~ ERROR suffixes on char literals are invalid
+    b'a'suffix; //~ ERROR suffixes on byte literals are invalid
 
     1234u1024; //~ ERROR invalid width `1024` for integer literal
     1234i1024; //~ ERROR invalid width `1024` for integer literal
diff --git a/src/test/ui/parser/bad-lit-suffixes.stderr b/src/test/ui/parser/bad-lit-suffixes.stderr
index 9b596571481..f74eef32445 100644
--- a/src/test/ui/parser/bad-lit-suffixes.stderr
+++ b/src/test/ui/parser/bad-lit-suffixes.stderr
@@ -1,46 +1,46 @@
-error: suffixes on a string literal are invalid
+error: suffixes on string literals are invalid
   --> $DIR/bad-lit-suffixes.rs:2:5
    |
 LL |     "C"suffix
    |     ^^^^^^^^^ invalid suffix `suffix`
 
-error: suffixes on a string literal are invalid
+error: suffixes on string literals are invalid
   --> $DIR/bad-lit-suffixes.rs:6:5
    |
 LL |     "C"suffix
    |     ^^^^^^^^^ invalid suffix `suffix`
 
-error: suffixes on a string literal are invalid
+error: suffixes on string literals are invalid
   --> $DIR/bad-lit-suffixes.rs:10:5
    |
 LL |     ""suffix;
    |     ^^^^^^^^ invalid suffix `suffix`
 
-error: suffixes on a byte string literal are invalid
+error: suffixes on byte string literals are invalid
   --> $DIR/bad-lit-suffixes.rs:11:5
    |
 LL |     b""suffix;
    |     ^^^^^^^^^ invalid suffix `suffix`
 
-error: suffixes on a string literal are invalid
+error: suffixes on string literals are invalid
   --> $DIR/bad-lit-suffixes.rs:12:5
    |
 LL |     r#""#suffix;
    |     ^^^^^^^^^^^ invalid suffix `suffix`
 
-error: suffixes on a byte string literal are invalid
+error: suffixes on byte string literals are invalid
   --> $DIR/bad-lit-suffixes.rs:13:5
    |
 LL |     br#""#suffix;
    |     ^^^^^^^^^^^^ invalid suffix `suffix`
 
-error: suffixes on a char literal are invalid
+error: suffixes on char literals are invalid
   --> $DIR/bad-lit-suffixes.rs:14:5
    |
 LL |     'a'suffix;
    |     ^^^^^^^^^ invalid suffix `suffix`
 
-error: suffixes on a byte literal are invalid
+error: suffixes on byte literals are invalid
   --> $DIR/bad-lit-suffixes.rs:15:5
    |
 LL |     b'a'suffix;
diff --git a/src/test/ui/parser/bad-pointer-type.rs b/src/test/ui/parser/bad-pointer-type.rs
index 59e5e0c5d31..6a82acb4cd6 100644
--- a/src/test/ui/parser/bad-pointer-type.rs
+++ b/src/test/ui/parser/bad-pointer-type.rs
@@ -1,5 +1,5 @@
 fn foo(_: *()) {
-    //~^ ERROR expected mut or const in raw pointer type
+    //~^ ERROR expected `mut` or `const` keyword in raw pointer type
 }
 
 fn main() {}
diff --git a/src/test/ui/parser/bad-pointer-type.stderr b/src/test/ui/parser/bad-pointer-type.stderr
index e18c220affe..b7225ca887d 100644
--- a/src/test/ui/parser/bad-pointer-type.stderr
+++ b/src/test/ui/parser/bad-pointer-type.stderr
@@ -1,10 +1,15 @@
-error: expected mut or const in raw pointer type
+error: expected `mut` or `const` keyword in raw pointer type
   --> $DIR/bad-pointer-type.rs:1:11
    |
 LL | fn foo(_: *()) {
-   |           ^ expected mut or const in raw pointer type
+   |           ^
    |
-   = help: use `*mut T` or `*const T` as appropriate
+help: add `mut` or `const` here
+   |
+LL | fn foo(_: *const ()) {
+   |            +++++
+LL | fn foo(_: *mut ()) {
+   |            +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/doc-after-struct-field.rs b/src/test/ui/parser/doc-after-struct-field.rs
index 5b6f0803603..03faa6733e2 100644
--- a/src/test/ui/parser/doc-after-struct-field.rs
+++ b/src/test/ui/parser/doc-after-struct-field.rs
@@ -1,13 +1,13 @@
 struct X {
     a: u8 /** document a */,
     //~^ ERROR found a documentation comment that doesn't document anything
-    //~| HELP maybe a comment was intended
+    //~| HELP if a comment was intended use `//`
 }
 
 struct Y {
     a: u8 /// document a
     //~^ ERROR found a documentation comment that doesn't document anything
-    //~| HELP maybe a comment was intended
+    //~| HELP if a comment was intended use `//`
 }
 
 fn main() {
diff --git a/src/test/ui/parser/doc-after-struct-field.stderr b/src/test/ui/parser/doc-after-struct-field.stderr
index e3b32a7f035..ae177f1a2d1 100644
--- a/src/test/ui/parser/doc-after-struct-field.stderr
+++ b/src/test/ui/parser/doc-after-struct-field.stderr
@@ -4,7 +4,7 @@ error[E0585]: found a documentation comment that doesn't document anything
 LL |     a: u8 /** document a */,
    |           ^^^^^^^^^^^^^^^^^
    |
-   = help: doc comments must come before what they document, maybe a comment was intended with `//`?
+   = help: doc comments must come before what they document, if a comment was intended use `//`
 
 error[E0585]: found a documentation comment that doesn't document anything
   --> $DIR/doc-after-struct-field.rs:8:11
@@ -12,7 +12,7 @@ error[E0585]: found a documentation comment that doesn't document anything
 LL |     a: u8 /// document a
    |           ^^^^^^^^^^^^^^
    |
-   = help: doc comments must come before what they document, maybe a comment was intended with `//`?
+   = help: doc comments must come before what they document, if a comment was intended use `//`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/parser/doc-before-extern-rbrace.stderr b/src/test/ui/parser/doc-before-extern-rbrace.stderr
index 0edceb268a7..8fa12ec261e 100644
--- a/src/test/ui/parser/doc-before-extern-rbrace.stderr
+++ b/src/test/ui/parser/doc-before-extern-rbrace.stderr
@@ -4,7 +4,7 @@ error[E0584]: found a documentation comment that doesn't document anything
 LL |     /// hi
    |     ^^^^^^ this doc comment doesn't document anything
    |
-   = help: doc comments must come before what they document, maybe a comment was intended with `//`?
+   = help: doc comments must come before what they document, if a comment was intended use `//`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/doc-before-fn-rbrace.rs b/src/test/ui/parser/doc-before-fn-rbrace.rs
index eb355136f1e..c8502164854 100644
--- a/src/test/ui/parser/doc-before-fn-rbrace.rs
+++ b/src/test/ui/parser/doc-before-fn-rbrace.rs
@@ -1,5 +1,5 @@
 fn main() {
     /// document
     //~^ ERROR found a documentation comment that doesn't document anything
-    //~| HELP maybe a comment was intended
+    //~| HELP if a comment was intended use `//`
 }
diff --git a/src/test/ui/parser/doc-before-fn-rbrace.stderr b/src/test/ui/parser/doc-before-fn-rbrace.stderr
index 56241de7092..6ea68e42b4c 100644
--- a/src/test/ui/parser/doc-before-fn-rbrace.stderr
+++ b/src/test/ui/parser/doc-before-fn-rbrace.stderr
@@ -4,7 +4,7 @@ error[E0585]: found a documentation comment that doesn't document anything
 LL |     /// document
    |     ^^^^^^^^^^^^
    |
-   = help: doc comments must come before what they document, maybe a comment was intended with `//`?
+   = help: doc comments must come before what they document, if a comment was intended use `//`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/doc-before-rbrace.rs b/src/test/ui/parser/doc-before-rbrace.rs
index 8ff946344ae..570306f2cdf 100644
--- a/src/test/ui/parser/doc-before-rbrace.rs
+++ b/src/test/ui/parser/doc-before-rbrace.rs
@@ -1,5 +1,5 @@
 fn main() {
     println!("Hi"); /// hi
     //~^ ERROR found a documentation comment that doesn't document anything
-    //~| HELP maybe a comment was intended
+    //~| HELP if a comment was intended use `//`
 }
diff --git a/src/test/ui/parser/doc-before-rbrace.stderr b/src/test/ui/parser/doc-before-rbrace.stderr
index 55719cf6411..4d4741dfe59 100644
--- a/src/test/ui/parser/doc-before-rbrace.stderr
+++ b/src/test/ui/parser/doc-before-rbrace.stderr
@@ -4,7 +4,7 @@ error[E0585]: found a documentation comment that doesn't document anything
 LL |     println!("Hi"); /// hi
    |                     ^^^^^^
    |
-   = help: doc comments must come before what they document, maybe a comment was intended with `//`?
+   = help: doc comments must come before what they document, if a comment was intended use `//`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/doc-before-semi.rs b/src/test/ui/parser/doc-before-semi.rs
index 405a7e1e2a3..444b5874ea2 100644
--- a/src/test/ui/parser/doc-before-semi.rs
+++ b/src/test/ui/parser/doc-before-semi.rs
@@ -1,6 +1,6 @@
 fn main() {
     /// hi
     //~^ ERROR found a documentation comment that doesn't document anything
-    //~| HELP maybe a comment was intended
+    //~| HELP if a comment was intended use `//`
     ;
 }
diff --git a/src/test/ui/parser/doc-before-semi.stderr b/src/test/ui/parser/doc-before-semi.stderr
index e6bade18d0a..a879e13ffbd 100644
--- a/src/test/ui/parser/doc-before-semi.stderr
+++ b/src/test/ui/parser/doc-before-semi.stderr
@@ -4,7 +4,7 @@ error[E0585]: found a documentation comment that doesn't document anything
 LL |     /// hi
    |     ^^^^^^
    |
-   = help: doc comments must come before what they document, maybe a comment was intended with `//`?
+   = help: doc comments must come before what they document, if a comment was intended use `//`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/doc-before-struct-rbrace-1.rs b/src/test/ui/parser/doc-before-struct-rbrace-1.rs
index 3866a3105c2..0c8d90c3b03 100644
--- a/src/test/ui/parser/doc-before-struct-rbrace-1.rs
+++ b/src/test/ui/parser/doc-before-struct-rbrace-1.rs
@@ -2,7 +2,7 @@ struct X {
     a: u8,
     /// document
     //~^ ERROR found a documentation comment that doesn't document anything
-    //~| HELP maybe a comment was intended
+    //~| HELP if a comment was intended use `//`
 }
 
 fn main() {
diff --git a/src/test/ui/parser/doc-before-struct-rbrace-1.stderr b/src/test/ui/parser/doc-before-struct-rbrace-1.stderr
index 19f90677398..94934f734b3 100644
--- a/src/test/ui/parser/doc-before-struct-rbrace-1.stderr
+++ b/src/test/ui/parser/doc-before-struct-rbrace-1.stderr
@@ -1,10 +1,13 @@
 error[E0585]: found a documentation comment that doesn't document anything
   --> $DIR/doc-before-struct-rbrace-1.rs:3:5
    |
+LL | struct X {
+   |        - while parsing this struct
+LL |     a: u8,
 LL |     /// document
    |     ^^^^^^^^^^^^
    |
-   = help: doc comments must come before what they document, maybe a comment was intended with `//`?
+   = help: doc comments must come before what they document, if a comment was intended use `//`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/doc-before-struct-rbrace-2.rs b/src/test/ui/parser/doc-before-struct-rbrace-2.rs
index dda138f1a88..2b2aadf7984 100644
--- a/src/test/ui/parser/doc-before-struct-rbrace-2.rs
+++ b/src/test/ui/parser/doc-before-struct-rbrace-2.rs
@@ -1,7 +1,7 @@
 struct X {
     a: u8 /// document
     //~^ ERROR found a documentation comment that doesn't document anything
-    //~| HELP maybe a comment was intended
+    //~| HELP if a comment was intended use `//`
 }
 
 fn main() {
diff --git a/src/test/ui/parser/doc-before-struct-rbrace-2.stderr b/src/test/ui/parser/doc-before-struct-rbrace-2.stderr
index b25ccab79f9..6b5c8c1f8b5 100644
--- a/src/test/ui/parser/doc-before-struct-rbrace-2.stderr
+++ b/src/test/ui/parser/doc-before-struct-rbrace-2.stderr
@@ -4,7 +4,7 @@ error[E0585]: found a documentation comment that doesn't document anything
 LL |     a: u8 /// document
    |           ^^^^^^^^^^^^
    |
-   = help: doc comments must come before what they document, maybe a comment was intended with `//`?
+   = help: doc comments must come before what they document, if a comment was intended use `//`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/doc-inside-trait-item.stderr b/src/test/ui/parser/doc-inside-trait-item.stderr
index 246255a0a46..900124adcc3 100644
--- a/src/test/ui/parser/doc-inside-trait-item.stderr
+++ b/src/test/ui/parser/doc-inside-trait-item.stderr
@@ -4,7 +4,7 @@ error[E0584]: found a documentation comment that doesn't document anything
 LL |     /// empty doc
    |     ^^^^^^^^^^^^^ this doc comment doesn't document anything
    |
-   = help: doc comments must come before what they document, maybe a comment was intended with `//`?
+   = help: doc comments must come before what they document, if a comment was intended use `//`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/double-pointer.rs b/src/test/ui/parser/double-pointer.rs
new file mode 100644
index 00000000000..54d34db4a50
--- /dev/null
+++ b/src/test/ui/parser/double-pointer.rs
@@ -0,0 +1,7 @@
+fn main() {
+    let x: i32 = 5;
+    let ptr: *const i32 = &x;
+    let dptr: **const i32 = &ptr;
+    //~^ ERROR expected `mut` or `const` keyword in raw pointer type
+    //~| HELP add `mut` or `const` here
+}
diff --git a/src/test/ui/parser/double-pointer.stderr b/src/test/ui/parser/double-pointer.stderr
new file mode 100644
index 00000000000..28037f93265
--- /dev/null
+++ b/src/test/ui/parser/double-pointer.stderr
@@ -0,0 +1,15 @@
+error: expected `mut` or `const` keyword in raw pointer type
+  --> $DIR/double-pointer.rs:4:15
+   |
+LL |     let dptr: **const i32 = &ptr;
+   |               ^
+   |
+help: add `mut` or `const` here
+   |
+LL |     let dptr: *const *const i32 = &ptr;
+   |                +++++
+LL |     let dptr: *mut *const i32 = &ptr;
+   |                +++
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/empty-impl-semicolon.rs b/src/test/ui/parser/empty-impl-semicolon.rs
index 207ebef642b..2485f5b8552 100644
--- a/src/test/ui/parser/empty-impl-semicolon.rs
+++ b/src/test/ui/parser/empty-impl-semicolon.rs
@@ -1 +1,4 @@
-impl Foo; //~ ERROR expected one of `!`, `(`, `+`, `::`, `<`, `for`, `where`, or `{`, found `;`
+struct Foo;
+impl Foo; //~ ERROR expected `{}`, found `;`
+
+fn main() {}
diff --git a/src/test/ui/parser/empty-impl-semicolon.stderr b/src/test/ui/parser/empty-impl-semicolon.stderr
index 398eb5c898c..6ed309eba93 100644
--- a/src/test/ui/parser/empty-impl-semicolon.stderr
+++ b/src/test/ui/parser/empty-impl-semicolon.stderr
@@ -1,8 +1,10 @@
-error: expected one of `!`, `(`, `+`, `::`, `<`, `for`, `where`, or `{`, found `;`
-  --> $DIR/empty-impl-semicolon.rs:1:9
+error: expected `{}`, found `;`
+  --> $DIR/empty-impl-semicolon.rs:2:9
    |
 LL | impl Foo;
-   |         ^ expected one of 8 possible tokens
+   |         ^
+   |
+   = help: try using `{}` instead
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/fn-field-parse-error-ice.stderr b/src/test/ui/parser/fn-field-parse-error-ice.stderr
index d582f61cc97..e9583f55b8e 100644
--- a/src/test/ui/parser/fn-field-parse-error-ice.stderr
+++ b/src/test/ui/parser/fn-field-parse-error-ice.stderr
@@ -7,6 +7,8 @@ LL |     inner : dyn fn ()
 error: functions are not allowed in struct definitions
   --> $DIR/fn-field-parse-error-ice.rs:4:17
    |
+LL | struct Baz {
+   |        --- while parsing this struct
 LL |     inner : dyn fn ()
    |                 ^^
    |
diff --git a/src/test/ui/parser/inner-attr-after-doc-comment.stderr b/src/test/ui/parser/inner-attr-after-doc-comment.stderr
index 2cfafac7794..3ec3ad8e977 100644
--- a/src/test/ui/parser/inner-attr-after-doc-comment.stderr
+++ b/src/test/ui/parser/inner-attr-after-doc-comment.stderr
@@ -7,7 +7,7 @@ LL | |  */
    | |___- previous doc comment
 LL |
 LL |   #![recursion_limit="100"]
-   |   ^^^^^^^^^^^^^^^^^^^^^^^^^ not permitted following an outer attribute
+   |   ^^^^^^^^^^^^^^^^^^^^^^^^^ not permitted following an outer doc comment
 LL |
 LL |   fn main() {}
    |   ------------ the inner attribute doesn't annotate this function
diff --git a/src/test/ui/parser/issues/issue-101540.rs b/src/test/ui/parser/issues/issue-101540.rs
new file mode 100644
index 00000000000..328ec6f906b
--- /dev/null
+++ b/src/test/ui/parser/issues/issue-101540.rs
@@ -0,0 +1,7 @@
+struct S1 {
+    struct S2 {
+    //~^ ERROR structs are not allowed in struct definitions
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/issues/issue-101540.stderr b/src/test/ui/parser/issues/issue-101540.stderr
new file mode 100644
index 00000000000..8af88705002
--- /dev/null
+++ b/src/test/ui/parser/issues/issue-101540.stderr
@@ -0,0 +1,12 @@
+error: structs are not allowed in struct definitions
+  --> $DIR/issue-101540.rs:2:5
+   |
+LL | struct S1 {
+   |        -- while parsing this struct
+LL |     struct S2 {
+   |     ^^^^^^^^^
+   |
+   = help: consider creating a new `struct` definition instead of nesting
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/issues/issue-34222-1.stderr b/src/test/ui/parser/issues/issue-34222-1.stderr
index 0799656b06b..b451484ba22 100644
--- a/src/test/ui/parser/issues/issue-34222-1.stderr
+++ b/src/test/ui/parser/issues/issue-34222-1.stderr
@@ -4,7 +4,7 @@ error[E0585]: found a documentation comment that doesn't document anything
 LL |     /// comment
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: doc comments must come before what they document, maybe a comment was intended with `//`?
+   = help: doc comments must come before what they document, if a comment was intended use `//`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/issues/issue-48636.stderr b/src/test/ui/parser/issues/issue-48636.stderr
index 462723d1d93..6177870d1ce 100644
--- a/src/test/ui/parser/issues/issue-48636.stderr
+++ b/src/test/ui/parser/issues/issue-48636.stderr
@@ -1,12 +1,14 @@
 error[E0585]: found a documentation comment that doesn't document anything
   --> $DIR/issue-48636.rs:7:5
    |
+LL | struct S {
+   |        - while parsing this struct
 LL |     x: u8
    |          - help: missing comma here: `,`
 LL |     /// The ID of the parent core
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: doc comments must come before what they document, maybe a comment was intended with `//`?
+   = help: doc comments must come before what they document, if a comment was intended use `//`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/issues/issue-68000-unicode-ident-after-missing-comma.stderr b/src/test/ui/parser/issues/issue-68000-unicode-ident-after-missing-comma.stderr
index ef365a61643..adabb68593c 100644
--- a/src/test/ui/parser/issues/issue-68000-unicode-ident-after-missing-comma.stderr
+++ b/src/test/ui/parser/issues/issue-68000-unicode-ident-after-missing-comma.stderr
@@ -7,6 +7,8 @@ LL |     pub bar: Vec<i32>ö
 error: expected `:`, found `}`
   --> $DIR/issue-68000-unicode-ident-after-missing-comma.rs:4:1
    |
+LL | pub struct Foo {
+   |            --- while parsing this struct
 LL |     pub bar: Vec<i32>ö
    |                       - expected `:`
 LL |
diff --git a/src/test/ui/parser/item-needs-block.rs b/src/test/ui/parser/item-needs-block.rs
new file mode 100644
index 00000000000..4edac588eee
--- /dev/null
+++ b/src/test/ui/parser/item-needs-block.rs
@@ -0,0 +1,10 @@
+trait Trait;
+//~^ ERROR expected `{}`, found `;`
+
+impl Trait for ();
+//~^ ERROR expected `{}`, found `;`
+
+enum Enum;
+//~^ ERROR expected `{}`, found `;`
+
+fn main() {}
diff --git a/src/test/ui/parser/item-needs-block.stderr b/src/test/ui/parser/item-needs-block.stderr
new file mode 100644
index 00000000000..3cabd0c73a3
--- /dev/null
+++ b/src/test/ui/parser/item-needs-block.stderr
@@ -0,0 +1,26 @@
+error: expected `{}`, found `;`
+  --> $DIR/item-needs-block.rs:1:12
+   |
+LL | trait Trait;
+   |            ^
+   |
+   = help: try using `{}` instead
+
+error: expected `{}`, found `;`
+  --> $DIR/item-needs-block.rs:4:18
+   |
+LL | impl Trait for ();
+   |                  ^
+   |
+   = help: try using `{}` instead
+
+error: expected `{}`, found `;`
+  --> $DIR/item-needs-block.rs:7:10
+   |
+LL | enum Enum;
+   |          ^
+   |
+   = help: try using `{}` instead
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/parser/macro/issue-37113.stderr b/src/test/ui/parser/macro/issue-37113.stderr
index 0912858ddc4..b1f8674fbdf 100644
--- a/src/test/ui/parser/macro/issue-37113.stderr
+++ b/src/test/ui/parser/macro/issue-37113.stderr
@@ -1,6 +1,8 @@
 error: expected identifier, found `String`
   --> $DIR/issue-37113.rs:4:16
    |
+LL |         enum SomeEnum {
+   |              -------- while parsing this enum
 LL |             $( $t, )*
    |                ^^ expected identifier
 ...
diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-struct.stderr b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-struct.stderr
index a47d5506ef0..ad1e90e43ec 100644
--- a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-struct.stderr
+++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-struct.stderr
@@ -10,6 +10,9 @@ LL | fn main() {}
 error: expected identifier, found keyword `trait`
   --> $DIR/missing-close-brace-in-struct.rs:4:1
    |
+LL | pub(crate) struct Bar<T> {
+   |                   --- while parsing this struct
+...
 LL | trait T {
    | ^^^^^ expected identifier, found keyword
 
diff --git a/src/test/ui/parser/missing-closing-angle-bracket-struct-field-ty.stderr b/src/test/ui/parser/missing-closing-angle-bracket-struct-field-ty.stderr
index 46ca1f06be6..6d8b0c3fccd 100644
--- a/src/test/ui/parser/missing-closing-angle-bracket-struct-field-ty.stderr
+++ b/src/test/ui/parser/missing-closing-angle-bracket-struct-field-ty.stderr
@@ -1,6 +1,9 @@
 error: expected one of `>`, a const expression, lifetime, or type, found `}`
   --> $DIR/missing-closing-angle-bracket-struct-field-ty.rs:9:1
    |
+LL | pub struct Foo {
+   |            --- while parsing this struct
+...
 LL |     c: Arc<Mutex<usize>>,
    |                          - expected one of `>`, a const expression, lifetime, or type
 LL | }
diff --git a/src/test/ui/parser/recover-enum2.stderr b/src/test/ui/parser/recover-enum2.stderr
index ee29f06638f..7634bca921c 100644
--- a/src/test/ui/parser/recover-enum2.stderr
+++ b/src/test/ui/parser/recover-enum2.stderr
@@ -1,6 +1,8 @@
 error: expected type, found `{`
   --> $DIR/recover-enum2.rs:6:18
    |
+LL |         Var3 {
+   |         ---- while parsing this struct
 LL |             abc: {},
    |                  ^ expected type
 
diff --git a/src/test/ui/parser/recover-field-semi.stderr b/src/test/ui/parser/recover-field-semi.stderr
index 657366db9b4..3cf4847488c 100644
--- a/src/test/ui/parser/recover-field-semi.stderr
+++ b/src/test/ui/parser/recover-field-semi.stderr
@@ -1,12 +1,16 @@
 error: struct fields are separated by `,`
   --> $DIR/recover-field-semi.rs:2:13
    |
+LL | struct Foo {
+   |        --- while parsing this struct
 LL |     foo: i32;
    |             ^ help: replace `;` with `,`
 
 error: union fields are separated by `,`
   --> $DIR/recover-field-semi.rs:7:13
    |
+LL | union Bar {
+   |       --- while parsing this union
 LL |     foo: i32;
    |             ^ help: replace `;` with `,`
 
@@ -14,7 +18,9 @@ error: struct fields are separated by `,`
   --> $DIR/recover-field-semi.rs:12:19
    |
 LL |     Qux { foo: i32; }
-   |                   ^ help: replace `;` with `,`
+   |     ---           ^ help: replace `;` with `,`
+   |     |
+   |     while parsing this struct
 
 error: unions cannot have zero fields
   --> $DIR/recover-field-semi.rs:6:1
diff --git a/src/test/ui/parser/recover-struct.stderr b/src/test/ui/parser/recover-struct.stderr
index 1b72184b0c8..9f6fb06caa3 100644
--- a/src/test/ui/parser/recover-struct.stderr
+++ b/src/test/ui/parser/recover-struct.stderr
@@ -1,6 +1,8 @@
 error: expected `:`, found `Bad`
   --> $DIR/recover-struct.rs:4:9
    |
+LL |     struct Test {
+   |            ---- while parsing this struct
 LL |         Very
    |             - expected `:`
 LL |         Bad
diff --git a/src/test/ui/parser/recovered-struct-variant.stderr b/src/test/ui/parser/recovered-struct-variant.stderr
index 51aaf8bb3cf..78c67866fb0 100644
--- a/src/test/ui/parser/recovered-struct-variant.stderr
+++ b/src/test/ui/parser/recovered-struct-variant.stderr
@@ -2,7 +2,9 @@ error: expected `:`, found `,`
   --> $DIR/recovered-struct-variant.rs:2:10
    |
 LL |     A { a, b: usize }
-   |          ^ expected `:`
+   |     -    ^ expected `:`
+   |     |
+   |     while parsing this struct
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/removed-syntax-enum-newtype.stderr b/src/test/ui/parser/removed-syntax-enum-newtype.stderr
index 2daa6249b4c..8f7ca356798 100644
--- a/src/test/ui/parser/removed-syntax-enum-newtype.stderr
+++ b/src/test/ui/parser/removed-syntax-enum-newtype.stderr
@@ -2,7 +2,9 @@ error: expected one of `<`, `where`, or `{`, found `=`
   --> $DIR/removed-syntax-enum-newtype.rs:1:8
    |
 LL | enum e = isize;
-   |        ^ expected one of `<`, `where`, or `{`
+   |      - ^ expected one of `<`, `where`, or `{`
+   |      |
+   |      while parsing this enum
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/removed-syntax-field-let.stderr b/src/test/ui/parser/removed-syntax-field-let.stderr
index 10be2e045b2..ab3d2056581 100644
--- a/src/test/ui/parser/removed-syntax-field-let.stderr
+++ b/src/test/ui/parser/removed-syntax-field-let.stderr
@@ -1,6 +1,8 @@
 error: expected identifier, found keyword `let`
   --> $DIR/removed-syntax-field-let.rs:2:5
    |
+LL | struct S {
+   |        - while parsing this struct
 LL |     let foo: (),
    |     ^^^ expected identifier, found keyword
 
diff --git a/src/test/ui/parser/removed-syntax-field-semicolon.stderr b/src/test/ui/parser/removed-syntax-field-semicolon.stderr
index e4f75f67206..532d4fb2b61 100644
--- a/src/test/ui/parser/removed-syntax-field-semicolon.stderr
+++ b/src/test/ui/parser/removed-syntax-field-semicolon.stderr
@@ -1,6 +1,8 @@
 error: struct fields are separated by `,`
   --> $DIR/removed-syntax-field-semicolon.rs:2:12
    |
+LL | struct S {
+   |        - while parsing this struct
 LL |     bar: ();
    |            ^ help: replace `;` with `,`
 
diff --git a/src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.stderr b/src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.stderr
index fef0f3c0e06..f40642f300c 100644
--- a/src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.stderr
+++ b/src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.stderr
@@ -1,6 +1,8 @@
 error: expected type, found `0`
   --> $DIR/issue-66270-pat-struct-parser-recovery.rs:4:22
    |
+LL | struct Bug {
+   |        --- while parsing this struct
 LL |     incorrect_field: 0,
    |                      ^ expected type
 
diff --git a/src/test/ui/privacy/associated-item-privacy-inherent.rs b/src/test/ui/privacy/associated-item-privacy-inherent.rs
index c3ae920238f..7b7c734a99a 100644
--- a/src/test/ui/privacy/associated-item-privacy-inherent.rs
+++ b/src/test/ui/privacy/associated-item-privacy-inherent.rs
@@ -11,11 +11,11 @@ mod priv_nominal {
 
     pub macro mac() {
         let value = Pub::method;
-        //~^ ERROR type `for<'r> fn(&'r priv_nominal::Pub) {priv_nominal::Pub::method}` is private
+        //~^ ERROR type `for<'a> fn(&'a priv_nominal::Pub) {priv_nominal::Pub::method}` is private
         value;
-        //~^ ERROR type `for<'r> fn(&'r priv_nominal::Pub) {priv_nominal::Pub::method}` is private
+        //~^ ERROR type `for<'a> fn(&'a priv_nominal::Pub) {priv_nominal::Pub::method}` is private
         Pub.method();
-        //~^ ERROR type `for<'r> fn(&'r priv_nominal::Pub) {priv_nominal::Pub::method}` is private
+        //~^ ERROR type `for<'a> fn(&'a priv_nominal::Pub) {priv_nominal::Pub::method}` is private
         Pub::CONST;
         //~^ ERROR associated constant `CONST` is private
         // let _: Pub::AssocTy;
diff --git a/src/test/ui/privacy/associated-item-privacy-inherent.stderr b/src/test/ui/privacy/associated-item-privacy-inherent.stderr
index 4478e5c2aba..f4d4ee45920 100644
--- a/src/test/ui/privacy/associated-item-privacy-inherent.stderr
+++ b/src/test/ui/privacy/associated-item-privacy-inherent.stderr
@@ -1,4 +1,4 @@
-error: type `for<'r> fn(&'r priv_nominal::Pub) {priv_nominal::Pub::method}` is private
+error: type `for<'a> fn(&'a priv_nominal::Pub) {priv_nominal::Pub::method}` is private
   --> $DIR/associated-item-privacy-inherent.rs:13:21
    |
 LL |         let value = Pub::method;
@@ -9,7 +9,7 @@ LL |     priv_nominal::mac!();
    |
    = note: this error originates in the macro `priv_nominal::mac` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: type `for<'r> fn(&'r priv_nominal::Pub) {priv_nominal::Pub::method}` is private
+error: type `for<'a> fn(&'a priv_nominal::Pub) {priv_nominal::Pub::method}` is private
   --> $DIR/associated-item-privacy-inherent.rs:15:9
    |
 LL |         value;
@@ -20,7 +20,7 @@ LL |     priv_nominal::mac!();
    |
    = note: this error originates in the macro `priv_nominal::mac` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: type `for<'r> fn(&'r priv_nominal::Pub) {priv_nominal::Pub::method}` is private
+error: type `for<'a> fn(&'a priv_nominal::Pub) {priv_nominal::Pub::method}` is private
   --> $DIR/associated-item-privacy-inherent.rs:17:13
    |
 LL |         Pub.method();
diff --git a/src/test/ui/privacy/associated-item-privacy-trait.rs b/src/test/ui/privacy/associated-item-privacy-trait.rs
index c07aeed99c7..ad9a5e15c4e 100644
--- a/src/test/ui/privacy/associated-item-privacy-trait.rs
+++ b/src/test/ui/privacy/associated-item-privacy-trait.rs
@@ -13,11 +13,11 @@ mod priv_trait {
 
     pub macro mac() {
         let value = <Pub as PrivTr>::method;
-        //~^ ERROR type `for<'r> fn(&'r priv_trait::Pub) {<priv_trait::Pub as PrivTr>::method}` is private
+        //~^ ERROR type `for<'a> fn(&'a priv_trait::Pub) {<priv_trait::Pub as PrivTr>::method}` is private
         value;
-        //~^ ERROR type `for<'r> fn(&'r priv_trait::Pub) {<priv_trait::Pub as PrivTr>::method}` is private
+        //~^ ERROR type `for<'a> fn(&'a priv_trait::Pub) {<priv_trait::Pub as PrivTr>::method}` is private
         Pub.method();
-        //~^ ERROR type `for<'r> fn(&'r Self) {<Self as PrivTr>::method}` is private
+        //~^ ERROR type `for<'a> fn(&'a Self) {<Self as PrivTr>::method}` is private
         <Pub as PrivTr>::CONST;
         //~^ ERROR associated constant `<Pub as PrivTr>::CONST` is private
         let _: <Pub as PrivTr>::AssocTy;
diff --git a/src/test/ui/privacy/associated-item-privacy-trait.stderr b/src/test/ui/privacy/associated-item-privacy-trait.stderr
index 6095f5f42b8..c4be1a9d9a2 100644
--- a/src/test/ui/privacy/associated-item-privacy-trait.stderr
+++ b/src/test/ui/privacy/associated-item-privacy-trait.stderr
@@ -1,4 +1,4 @@
-error: type `for<'r> fn(&'r priv_trait::Pub) {<priv_trait::Pub as PrivTr>::method}` is private
+error: type `for<'a> fn(&'a priv_trait::Pub) {<priv_trait::Pub as PrivTr>::method}` is private
   --> $DIR/associated-item-privacy-trait.rs:15:21
    |
 LL |         let value = <Pub as PrivTr>::method;
@@ -9,7 +9,7 @@ LL |     priv_trait::mac!();
    |
    = note: this error originates in the macro `priv_trait::mac` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: type `for<'r> fn(&'r priv_trait::Pub) {<priv_trait::Pub as PrivTr>::method}` is private
+error: type `for<'a> fn(&'a priv_trait::Pub) {<priv_trait::Pub as PrivTr>::method}` is private
   --> $DIR/associated-item-privacy-trait.rs:17:9
    |
 LL |         value;
@@ -20,7 +20,7 @@ LL |     priv_trait::mac!();
    |
    = note: this error originates in the macro `priv_trait::mac` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: type `for<'r> fn(&'r Self) {<Self as PrivTr>::method}` is private
+error: type `for<'a> fn(&'a Self) {<Self as PrivTr>::method}` is private
   --> $DIR/associated-item-privacy-trait.rs:19:13
    |
 LL |         Pub.method();
diff --git a/src/test/ui/privacy/private-inferred-type-3.rs b/src/test/ui/privacy/private-inferred-type-3.rs
index 00f0a715a83..0337aedd008 100644
--- a/src/test/ui/privacy/private-inferred-type-3.rs
+++ b/src/test/ui/privacy/private-inferred-type-3.rs
@@ -6,7 +6,7 @@
 // error-pattern:type `fn() {<u8 as ext::PrivTrait>::method}` is private
 // error-pattern:type `fn(u8) -> ext::PrivTupleStruct {ext::PrivTupleStruct}` is private
 // error-pattern:type `fn(u8) -> PubTupleStruct {PubTupleStruct}` is private
-// error-pattern:type `for<'r> fn(&'r Pub<u8>) {Pub::<u8>::priv_method}` is private
+// error-pattern:type `for<'a> fn(&'a Pub<u8>) {Pub::<u8>::priv_method}` is private
 
 #![feature(decl_macro)]
 
diff --git a/src/test/ui/privacy/private-inferred-type-3.stderr b/src/test/ui/privacy/private-inferred-type-3.stderr
index f9dd1c3d035..00b61512de6 100644
--- a/src/test/ui/privacy/private-inferred-type-3.stderr
+++ b/src/test/ui/privacy/private-inferred-type-3.stderr
@@ -46,7 +46,7 @@ LL |     ext::m!();
    |
    = note: this error originates in the macro `ext::m` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: type `for<'r> fn(&'r Pub<u8>) {Pub::<u8>::priv_method}` is private
+error: type `for<'a> fn(&'a Pub<u8>) {Pub::<u8>::priv_method}` is private
   --> $DIR/private-inferred-type-3.rs:16:5
    |
 LL |     ext::m!();
diff --git a/src/test/ui/privacy/private-inferred-type.rs b/src/test/ui/privacy/private-inferred-type.rs
index b083a3970d6..e8743dd968f 100644
--- a/src/test/ui/privacy/private-inferred-type.rs
+++ b/src/test/ui/privacy/private-inferred-type.rs
@@ -47,7 +47,7 @@ mod m {
         PubTupleStruct;
         //~^ ERROR type `fn(u8) -> PubTupleStruct {PubTupleStruct}` is private
         Pub(0u8).priv_method();
-        //~^ ERROR type `for<'r> fn(&'r Pub<u8>) {Pub::<u8>::priv_method}` is private
+        //~^ ERROR type `for<'a> fn(&'a Pub<u8>) {Pub::<u8>::priv_method}` is private
     }
 
     trait Trait {}
diff --git a/src/test/ui/privacy/private-inferred-type.stderr b/src/test/ui/privacy/private-inferred-type.stderr
index aecd8b58c83..fc3f9ab62bf 100644
--- a/src/test/ui/privacy/private-inferred-type.stderr
+++ b/src/test/ui/privacy/private-inferred-type.stderr
@@ -161,7 +161,7 @@ LL |     m::m!();
    |
    = note: this error originates in the macro `m::m` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: type `for<'r> fn(&'r Pub<u8>) {Pub::<u8>::priv_method}` is private
+error: type `for<'a> fn(&'a Pub<u8>) {Pub::<u8>::priv_method}` is private
   --> $DIR/private-inferred-type.rs:49:18
    |
 LL |         Pub(0u8).priv_method();
diff --git a/src/test/ui/proc-macro/derive-bad.stderr b/src/test/ui/proc-macro/derive-bad.stderr
index ae48141fb31..241f99b28c2 100644
--- a/src/test/ui/proc-macro/derive-bad.stderr
+++ b/src/test/ui/proc-macro/derive-bad.stderr
@@ -2,7 +2,10 @@ error: expected `:`, found `}`
   --> $DIR/derive-bad.rs:6:10
    |
 LL | #[derive(A)]
-   |          ^ expected `:`
+   |          ^
+   |          |
+   |          expected `:`
+   |          while parsing this struct
    |
    = note: this error originates in the derive macro `A` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/src/test/ui/process/process-panic-after-fork.rs b/src/test/ui/process/process-panic-after-fork.rs
index 1ccf6bb051c..08b30b600e7 100644
--- a/src/test/ui/process/process-panic-after-fork.rs
+++ b/src/test/ui/process/process-panic-after-fork.rs
@@ -7,7 +7,6 @@
 // ignore-sgx no processes
 // ignore-android: FIXME(#85261)
 
-#![feature(bench_black_box)]
 #![feature(rustc_private)]
 #![feature(never_type)]
 #![feature(panic_always_abort)]
diff --git a/src/test/ui/pub/pub-restricted-error.stderr b/src/test/ui/pub/pub-restricted-error.stderr
index 95bf498c7f7..b47328f34e6 100644
--- a/src/test/ui/pub/pub-restricted-error.stderr
+++ b/src/test/ui/pub/pub-restricted-error.stderr
@@ -1,6 +1,8 @@
 error: expected identifier, found `(`
   --> $DIR/pub-restricted-error.rs:4:16
    |
+LL | struct Foo {
+   |        --- while parsing this struct
 LL |     pub(crate) () foo: usize,
    |                ^ expected identifier
 
diff --git a/src/test/ui/regions/issue-101280.rs b/src/test/ui/regions/issue-101280.rs
new file mode 100644
index 00000000000..29f158366f0
--- /dev/null
+++ b/src/test/ui/regions/issue-101280.rs
@@ -0,0 +1,10 @@
+use std::cell::Cell;
+
+type Ty = for<'r> fn(Cell<(&'r i32, &'r i32)>);
+
+fn f<'r>(f: fn(Cell<(&'r i32, &i32)>)) -> Ty {
+    f
+    //~^ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/regions/issue-101280.stderr b/src/test/ui/regions/issue-101280.stderr
new file mode 100644
index 00000000000..320d008aeff
--- /dev/null
+++ b/src/test/ui/regions/issue-101280.stderr
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-101280.rs:6:5
+   |
+LL | fn f<'r>(f: fn(Cell<(&'r i32, &i32)>)) -> Ty {
+   |                                           -- expected `for<'r> fn(Cell<(&'r i32, &'r i32)>)` because of return type
+LL |     f
+   |     ^ one type is more general than the other
+   |
+   = note: expected fn pointer `for<'r> fn(Cell<(&'r i32, &'r i32)>)`
+              found fn pointer `for<'a> fn(Cell<(&'r i32, &'a i32)>)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/regions/issue-102374.rs b/src/test/ui/regions/issue-102374.rs
new file mode 100644
index 00000000000..e0a1164211a
--- /dev/null
+++ b/src/test/ui/regions/issue-102374.rs
@@ -0,0 +1,20 @@
+use std::cell::Cell;
+
+#[rustfmt::skip]
+fn f(
+    f: for<'a, 'b, 'c, 'd, 'e, 'f, 'g,
+           'h, 'i, 'j, 'k, 'l, 'm, 'n,
+           'o, 'p, 'q, 'r, 's, 't, 'u,
+           'v, 'w, 'x, 'y, 'z, 'z0>
+        fn(Cell<(&   i32, &'a i32, &'b i32, &'c i32, &'d i32,
+                 &'e i32, &'f i32, &'g i32, &'h i32, &'i i32,
+                 &'j i32, &'k i32, &'l i32, &'m i32, &'n i32,
+                 &'o i32, &'p i32, &'q i32, &'r i32, &'s i32,
+                 &'t i32, &'u i32, &'v i32, &'w i32, &'x i32,
+                 &'y i32, &'z i32, &'z0 i32)>),
+) -> i32 {
+    f
+    //~^ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/regions/issue-102374.stderr b/src/test/ui/regions/issue-102374.stderr
new file mode 100644
index 00000000000..31b855c36be
--- /dev/null
+++ b/src/test/ui/regions/issue-102374.stderr
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-102374.rs:16:5
+   |
+LL | ) -> i32 {
+   |      --- expected `i32` because of return type
+LL |     f
+   |     ^ expected `i32`, found fn pointer
+   |
+   = note:    expected type `i32`
+           found fn pointer `for<'z1, 'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'l, 'm, 'n, 'o, 'p, 'q, 'r, 's, 't, 'u, 'v, 'w, 'x, 'y, 'z, 'z0> fn(Cell<(&'z1 i32, &'a i32, &'b i32, &'c i32, &'d i32, &'e i32, &'f i32, &'g i32, &'h i32, &'i i32, &'j i32, &'k i32, &'l i32, &'m i32, &'n i32, &'o i32, &'p i32, &'q i32, &'r i32, &'s i32, &'t i32, &'u i32, &'v i32, &'w i32, &'x i32, &'y i32, &'z i32, &'z0 i32)>)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr
index 48f2e1a2fa2..3b62c7b61c1 100644
--- a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr
+++ b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr
@@ -4,8 +4,8 @@ error[E0308]: mismatched types
 LL |     let _: fn(&mut &isize, &mut &isize) = a;
    |                                           ^ one type is more general than the other
    |
-   = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
-                 found fn item `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}`
+   = note: expected fn pointer `for<'a, 'b, 'c, 'd> fn(&'a mut &'b isize, &'c mut &'d isize)`
+                 found fn item `for<'a, 'b> fn(&'a mut &isize, &'b mut &isize) {a::<'_, '_>}`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr
index 36f40cd9a0f..8a18a234b5c 100644
--- a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr
+++ b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr
@@ -4,8 +4,8 @@ error[E0308]: mismatched types
 LL |     let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
    |                                                        ^ one type is more general than the other
    |
-   = note: expected fn pointer `for<'r, 's, 't0, 't1, 't2, 't3> fn(&'r mut &'s isize, &'t0 mut &'t1 isize, &'t2 mut &'t3 isize)`
-                 found fn item `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize) {a::<'_, '_, '_>}`
+   = note: expected fn pointer `for<'a, 'b, 'c, 'd, 'e, 'f> fn(&'a mut &'b isize, &'c mut &'d isize, &'e mut &'f isize)`
+                 found fn item `for<'a, 'b, 'c> fn(&'a mut &isize, &'b mut &isize, &'c mut &isize) {a::<'_, '_, '_>}`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-fn-subtyping-return-static-fail.stderr b/src/test/ui/regions/regions-fn-subtyping-return-static-fail.stderr
index d87d0d2f6f9..8d82ff958ff 100644
--- a/src/test/ui/regions/regions-fn-subtyping-return-static-fail.stderr
+++ b/src/test/ui/regions/regions-fn-subtyping-return-static-fail.stderr
@@ -7,7 +7,7 @@ LL |     want_G(baz);
    |     arguments to this function are incorrect
    |
    = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'static S`
-                 found fn item `for<'r> fn(&'r S) -> &'r S {baz}`
+                 found fn item `for<'a> fn(&'a S) -> &'a S {baz}`
 note: function defined here
   --> $DIR/regions-fn-subtyping-return-static-fail.rs:20:4
    |
diff --git a/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr b/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr
index a0daf58c6b5..17a9019436a 100644
--- a/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr
+++ b/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr
@@ -4,8 +4,8 @@ error[E0308]: mismatched types
 LL |     let _: fn(&mut &isize, &mut &isize) = a;
    |                                           ^ one type is more general than the other
    |
-   = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
-                 found fn item `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}`
+   = note: expected fn pointer `for<'a, 'b, 'c, 'd> fn(&'a mut &'b isize, &'c mut &'d isize)`
+                 found fn item `for<'a, 'b> fn(&'a mut &isize, &'b mut &isize) {a::<'_, '_>}`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/resolve/name-collision-in-trait-fn-sig.rs b/src/test/ui/resolve/name-collision-in-trait-fn-sig.rs
new file mode 100644
index 00000000000..fba4ffa1c6e
--- /dev/null
+++ b/src/test/ui/resolve/name-collision-in-trait-fn-sig.rs
@@ -0,0 +1,11 @@
+// check-pass
+// This is currently stable behavior, which was almost accidentally made an
+// error in #102161 since there is no test exercising it. I am not sure if
+// this _should_ be the desired behavior, but at least we should know if it
+// changes.
+
+fn main() {}
+
+trait Foo {
+    fn fn_with_type_named_same_as_local_in_param(b: i32, b: i32);
+}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/specializing-constness-2.rs b/src/test/ui/rfc-2632-const-trait-impl/specializing-constness-2.rs
new file mode 100644
index 00000000000..633543700d2
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/specializing-constness-2.rs
@@ -0,0 +1,31 @@
+#![feature(const_trait_impl, min_specialization, rustc_attrs)]
+
+#[rustc_specialization_trait]
+#[const_trait]
+pub trait Sup {}
+
+impl const Sup for () {}
+
+#[const_trait]
+pub trait A {
+    fn a() -> u32;
+}
+
+impl<T: Default> A for T {
+    default fn a() -> u32 {
+        2
+    }
+}
+
+impl<T: Default + ~const Sup> const A for T {
+    fn a() -> u32 {
+        3
+    }
+}
+
+const fn generic<T: Default>() {
+    <T as A>::a();
+    //~^ ERROR: the trait bound `T: ~const Sup` is not satisfied
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/specializing-constness-2.stderr b/src/test/ui/rfc-2632-const-trait-impl/specializing-constness-2.stderr
new file mode 100644
index 00000000000..c554671e18d
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/specializing-constness-2.stderr
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `T: ~const Sup` is not satisfied
+  --> $DIR/specializing-constness-2.rs:27:5
+   |
+LL |     <T as A>::a();
+   |     ^^^^^^^^^^^^^ the trait `~const Sup` is not implemented for `T`
+   |
+note: required for `T` to implement `~const A`
+  --> $DIR/specializing-constness-2.rs:20:37
+   |
+LL | impl<T: Default + ~const Sup> const A for T {
+   |                                     ^     ^
+help: consider further restricting this bound
+   |
+LL | const fn generic<T: Default + ~const Sup>() {
+   |                             ++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/specializing-constness.rs b/src/test/ui/rfc-2632-const-trait-impl/specializing-constness.rs
new file mode 100644
index 00000000000..ff0cd489d47
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/specializing-constness.rs
@@ -0,0 +1,26 @@
+#![feature(const_trait_impl, min_specialization, rustc_attrs)]
+
+#[rustc_specialization_trait]
+#[const_trait]
+pub trait Sup {}
+
+impl const Sup for () {}
+
+#[const_trait]
+pub trait A {
+    fn a() -> u32;
+}
+
+impl<T: ~const Default> const A for T {
+    default fn a() -> u32 {
+        2
+    }
+}
+
+impl<T: Default + Sup> A for T { //~ ERROR: cannot specialize
+    fn a() -> u32 {
+        3
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/specializing-constness.stderr b/src/test/ui/rfc-2632-const-trait-impl/specializing-constness.stderr
new file mode 100644
index 00000000000..3296c109c4e
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/specializing-constness.stderr
@@ -0,0 +1,8 @@
+error: cannot specialize on trait `Default`
+  --> $DIR/specializing-constness.rs:20:9
+   |
+LL | impl<T: Default + Sup> A for T {
+   |         ^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rfc-2632-const-trait-impl/tilde-const-and-const-params.rs b/src/test/ui/rfc-2632-const-trait-impl/tilde-const-and-const-params.rs
new file mode 100644
index 00000000000..b29b633cff6
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/tilde-const-and-const-params.rs
@@ -0,0 +1,34 @@
+// check-pass
+#![feature(const_trait_impl)]
+#![feature(generic_arg_infer)]
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+struct Foo<const N: usize>;
+
+impl<const N: usize> Foo<N> {
+   fn add<A: ~const Add42>(self) -> Foo<{ A::add(N) }> {
+      Foo
+   }
+}
+
+#[const_trait]
+trait Add42 {
+    fn add(a: usize) -> usize;
+}
+
+impl const Add42 for () {
+    fn add(a: usize) -> usize {
+        a + 42
+    }
+}
+
+fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
+    Foo
+}
+
+fn main() {
+   let foo = Foo::<0>;
+   let foo = bar::<(), _>(foo);
+   let _foo = bar::<(), _>(foo);
+}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.rs b/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.rs
index b4302f3e75f..350be4d8250 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.rs
@@ -17,12 +17,6 @@ fn rpit_assoc_bound() -> impl IntoIterator<Item: ~const T> { Some(S) }
 fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T>) {}
 //~^ ERROR `~const` is not allowed
 
-fn generic<P: ~const T>() {}
-//~^ ERROR `~const` is not allowed
-
-fn where_clause<P>() where P: ~const T {}
-//~^ ERROR `~const` is not allowed
-
 struct TildeQuestion<T: ~const ?Sized>(std::marker::PhantomData<T>);
 //~^ ERROR `~const` and `?` are mutually exclusive
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr b/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr
index 033ec21ba84..8d781d063d1 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr
@@ -4,7 +4,7 @@ error: `~const` is not allowed here
 LL | fn rpit() -> impl ~const T { S }
    |                   ^^^^^^^^
    |
-   = note: only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions
+   = note: only allowed on bounds on functions, traits' associated types and functions, const impls and its associated functions
 
 error: `~const` is not allowed here
   --> $DIR/tilde-const-invalid-places.rs:11:17
@@ -12,7 +12,7 @@ error: `~const` is not allowed here
 LL | fn apit(_: impl ~const T) {}
    |                 ^^^^^^^^
    |
-   = note: only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions
+   = note: only allowed on bounds on functions, traits' associated types and functions, const impls and its associated functions
 
 error: `~const` is not allowed here
   --> $DIR/tilde-const-invalid-places.rs:14:50
@@ -20,7 +20,7 @@ error: `~const` is not allowed here
 LL | fn rpit_assoc_bound() -> impl IntoIterator<Item: ~const T> { Some(S) }
    |                                                  ^^^^^^^^
    |
-   = note: only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions
+   = note: only allowed on bounds on functions, traits' associated types and functions, const impls and its associated functions
 
 error: `~const` is not allowed here
   --> $DIR/tilde-const-invalid-places.rs:17:48
@@ -28,29 +28,13 @@ error: `~const` is not allowed here
 LL | fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T>) {}
    |                                                ^^^^^^^^
    |
-   = note: only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions
-
-error: `~const` is not allowed here
-  --> $DIR/tilde-const-invalid-places.rs:20:15
-   |
-LL | fn generic<P: ~const T>() {}
-   |               ^^^^^^^^
-   |
-   = note: only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions
-
-error: `~const` is not allowed here
-  --> $DIR/tilde-const-invalid-places.rs:23:31
-   |
-LL | fn where_clause<P>() where P: ~const T {}
-   |                               ^^^^^^^^
-   |
-   = note: only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions
+   = note: only allowed on bounds on functions, traits' associated types and functions, const impls and its associated functions
 
 error: `~const` and `?` are mutually exclusive
-  --> $DIR/tilde-const-invalid-places.rs:26:25
+  --> $DIR/tilde-const-invalid-places.rs:20:25
    |
 LL | struct TildeQuestion<T: ~const ?Sized>(std::marker::PhantomData<T>);
    |                         ^^^^^^^^^^^^^
 
-error: aborting due to 7 previous errors
+error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-const.rs b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-const.rs
index 7a88ec35c8f..47c38c979c3 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-const.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-const.rs
@@ -1,6 +1,6 @@
 // Like trait-where-clause.rs, but we are calling from a const context.
 // Checking the validity of traits' where clauses happen at a later stage.
-// (`rustc_const_eval` instead of `rustc_typeck`) Therefore one file as a
+// (`rustc_const_eval` instead of `rustc_hir_analysis`) Therefore one file as a
 // test is not enough.
 #![feature(const_trait_impl)]
 
diff --git a/src/test/ui/rfc1623-2.stderr b/src/test/ui/rfc1623-2.stderr
index 495d45e2234..945c6533c79 100644
--- a/src/test/ui/rfc1623-2.stderr
+++ b/src/test/ui/rfc1623-2.stderr
@@ -23,7 +23,7 @@ help: consider making the type lifetime-generic with a new `'a` lifetime
 LL |     &(non_elidable as for<'a> fn(&'a u8, &'a u8) -> &'a u8);
    |                       +++++++     ++      ++         ++
 
-error[E0605]: non-primitive cast: `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8 {non_elidable}` as `for<'r, 's> fn(&'r u8, &'s u8) -> &u8`
+error[E0605]: non-primitive cast: `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8 {non_elidable}` as `for<'a, 'b> fn(&'a u8, &'b u8) -> &u8`
   --> $DIR/rfc1623-2.rs:10:6
    |
 LL |     &(non_elidable as fn(&u8, &u8) -> &u8);
diff --git a/src/test/ui/sanitize/address.rs b/src/test/ui/sanitize/address.rs
index 9a26a351d99..5b2cea87560 100644
--- a/src/test/ui/sanitize/address.rs
+++ b/src/test/ui/sanitize/address.rs
@@ -5,9 +5,7 @@
 //
 // run-fail
 // error-pattern: AddressSanitizer: stack-buffer-overflow
-// error-pattern: 'xs' (line 15) <== Memory access at offset
-
-#![feature(bench_black_box)]
+// error-pattern: 'xs' (line 13) <== Memory access at offset
 
 use std::hint::black_box;
 
diff --git a/src/test/ui/sanitize/hwaddress.rs b/src/test/ui/sanitize/hwaddress.rs
index b988035f75e..f9b37a155aa 100644
--- a/src/test/ui/sanitize/hwaddress.rs
+++ b/src/test/ui/sanitize/hwaddress.rs
@@ -10,8 +10,6 @@
 // run-fail
 // error-pattern: HWAddressSanitizer: tag-mismatch
 
-#![feature(bench_black_box)]
-
 use std::hint::black_box;
 
 fn main() {
diff --git a/src/test/ui/sanitize/leak.rs b/src/test/ui/sanitize/leak.rs
index f63f81352da..cbb44ae8acd 100644
--- a/src/test/ui/sanitize/leak.rs
+++ b/src/test/ui/sanitize/leak.rs
@@ -6,8 +6,6 @@
 // run-fail
 // error-pattern: LeakSanitizer: detected memory leaks
 
-#![feature(bench_black_box)]
-
 use std::hint::black_box;
 use std::mem;
 
diff --git a/src/test/ui/sanitize/memory-eager.rs b/src/test/ui/sanitize/memory-eager.rs
index cc0593ec07d..0018c2f7581 100644
--- a/src/test/ui/sanitize/memory-eager.rs
+++ b/src/test/ui/sanitize/memory-eager.rs
@@ -17,7 +17,6 @@
 
 #![feature(core_intrinsics)]
 #![feature(start)]
-#![feature(bench_black_box)]
 
 use std::hint::black_box;
 use std::mem::MaybeUninit;
diff --git a/src/test/ui/sanitize/memory.rs b/src/test/ui/sanitize/memory.rs
index 14d4de65dd3..1a9ac3a4f3c 100644
--- a/src/test/ui/sanitize/memory.rs
+++ b/src/test/ui/sanitize/memory.rs
@@ -16,7 +16,6 @@
 
 #![feature(core_intrinsics)]
 #![feature(start)]
-#![feature(bench_black_box)]
 #![allow(invalid_value)]
 
 use std::hint::black_box;
diff --git a/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs b/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs
index 1542c7f3118..33e18e35522 100644
--- a/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs
+++ b/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs
@@ -7,7 +7,7 @@
 //
 // no-prefer-dynamic
 // revisions: opt0 opt1
-// compile-flags: -Znew-llvm-pass-manager=yes -Zsanitizer=address -Clto=thin
+// compile-flags: -Zsanitizer=address -Clto=thin
 //[opt0]compile-flags: -Copt-level=0
 //[opt1]compile-flags: -Copt-level=1
 // run-fail
diff --git a/src/test/ui/span/E0204.stderr b/src/test/ui/span/E0204.stderr
index 25758484352..0b2166eed7e 100644
--- a/src/test/ui/span/E0204.stderr
+++ b/src/test/ui/span/E0204.stderr
@@ -1,11 +1,11 @@
 error[E0204]: the trait `Copy` may not be implemented for this type
-  --> $DIR/E0204.rs:5:6
+  --> $DIR/E0204.rs:5:15
    |
 LL |     foo: Vec<u32>,
    |     ------------- this field does not implement `Copy`
 ...
 LL | impl Copy for Foo { }
-   |      ^^^^
+   |               ^^^
 
 error[E0204]: the trait `Copy` may not be implemented for this type
   --> $DIR/E0204.rs:7:10
@@ -19,13 +19,13 @@ LL |     ty: &'a mut bool,
    = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0204]: the trait `Copy` may not be implemented for this type
-  --> $DIR/E0204.rs:17:6
+  --> $DIR/E0204.rs:17:15
    |
 LL |     Bar { x: Vec<u32> },
    |           ----------- this field does not implement `Copy`
 ...
 LL | impl Copy for EFoo { }
-   |      ^^^^
+   |               ^^^^
 
 error[E0204]: the trait `Copy` may not be implemented for this type
   --> $DIR/E0204.rs:19:10
diff --git a/src/test/ui/span/E0493.rs b/src/test/ui/span/E0493.rs
index ad4100205f2..625da25a7c2 100644
--- a/src/test/ui/span/E0493.rs
+++ b/src/test/ui/span/E0493.rs
@@ -15,7 +15,7 @@ impl Drop for Bar {
 }
 
 const F : Foo = (Foo { a : 0 }, Foo { a : 1 }).1;
-//~^ destructors cannot be evaluated at compile-time
+//~^ ERROR destructor of
 
 fn main() {
 }
diff --git a/src/test/ui/span/E0493.stderr b/src/test/ui/span/E0493.stderr
index 29d1b000943..9db627562d6 100644
--- a/src/test/ui/span/E0493.stderr
+++ b/src/test/ui/span/E0493.stderr
@@ -1,10 +1,10 @@
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `(Foo, Foo)` cannot be evaluated at compile-time
   --> $DIR/E0493.rs:17:17
    |
 LL | const F : Foo = (Foo { a : 0 }, Foo { a : 1 }).1;
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - value is dropped here
    |                 |
-   |                 constants cannot evaluate destructors
+   |                 the destructor for this type cannot be evaluated in constants
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/specialization/const_trait_impl.rs b/src/test/ui/specialization/const_trait_impl.rs
new file mode 100644
index 00000000000..05ba4c8d45d
--- /dev/null
+++ b/src/test/ui/specialization/const_trait_impl.rs
@@ -0,0 +1,55 @@
+// check-pass
+#![feature(const_trait_impl, min_specialization, rustc_attrs)]
+
+#[rustc_specialization_trait]
+#[const_trait]
+pub unsafe trait Sup {
+    fn foo() -> u32;
+}
+
+#[rustc_specialization_trait]
+#[const_trait]
+pub unsafe trait Sub: ~const Sup {}
+
+unsafe impl const Sup for u8 {
+    default fn foo() -> u32 {
+        1
+    }
+}
+
+unsafe impl const Sup for () {
+    fn foo() -> u32 {
+        42
+    }
+}
+
+unsafe impl const Sub for () {}
+
+#[const_trait]
+pub trait A {
+    fn a() -> u32;
+}
+
+impl<T: ~const Default> const A for T {
+    default fn a() -> u32 {
+        2
+    }
+}
+
+impl<T: ~const Default + ~const Sup> const A for T {
+    default fn a() -> u32 {
+        3
+    }
+}
+
+impl<T: ~const Default + ~const Sub> const A for T {
+    fn a() -> u32 {
+        T::foo()
+    }
+}
+
+const _: () = assert!(<()>::a() == 42);
+const _: () = assert!(<u8>::a() == 3);
+const _: () = assert!(<u16>::a() == 2);
+
+fn main() {}
diff --git a/src/test/ui/static/static-drop-scope.rs b/src/test/ui/static/static-drop-scope.rs
index e7ea8663d5a..34afa9873a3 100644
--- a/src/test/ui/static/static-drop-scope.rs
+++ b/src/test/ui/static/static-drop-scope.rs
@@ -5,33 +5,33 @@ impl Drop for WithDtor {
 }
 
 static PROMOTION_FAIL_S: Option<&'static WithDtor> = Some(&WithDtor);
-//~^ ERROR destructors cannot be evaluated at compile-time
+//~^ ERROR destructor of
 //~| ERROR temporary value dropped while borrowed
 
 const PROMOTION_FAIL_C: Option<&'static WithDtor> = Some(&WithDtor);
-//~^ ERROR destructors cannot be evaluated at compile-time
+//~^ ERROR destructor of
 //~| ERROR temporary value dropped while borrowed
 
 static EARLY_DROP_S: i32 = (WithDtor, 0).1;
-//~^ ERROR destructors cannot be evaluated at compile-time
+//~^ ERROR destructor of
 
 const EARLY_DROP_C: i32 = (WithDtor, 0).1;
-//~^ ERROR destructors cannot be evaluated at compile-time
+//~^ ERROR destructor of
 
 const fn const_drop<T>(_: T) {}
-//~^ ERROR destructors cannot be evaluated at compile-time
+//~^ ERROR destructor of
 
 const fn const_drop2<T>(x: T) {
     (x, ()).1
-    //~^ ERROR destructors cannot be evaluated at compile-time
+    //~^ ERROR destructor of
 }
 
 const EARLY_DROP_C_OPTION: i32 = (Some(WithDtor), 0).1;
-//~^ ERROR destructors cannot be evaluated at compile-time
+//~^ ERROR destructor of
 
 const HELPER: Option<WithDtor> = Some(WithDtor);
 
 const EARLY_DROP_C_OPTION_CONSTANT: i32 = (HELPER, 0).1;
-//~^ ERROR destructors cannot be evaluated at compile-time
+//~^ ERROR destructor of
 
 fn main () {}
diff --git a/src/test/ui/static/static-drop-scope.stderr b/src/test/ui/static/static-drop-scope.stderr
index ac32f217fd7..112bfc00304 100644
--- a/src/test/ui/static/static-drop-scope.stderr
+++ b/src/test/ui/static/static-drop-scope.stderr
@@ -1,10 +1,10 @@
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `WithDtor` cannot be evaluated at compile-time
   --> $DIR/static-drop-scope.rs:7:60
    |
 LL | static PROMOTION_FAIL_S: Option<&'static WithDtor> = Some(&WithDtor);
    |                                                            ^^^^^^^^- value is dropped here
    |                                                            |
-   |                                                            statics cannot evaluate destructors
+   |                                                            the destructor for this type cannot be evaluated in statics
 
 error[E0716]: temporary value dropped while borrowed
   --> $DIR/static-drop-scope.rs:7:60
@@ -16,13 +16,13 @@ LL | static PROMOTION_FAIL_S: Option<&'static WithDtor> = Some(&WithDtor);
    |                                                      |     creates a temporary which is freed while still in use
    |                                                      using this value as a static requires that borrow lasts for `'static`
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `WithDtor` cannot be evaluated at compile-time
   --> $DIR/static-drop-scope.rs:11:59
    |
 LL | const PROMOTION_FAIL_C: Option<&'static WithDtor> = Some(&WithDtor);
    |                                                           ^^^^^^^^- value is dropped here
    |                                                           |
-   |                                                           constants cannot evaluate destructors
+   |                                                           the destructor for this type cannot be evaluated in constants
 
 error[E0716]: temporary value dropped while borrowed
   --> $DIR/static-drop-scope.rs:11:59
@@ -34,54 +34,54 @@ LL | const PROMOTION_FAIL_C: Option<&'static WithDtor> = Some(&WithDtor);
    |                                                     |     creates a temporary which is freed while still in use
    |                                                     using this value as a constant requires that borrow lasts for `'static`
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `(WithDtor, i32)` cannot be evaluated at compile-time
   --> $DIR/static-drop-scope.rs:15:28
    |
 LL | static EARLY_DROP_S: i32 = (WithDtor, 0).1;
    |                            ^^^^^^^^^^^^^ - value is dropped here
    |                            |
-   |                            statics cannot evaluate destructors
+   |                            the destructor for this type cannot be evaluated in statics
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `(WithDtor, i32)` cannot be evaluated at compile-time
   --> $DIR/static-drop-scope.rs:18:27
    |
 LL | const EARLY_DROP_C: i32 = (WithDtor, 0).1;
    |                           ^^^^^^^^^^^^^ - value is dropped here
    |                           |
-   |                           constants cannot evaluate destructors
+   |                           the destructor for this type cannot be evaluated in constants
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `T` cannot be evaluated at compile-time
   --> $DIR/static-drop-scope.rs:21:24
    |
 LL | const fn const_drop<T>(_: T) {}
    |                        ^      - value is dropped here
    |                        |
-   |                        constant functions cannot evaluate destructors
+   |                        the destructor for this type cannot be evaluated in constant functions
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `(T, ())` cannot be evaluated at compile-time
   --> $DIR/static-drop-scope.rs:25:5
    |
 LL |     (x, ()).1
-   |     ^^^^^^^ constant functions cannot evaluate destructors
+   |     ^^^^^^^ the destructor for this type cannot be evaluated in constant functions
 LL |
 LL | }
    | - value is dropped here
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `(Option<WithDtor>, i32)` cannot be evaluated at compile-time
   --> $DIR/static-drop-scope.rs:29:34
    |
 LL | const EARLY_DROP_C_OPTION: i32 = (Some(WithDtor), 0).1;
    |                                  ^^^^^^^^^^^^^^^^^^^ - value is dropped here
    |                                  |
-   |                                  constants cannot evaluate destructors
+   |                                  the destructor for this type cannot be evaluated in constants
 
-error[E0493]: destructors cannot be evaluated at compile-time
+error[E0493]: destructor of `(Option<WithDtor>, i32)` cannot be evaluated at compile-time
   --> $DIR/static-drop-scope.rs:34:43
    |
 LL | const EARLY_DROP_C_OPTION_CONSTANT: i32 = (HELPER, 0).1;
    |                                           ^^^^^^^^^^^ - value is dropped here
    |                                           |
-   |                                           constants cannot evaluate destructors
+   |                                           the destructor for this type cannot be evaluated in constants
 
 error: aborting due to 10 previous errors
 
diff --git a/src/test/ui/statics/uninhabited-static.stderr b/src/test/ui/statics/uninhabited-static.stderr
index 88ee4cbdc2e..6d37de8ff3f 100644
--- a/src/test/ui/statics/uninhabited-static.stderr
+++ b/src/test/ui/statics/uninhabited-static.stderr
@@ -59,7 +59,11 @@ LL | static VOID2: Void = unsafe { std::mem::transmute(()) };
    |                               help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
    |
    = note: `#[warn(invalid_value)]` on by default
-   = note: enums with no variants have no valid value
+note: enums with no inhabited variants have no valid value
+  --> $DIR/uninhabited-static.rs:4:1
+   |
+LL | enum Void {}
+   | ^^^^^^^^^
 
 error[E0080]: could not evaluate static initializer
   --> $DIR/uninhabited-static.rs:16:32
@@ -76,7 +80,11 @@ LL | static NEVER2: Void = unsafe { std::mem::transmute(()) };
    |                                this code causes undefined behavior when executed
    |                                help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
    |
-   = note: enums with no variants have no valid value
+note: enums with no inhabited variants have no valid value
+  --> $DIR/uninhabited-static.rs:4:1
+   |
+LL | enum Void {}
+   | ^^^^^^^^^
 
 error: aborting due to 6 previous errors; 2 warnings emitted
 
diff --git a/src/test/ui/stats/hir-stats.stderr b/src/test/ui/stats/hir-stats.stderr
index 8d977606530..350b140aada 100644
--- a/src/test/ui/stats/hir-stats.stderr
+++ b/src/test/ui/stats/hir-stats.stderr
@@ -118,61 +118,61 @@ ast-stats-2
 hir-stats HIR STATS
 hir-stats Name                Accumulated Size         Count     Item Size
 hir-stats ----------------------------------------------------------------
-hir-stats ForeignItemRef            24 ( 0.2%)             1            24
-hir-stats Lifetime                  32 ( 0.3%)             1            32
-hir-stats Mod                       32 ( 0.3%)             1            32
+hir-stats ForeignItemRef            24 ( 0.3%)             1            24
+hir-stats Lifetime                  32 ( 0.4%)             1            32
+hir-stats Mod                       32 ( 0.4%)             1            32
 hir-stats ExprField                 40 ( 0.4%)             1            40
 hir-stats TraitItemRef              56 ( 0.6%)             2            28
 hir-stats Local                     64 ( 0.7%)             1            64
 hir-stats Param                     64 ( 0.7%)             2            32
-hir-stats InlineAsm                 72 ( 0.7%)             1            72
-hir-stats ImplItemRef               72 ( 0.7%)             2            36
-hir-stats Body                      96 ( 1.0%)             3            32
-hir-stats GenericArg                96 ( 1.0%)             4            24
-hir-stats - Type                      24 ( 0.2%)             1
-hir-stats - Lifetime                  72 ( 0.7%)             3
-hir-stats FieldDef                  96 ( 1.0%)             2            48
-hir-stats Arm                       96 ( 1.0%)             2            48
-hir-stats Stmt                      96 ( 1.0%)             3            32
-hir-stats - Local                     32 ( 0.3%)             1
-hir-stats - Semi                      32 ( 0.3%)             1
-hir-stats - Expr                      32 ( 0.3%)             1
-hir-stats FnDecl                   120 ( 1.2%)             3            40
-hir-stats Attribute                128 ( 1.3%)             4            32
-hir-stats GenericArgs              144 ( 1.5%)             3            48
-hir-stats Variant                  160 ( 1.7%)             2            80
-hir-stats WherePredicate           168 ( 1.7%)             3            56
-hir-stats - BoundPredicate           168 ( 1.7%)             3
-hir-stats GenericBound             192 ( 2.0%)             4            48
-hir-stats - Trait                    192 ( 2.0%)             4
-hir-stats Block                    288 ( 3.0%)             6            48
-hir-stats Pat                      360 ( 3.7%)             5            72
-hir-stats - Wild                      72 ( 0.7%)             1
-hir-stats - Struct                    72 ( 0.7%)             1
-hir-stats - Binding                  216 ( 2.2%)             3
-hir-stats GenericParam             400 ( 4.1%)             5            80
-hir-stats Generics                 560 ( 5.8%)            10            56
-hir-stats Ty                       720 ( 7.4%)            15            48
+hir-stats InlineAsm                 72 ( 0.8%)             1            72
+hir-stats ImplItemRef               72 ( 0.8%)             2            36
+hir-stats Body                      96 ( 1.1%)             3            32
+hir-stats GenericArg                96 ( 1.1%)             4            24
+hir-stats - Type                      24 ( 0.3%)             1
+hir-stats - Lifetime                  72 ( 0.8%)             3
+hir-stats FieldDef                  96 ( 1.1%)             2            48
+hir-stats Arm                       96 ( 1.1%)             2            48
+hir-stats Stmt                      96 ( 1.1%)             3            32
+hir-stats - Local                     32 ( 0.4%)             1
+hir-stats - Semi                      32 ( 0.4%)             1
+hir-stats - Expr                      32 ( 0.4%)             1
+hir-stats FnDecl                   120 ( 1.3%)             3            40
+hir-stats Attribute                128 ( 1.4%)             4            32
+hir-stats GenericArgs              144 ( 1.6%)             3            48
+hir-stats Variant                  160 ( 1.8%)             2            80
+hir-stats GenericBound             192 ( 2.1%)             4            48
+hir-stats - Trait                    192 ( 2.1%)             4
+hir-stats WherePredicate           192 ( 2.1%)             3            64
+hir-stats - BoundPredicate           192 ( 2.1%)             3
+hir-stats Block                    288 ( 3.2%)             6            48
+hir-stats Pat                      360 ( 3.9%)             5            72
+hir-stats - Wild                      72 ( 0.8%)             1
+hir-stats - Struct                    72 ( 0.8%)             1
+hir-stats - Binding                  216 ( 2.4%)             3
+hir-stats GenericParam             400 ( 4.4%)             5            80
+hir-stats Generics                 560 ( 6.1%)            10            56
+hir-stats Ty                       720 ( 7.9%)            15            48
 hir-stats - Ptr                       48 ( 0.5%)             1
 hir-stats - Rptr                      48 ( 0.5%)             1
-hir-stats - Path                     624 ( 6.4%)            13
-hir-stats Expr                     768 ( 7.9%)            12            64
+hir-stats - Path                     624 ( 6.8%)            13
+hir-stats Expr                     768 ( 8.4%)            12            64
 hir-stats - Path                      64 ( 0.7%)             1
 hir-stats - Struct                    64 ( 0.7%)             1
 hir-stats - Match                     64 ( 0.7%)             1
 hir-stats - InlineAsm                 64 ( 0.7%)             1
-hir-stats - Lit                      128 ( 1.3%)             2
-hir-stats - Block                    384 ( 4.0%)             6
-hir-stats Item                     960 ( 9.9%)            12            80
-hir-stats - Trait                     80 ( 0.8%)             1
-hir-stats - Enum                      80 ( 0.8%)             1
-hir-stats - ExternCrate               80 ( 0.8%)             1
-hir-stats - ForeignMod                80 ( 0.8%)             1
-hir-stats - Impl                      80 ( 0.8%)             1
-hir-stats - Fn                       160 ( 1.7%)             2
-hir-stats - Use                      400 ( 4.1%)             5
-hir-stats Path                   1_536 (15.9%)            32            48
-hir-stats PathSegment            2_240 (23.1%)            40            56
+hir-stats - Lit                      128 ( 1.4%)             2
+hir-stats - Block                    384 ( 4.2%)             6
+hir-stats Item                     960 (10.5%)            12            80
+hir-stats - Trait                     80 ( 0.9%)             1
+hir-stats - Enum                      80 ( 0.9%)             1
+hir-stats - ExternCrate               80 ( 0.9%)             1
+hir-stats - ForeignMod                80 ( 0.9%)             1
+hir-stats - Impl                      80 ( 0.9%)             1
+hir-stats - Fn                       160 ( 1.8%)             2
+hir-stats - Use                      400 ( 4.4%)             5
+hir-stats Path                   1_280 (14.0%)            32            40
+hir-stats PathSegment            1_920 (21.0%)            40            48
 hir-stats ----------------------------------------------------------------
-hir-stats Total                  9_680
+hir-stats Total                  9_128
 hir-stats
diff --git a/src/test/ui/structs-enums/rec-align-u32.rs b/src/test/ui/structs-enums/rec-align-u32.rs
index 889294daa34..ee704198d19 100644
--- a/src/test/ui/structs-enums/rec-align-u32.rs
+++ b/src/test/ui/structs-enums/rec-align-u32.rs
@@ -10,6 +10,7 @@ use std::mem;
 mod rusti {
     extern "rust-intrinsic" {
         pub fn pref_align_of<T>() -> usize;
+        #[rustc_safe_intrinsic]
         pub fn min_align_of<T>() -> usize;
     }
 }
diff --git a/src/test/ui/structs-enums/rec-align-u64.rs b/src/test/ui/structs-enums/rec-align-u64.rs
index 3bc2d16cf9d..40ede9705f1 100644
--- a/src/test/ui/structs-enums/rec-align-u64.rs
+++ b/src/test/ui/structs-enums/rec-align-u64.rs
@@ -12,6 +12,7 @@ use std::mem;
 mod rusti {
     extern "rust-intrinsic" {
         pub fn pref_align_of<T>() -> usize;
+        #[rustc_safe_intrinsic]
         pub fn min_align_of<T>() -> usize;
     }
 }
diff --git a/src/test/ui/structs/struct-fn-in-definition.stderr b/src/test/ui/structs/struct-fn-in-definition.stderr
index 1d7cd527295..472365c6ed7 100644
--- a/src/test/ui/structs/struct-fn-in-definition.stderr
+++ b/src/test/ui/structs/struct-fn-in-definition.stderr
@@ -1,6 +1,9 @@
 error: functions are not allowed in struct definitions
   --> $DIR/struct-fn-in-definition.rs:9:5
    |
+LL | struct S {
+   |        - while parsing this struct
+...
 LL |     fn foo() {}
    |     ^^^^^^^^^^^
    |
@@ -10,6 +13,9 @@ LL |     fn foo() {}
 error: functions are not allowed in union definitions
   --> $DIR/struct-fn-in-definition.rs:18:5
    |
+LL | union U {
+   |       - while parsing this union
+...
 LL |     fn foo() {}
    |     ^^^^^^^^^^^
    |
@@ -19,6 +25,9 @@ LL |     fn foo() {}
 error: functions are not allowed in enum definitions
   --> $DIR/struct-fn-in-definition.rs:27:5
    |
+LL | enum E {
+   |      - while parsing this enum
+...
 LL |     fn foo() {}
    |     ^^^^^^^^^^^
    |
diff --git a/src/test/ui/structs/struct-path-associated-type.rs b/src/test/ui/structs/struct-path-associated-type.rs
index f88572f8419..2dd7174a9be 100644
--- a/src/test/ui/structs/struct-path-associated-type.rs
+++ b/src/test/ui/structs/struct-path-associated-type.rs
@@ -13,7 +13,7 @@ fn f<T: Tr>() {
     //~^ ERROR expected struct, variant or union type, found associated type
     let z = T::A::<u8> {};
     //~^ ERROR expected struct, variant or union type, found associated type
-    //~| ERROR type arguments are not allowed on this type
+    //~| ERROR this associated type takes 0 generic arguments but 1 generic argument was supplied
     match S {
         T::A {} => {}
         //~^ ERROR expected struct, variant or union type, found associated type
@@ -22,7 +22,7 @@ fn f<T: Tr>() {
 
 fn g<T: Tr<A = S>>() {
     let s = T::A {}; // OK
-    let z = T::A::<u8> {}; //~ ERROR type arguments are not allowed on this type
+    let z = T::A::<u8> {}; //~ ERROR this associated type takes 0 generic arguments but 1 generic argument was supplied
     match S {
         T::A {} => {} // OK
     }
diff --git a/src/test/ui/structs/struct-path-associated-type.stderr b/src/test/ui/structs/struct-path-associated-type.stderr
index bdce0e1b331..abb445214f3 100644
--- a/src/test/ui/structs/struct-path-associated-type.stderr
+++ b/src/test/ui/structs/struct-path-associated-type.stderr
@@ -4,13 +4,19 @@ error[E0071]: expected struct, variant or union type, found associated type
 LL |     let s = T::A {};
    |             ^^^^ not a struct
 
-error[E0109]: type arguments are not allowed on this type
-  --> $DIR/struct-path-associated-type.rs:14:20
+error[E0107]: this associated type takes 0 generic arguments but 1 generic argument was supplied
+  --> $DIR/struct-path-associated-type.rs:14:16
    |
 LL |     let z = T::A::<u8> {};
-   |                -   ^^ type argument not allowed
+   |                ^------ help: remove these generics
    |                |
-   |                not allowed on this type
+   |                expected 0 generic arguments
+   |
+note: associated type defined here, with 0 generic parameters
+  --> $DIR/struct-path-associated-type.rs:4:10
+   |
+LL |     type A;
+   |          ^
 
 error[E0071]: expected struct, variant or union type, found associated type
   --> $DIR/struct-path-associated-type.rs:14:13
@@ -24,13 +30,19 @@ error[E0071]: expected struct, variant or union type, found associated type
 LL |         T::A {} => {}
    |         ^^^^ not a struct
 
-error[E0109]: type arguments are not allowed on this type
-  --> $DIR/struct-path-associated-type.rs:25:20
+error[E0107]: this associated type takes 0 generic arguments but 1 generic argument was supplied
+  --> $DIR/struct-path-associated-type.rs:25:16
    |
 LL |     let z = T::A::<u8> {};
-   |                -   ^^ type argument not allowed
+   |                ^------ help: remove these generics
    |                |
-   |                not allowed on this type
+   |                expected 0 generic arguments
+   |
+note: associated type defined here, with 0 generic parameters
+  --> $DIR/struct-path-associated-type.rs:4:10
+   |
+LL |     type A;
+   |          ^
 
 error[E0223]: ambiguous associated type
   --> $DIR/struct-path-associated-type.rs:32:13
@@ -52,5 +64,5 @@ LL |         S::A {} => {}
 
 error: aborting due to 8 previous errors
 
-Some errors have detailed explanations: E0071, E0109, E0223.
+Some errors have detailed explanations: E0071, E0107, E0223.
 For more information about an error, try `rustc --explain E0071`.
diff --git a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr
index 3c7b895e337..f05dba1d4ca 100644
--- a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr
+++ b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr
@@ -220,7 +220,7 @@ error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:41:20
    |
 LL |     fn ban(&self) -> usize { 42 }
-   |     ---------------------- for<'r> fn(&'r X) -> usize {<X as T>::ban} defined here
+   |     ---------------------- for<'a> fn(&'a X) -> usize {<X as T>::ban} defined here
 ...
 LL |     let _: usize = X::ban;
    |            -----   ^^^^^^ expected `usize`, found fn item
@@ -228,7 +228,7 @@ LL |     let _: usize = X::ban;
    |            expected due to this
    |
    = note: expected type `usize`
-           found fn item `for<'r> fn(&'r X) -> usize {<X as T>::ban}`
+           found fn item `for<'a> fn(&'a X) -> usize {<X as T>::ban}`
 help: use parentheses to call this associated function
    |
 LL |     let _: usize = X::ban(/* &X */);
@@ -238,7 +238,7 @@ error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:42:20
    |
 LL |     fn bal(&self) -> usize;
-   |     ----------------------- for<'r> fn(&'r X) -> usize {<X as T>::bal} defined here
+   |     ----------------------- for<'a> fn(&'a X) -> usize {<X as T>::bal} defined here
 ...
 LL |     let _: usize = X::bal;
    |            -----   ^^^^^^ expected `usize`, found fn item
@@ -246,7 +246,7 @@ LL |     let _: usize = X::bal;
    |            expected due to this
    |
    = note: expected type `usize`
-           found fn item `for<'r> fn(&'r X) -> usize {<X as T>::bal}`
+           found fn item `for<'a> fn(&'a X) -> usize {<X as T>::bal}`
 help: use parentheses to call this associated function
    |
 LL |     let _: usize = X::bal(/* &X */);
diff --git a/src/test/ui/suggestions/inner_type.fixed b/src/test/ui/suggestions/inner_type.fixed
new file mode 100644
index 00000000000..7af7391ca85
--- /dev/null
+++ b/src/test/ui/suggestions/inner_type.fixed
@@ -0,0 +1,40 @@
+// compile-flags: --edition=2021
+// run-rustfix
+
+pub struct Struct<T> {
+    pub p: T,
+}
+
+impl<T> Struct<T> {
+    pub fn method(&self) {}
+
+    pub fn some_mutable_method(&mut self) {}
+}
+
+fn main() {
+    let other_item = std::cell::RefCell::new(Struct { p: 42_u32 });
+
+    other_item.borrow().method();
+    //~^ ERROR no method named `method` found for struct `RefCell` in the current scope [E0599]
+    //~| HELP use `.borrow()` to borrow the `Struct<u32>`, panicking if a mutable borrow exists
+
+    other_item.borrow_mut().some_mutable_method();
+    //~^ ERROR no method named `some_mutable_method` found for struct `RefCell` in the current scope [E0599]
+    //~| HELP .borrow_mut()` to mutably borrow the `Struct<u32>`, panicking if any borrows exist
+
+    let another_item = std::sync::Mutex::new(Struct { p: 42_u32 });
+
+    another_item.lock().unwrap().method();
+    //~^ ERROR no method named `method` found for struct `Mutex` in the current scope [E0599]
+    //~| HELP use `.lock().unwrap()` to borrow the `Struct<u32>`, blocking the current thread until it can be acquired
+
+    let another_item = std::sync::RwLock::new(Struct { p: 42_u32 });
+
+    another_item.read().unwrap().method();
+    //~^ ERROR no method named `method` found for struct `RwLock` in the current scope [E0599]
+    //~| HELP  use `.read().unwrap()` to borrow the `Struct<u32>`, blocking the current thread until it can be acquired
+
+    another_item.write().unwrap().some_mutable_method();
+    //~^ ERROR no method named `some_mutable_method` found for struct `RwLock` in the current scope [E0599]
+    //~| HELP use `.write().unwrap()` to mutably borrow the `Struct<u32>`, blocking the current thread until it can be acquired
+}
diff --git a/src/test/ui/suggestions/inner_type.rs b/src/test/ui/suggestions/inner_type.rs
new file mode 100644
index 00000000000..4aca5071625
--- /dev/null
+++ b/src/test/ui/suggestions/inner_type.rs
@@ -0,0 +1,40 @@
+// compile-flags: --edition=2021
+// run-rustfix
+
+pub struct Struct<T> {
+    pub p: T,
+}
+
+impl<T> Struct<T> {
+    pub fn method(&self) {}
+
+    pub fn some_mutable_method(&mut self) {}
+}
+
+fn main() {
+    let other_item = std::cell::RefCell::new(Struct { p: 42_u32 });
+
+    other_item.method();
+    //~^ ERROR no method named `method` found for struct `RefCell` in the current scope [E0599]
+    //~| HELP use `.borrow()` to borrow the `Struct<u32>`, panicking if a mutable borrow exists
+
+    other_item.some_mutable_method();
+    //~^ ERROR no method named `some_mutable_method` found for struct `RefCell` in the current scope [E0599]
+    //~| HELP .borrow_mut()` to mutably borrow the `Struct<u32>`, panicking if any borrows exist
+
+    let another_item = std::sync::Mutex::new(Struct { p: 42_u32 });
+
+    another_item.method();
+    //~^ ERROR no method named `method` found for struct `Mutex` in the current scope [E0599]
+    //~| HELP use `.lock().unwrap()` to borrow the `Struct<u32>`, blocking the current thread until it can be acquired
+
+    let another_item = std::sync::RwLock::new(Struct { p: 42_u32 });
+
+    another_item.method();
+    //~^ ERROR no method named `method` found for struct `RwLock` in the current scope [E0599]
+    //~| HELP  use `.read().unwrap()` to borrow the `Struct<u32>`, blocking the current thread until it can be acquired
+
+    another_item.some_mutable_method();
+    //~^ ERROR no method named `some_mutable_method` found for struct `RwLock` in the current scope [E0599]
+    //~| HELP use `.write().unwrap()` to mutably borrow the `Struct<u32>`, blocking the current thread until it can be acquired
+}
diff --git a/src/test/ui/suggestions/inner_type.stderr b/src/test/ui/suggestions/inner_type.stderr
new file mode 100644
index 00000000000..5ac3d04f104
--- /dev/null
+++ b/src/test/ui/suggestions/inner_type.stderr
@@ -0,0 +1,83 @@
+error[E0599]: no method named `method` found for struct `RefCell` in the current scope
+  --> $DIR/inner_type.rs:17:16
+   |
+LL |     other_item.method();
+   |                ^^^^^^ method not found in `RefCell<Struct<u32>>`
+   |
+note: the method `method` exists on the type `Struct<u32>`
+  --> $DIR/inner_type.rs:9:5
+   |
+LL |     pub fn method(&self) {}
+   |     ^^^^^^^^^^^^^^^^^^^^
+help: use `.borrow()` to borrow the `Struct<u32>`, panicking if a mutable borrow exists
+   |
+LL |     other_item.borrow().method();
+   |               +++++++++
+
+error[E0599]: no method named `some_mutable_method` found for struct `RefCell` in the current scope
+  --> $DIR/inner_type.rs:21:16
+   |
+LL |     other_item.some_mutable_method();
+   |                ^^^^^^^^^^^^^^^^^^^ method not found in `RefCell<Struct<u32>>`
+   |
+note: the method `some_mutable_method` exists on the type `Struct<u32>`
+  --> $DIR/inner_type.rs:11:5
+   |
+LL |     pub fn some_mutable_method(&mut self) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: use `.borrow_mut()` to mutably borrow the `Struct<u32>`, panicking if any borrows exist
+   |
+LL |     other_item.borrow_mut().some_mutable_method();
+   |               +++++++++++++
+
+error[E0599]: no method named `method` found for struct `Mutex` in the current scope
+  --> $DIR/inner_type.rs:27:18
+   |
+LL |     another_item.method();
+   |                  ^^^^^^ method not found in `Mutex<Struct<u32>>`
+   |
+note: the method `method` exists on the type `Struct<u32>`
+  --> $DIR/inner_type.rs:9:5
+   |
+LL |     pub fn method(&self) {}
+   |     ^^^^^^^^^^^^^^^^^^^^
+help: use `.lock().unwrap()` to borrow the `Struct<u32>`, blocking the current thread until it can be acquired
+   |
+LL |     another_item.lock().unwrap().method();
+   |                 ++++++++++++++++
+
+error[E0599]: no method named `method` found for struct `RwLock` in the current scope
+  --> $DIR/inner_type.rs:33:18
+   |
+LL |     another_item.method();
+   |                  ^^^^^^ method not found in `RwLock<Struct<u32>>`
+   |
+note: the method `method` exists on the type `Struct<u32>`
+  --> $DIR/inner_type.rs:9:5
+   |
+LL |     pub fn method(&self) {}
+   |     ^^^^^^^^^^^^^^^^^^^^
+help: use `.read().unwrap()` to borrow the `Struct<u32>`, blocking the current thread until it can be acquired
+   |
+LL |     another_item.read().unwrap().method();
+   |                 ++++++++++++++++
+
+error[E0599]: no method named `some_mutable_method` found for struct `RwLock` in the current scope
+  --> $DIR/inner_type.rs:37:18
+   |
+LL |     another_item.some_mutable_method();
+   |                  ^^^^^^^^^^^^^^^^^^^ method not found in `RwLock<Struct<u32>>`
+   |
+note: the method `some_mutable_method` exists on the type `Struct<u32>`
+  --> $DIR/inner_type.rs:11:5
+   |
+LL |     pub fn some_mutable_method(&mut self) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: use `.write().unwrap()` to mutably borrow the `Struct<u32>`, blocking the current thread until it can be acquired
+   |
+LL |     another_item.write().unwrap().some_mutable_method();
+   |                 +++++++++++++++++
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/suggestions/inner_type2.rs b/src/test/ui/suggestions/inner_type2.rs
new file mode 100644
index 00000000000..c56ea7c030d
--- /dev/null
+++ b/src/test/ui/suggestions/inner_type2.rs
@@ -0,0 +1,26 @@
+pub struct Struct<T> {
+    pub p: T,
+}
+
+impl<T> Struct<T> {
+    pub fn method(&self) {}
+
+    pub fn some_mutable_method(&mut self) {}
+}
+
+thread_local! {
+    static STRUCT: Struct<u32> = Struct {
+        p: 42_u32
+    };
+}
+
+fn main() {
+    STRUCT.method();
+    //~^ ERROR no method named `method` found for struct `LocalKey` in the current scope [E0599]
+    //~| HELP use `with` or `try_with` to access thread local storage
+
+    let item = std::mem::MaybeUninit::new(Struct { p: 42_u32 });
+    item.method();
+    //~^ ERROR no method named `method` found for union `MaybeUninit` in the current scope [E0599]
+    //~| HELP if this `MaybeUninit::<Struct<u32>>` has been initialized, use one of the `assume_init` methods to access the inner value
+}
diff --git a/src/test/ui/suggestions/inner_type2.stderr b/src/test/ui/suggestions/inner_type2.stderr
new file mode 100644
index 00000000000..eddfd9d6340
--- /dev/null
+++ b/src/test/ui/suggestions/inner_type2.stderr
@@ -0,0 +1,29 @@
+error[E0599]: no method named `method` found for struct `LocalKey` in the current scope
+  --> $DIR/inner_type2.rs:18:12
+   |
+LL |     STRUCT.method();
+   |            ^^^^^^ method not found in `LocalKey<Struct<u32>>`
+   |
+   = help: use `with` or `try_with` to access thread local storage
+note: the method `method` exists on the type `Struct<u32>`
+  --> $DIR/inner_type2.rs:6:5
+   |
+LL |     pub fn method(&self) {}
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error[E0599]: no method named `method` found for union `MaybeUninit` in the current scope
+  --> $DIR/inner_type2.rs:23:10
+   |
+LL |     item.method();
+   |          ^^^^^^ method not found in `MaybeUninit<Struct<u32>>`
+   |
+   = help: if this `MaybeUninit::<Struct<u32>>` has been initialized, use one of the `assume_init` methods to access the inner value
+note: the method `method` exists on the type `Struct<u32>`
+  --> $DIR/inner_type2.rs:6:5
+   |
+LL |     pub fn method(&self) {}
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/suggestions/issue-101984.stderr b/src/test/ui/suggestions/issue-101984.stderr
index c744c62d11f..81758a7007c 100644
--- a/src/test/ui/suggestions/issue-101984.stderr
+++ b/src/test/ui/suggestions/issue-101984.stderr
@@ -2,11 +2,11 @@ error[E0308]: mismatched types
   --> $DIR/issue-101984.rs:21:13
    |
 LL |         let (cmp, router) = self.router.at()?;
-   |             ^^^^^^^^^^^^^   ----------------- this expression has type `Match<&(for<'r> fn(&'r ()), Box<Wrapper>)>`
+   |             ^^^^^^^^^^^^^   ----------------- this expression has type `Match<&(for<'a> fn(&'a ()), Box<Wrapper>)>`
    |             |
    |             expected struct `Match`, found tuple
    |
-   = note: expected struct `Match<&(for<'r> fn(&'r ()), Box<Wrapper>)>`
+   = note: expected struct `Match<&(for<'a> fn(&'a ()), Box<Wrapper>)>`
                found tuple `(_, _)`
 
 error: aborting due to previous error
diff --git a/src/test/ui/suggestions/issue-85347.rs b/src/test/ui/suggestions/issue-85347.rs
index dd52b315055..02b5fb61894 100644
--- a/src/test/ui/suggestions/issue-85347.rs
+++ b/src/test/ui/suggestions/issue-85347.rs
@@ -2,6 +2,7 @@ use std::ops::Deref;
 trait Foo {
     type Bar<'a>: Deref<Target = <Self>::Bar<Target = Self>>;
     //~^ ERROR this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
+    //~| ERROR associated type bindings are not allowed here
     //~| HELP add missing
 }
 
diff --git a/src/test/ui/suggestions/issue-85347.stderr b/src/test/ui/suggestions/issue-85347.stderr
index de853de27e4..17c1b7dc4cc 100644
--- a/src/test/ui/suggestions/issue-85347.stderr
+++ b/src/test/ui/suggestions/issue-85347.stderr
@@ -14,6 +14,13 @@ help: add missing lifetime argument
 LL |     type Bar<'a>: Deref<Target = <Self>::Bar<'a, Target = Self>>;
    |                                              +++
 
-error: aborting due to previous error
+error[E0229]: associated type bindings are not allowed here
+  --> $DIR/issue-85347.rs:3:46
+   |
+LL |     type Bar<'a>: Deref<Target = <Self>::Bar<Target = Self>>;
+   |                                              ^^^^^^^^^^^^^ associated type not allowed here
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0107`.
+Some errors have detailed explanations: E0107, E0229.
+For more information about an error, try `rustc --explain E0107`.
diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr
index e5d2ead6ad6..872263fd731 100644
--- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr
+++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr
@@ -27,3 +27,4 @@ LL | fn func<'a, T: Test + 'a>(foo: &Foo, t: T) {
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0311`.
diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
index ed1b91676a2..171f4b333db 100644
--- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
+++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
@@ -164,5 +164,5 @@ LL |     G: Get<T> + 'a,
 
 error: aborting due to 8 previous errors
 
-Some errors have detailed explanations: E0261, E0309, E0621, E0700.
+Some errors have detailed explanations: E0261, E0309, E0311, E0621, E0700.
 For more information about an error, try `rustc --explain E0261`.
diff --git a/src/test/ui/suggestions/missing-bound-in-manual-copy-impl-2.stderr b/src/test/ui/suggestions/missing-bound-in-manual-copy-impl-2.stderr
index e0f405eedfa..9e6f0d9ebbd 100644
--- a/src/test/ui/suggestions/missing-bound-in-manual-copy-impl-2.stderr
+++ b/src/test/ui/suggestions/missing-bound-in-manual-copy-impl-2.stderr
@@ -1,11 +1,11 @@
 error[E0204]: the trait `Copy` may not be implemented for this type
-  --> $DIR/missing-bound-in-manual-copy-impl-2.rs:16:9
+  --> $DIR/missing-bound-in-manual-copy-impl-2.rs:16:18
    |
 LL | struct Wrapper<T>(T);
    |                   - this field does not implement `Copy`
 ...
 LL | impl<S> Copy for Wrapper<OnlyCopyIfDisplay<S>> {}
-   |         ^^^^
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the `Copy` impl for `OnlyCopyIfDisplay<S>` requires that `S: std::fmt::Display`
   --> $DIR/missing-bound-in-manual-copy-impl-2.rs:4:19
diff --git a/src/test/ui/suggestions/missing-bound-in-manual-copy-impl.stderr b/src/test/ui/suggestions/missing-bound-in-manual-copy-impl.stderr
index 218988511db..fe2d133c8aa 100644
--- a/src/test/ui/suggestions/missing-bound-in-manual-copy-impl.stderr
+++ b/src/test/ui/suggestions/missing-bound-in-manual-copy-impl.stderr
@@ -1,11 +1,11 @@
 error[E0204]: the trait `Copy` may not be implemented for this type
-  --> $DIR/missing-bound-in-manual-copy-impl.rs:6:9
+  --> $DIR/missing-bound-in-manual-copy-impl.rs:6:18
    |
 LL | struct Wrapper<T>(T);
    |                   - this field does not implement `Copy`
 LL |
 LL | impl<S> Copy for Wrapper<S> {}
-   |         ^^^^
+   |                  ^^^^^^^^^^
    |
 help: consider restricting type parameter `S`
    |
diff --git a/src/test/ui/suggestions/non-existent-field-present-in-subfield-recursion-limit.rs b/src/test/ui/suggestions/non-existent-field-present-in-subfield-recursion-limit.rs
index 98b408daa02..a7a3f98180a 100644
--- a/src/test/ui/suggestions/non-existent-field-present-in-subfield-recursion-limit.rs
+++ b/src/test/ui/suggestions/non-existent-field-present-in-subfield-recursion-limit.rs
@@ -1,4 +1,4 @@
-// In rustc_typeck::check::expr::no_such_field_err we recursively
+// In rustc_hir_analysis::check::expr::no_such_field_err we recursively
 // look in subfields for the field. This recursive search is limited
 // in depth for compile-time reasons and to avoid infinite recursion
 // in case of cycles. This file tests that the limit in the recursion
diff --git a/src/test/ui/suggestions/return-closures.stderr b/src/test/ui/suggestions/return-closures.stderr
index e273793ea2c..8b856d8de70 100644
--- a/src/test/ui/suggestions/return-closures.stderr
+++ b/src/test/ui/suggestions/return-closures.stderr
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/return-closures.rs:3:5
    |
 LL | fn foo() {
-   |          - help: try adding a return type: `-> impl for<'r> Fn(&'r i32) -> i32`
+   |          - help: try adding a return type: `-> impl for<'a> Fn(&'a i32) -> i32`
 LL |
 LL |     |x: &i32| 1i32
    |     ^^^^^^^^^^^^^^ expected `()`, found closure
diff --git a/src/test/ui/suggestions/struct-field-type-including-single-colon.stderr b/src/test/ui/suggestions/struct-field-type-including-single-colon.stderr
index 189759d64fc..4dd514480da 100644
--- a/src/test/ui/suggestions/struct-field-type-including-single-colon.stderr
+++ b/src/test/ui/suggestions/struct-field-type-including-single-colon.stderr
@@ -12,6 +12,8 @@ LL |     a: foo::A,
 error: expected `,`, or `}`, found `:`
   --> $DIR/struct-field-type-including-single-colon.rs:9:11
    |
+LL | struct Foo {
+   |        --- while parsing this struct
 LL |     a: foo:A,
    |           ^
 
@@ -29,6 +31,8 @@ LL |     b: foo::bar::B,
 error: expected `,`, or `}`, found `:`
   --> $DIR/struct-field-type-including-single-colon.rs:15:16
    |
+LL | struct Bar {
+   |        --- while parsing this struct
 LL |     b: foo::bar:B,
    |                ^
 
diff --git a/src/test/ui/symbol-names/impl1.legacy.stderr b/src/test/ui/symbol-names/impl1.legacy.stderr
index b6012e41594..3d438df92b8 100644
--- a/src/test/ui/symbol-names/impl1.legacy.stderr
+++ b/src/test/ui/symbol-names/impl1.legacy.stderr
@@ -64,7 +64,7 @@ error: demangling-alt(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::A
 LL |             #[rustc_symbol_name]
    |             ^^^^^^^^^^^^^^^^^^^^
 
-error: def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as main::{closure#1}::Bar>::method)
+error: def-path(<[&dyn Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + AutoTrait; 3] as main::{closure#1}::Bar>::method)
   --> $DIR/impl1.rs:69:13
    |
 LL |             #[rustc_def_path]
diff --git a/src/test/ui/symbol-names/impl1.rs b/src/test/ui/symbol-names/impl1.rs
index 86f0a8b0bef..629c2f33ddc 100644
--- a/src/test/ui/symbol-names/impl1.rs
+++ b/src/test/ui/symbol-names/impl1.rs
@@ -67,8 +67,8 @@ fn main() {
                 //[v0]~| ERROR demangling(<[&dyn
                 //[v0]~| ERROR demangling-alt(<[&dyn impl1::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1::AutoTrait; 3] as impl1::main::{closure#1}::Bar>::method)
             #[rustc_def_path]
-            //[legacy]~^ ERROR def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as main::{closure#1}::Bar>::method)
-               //[v0]~^^ ERROR def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as main::{closure#1}::Bar>::method)
+            //[legacy]~^ ERROR def-path(<[&dyn Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + AutoTrait; 3] as main::{closure#1}::Bar>::method)
+               //[v0]~^^ ERROR def-path(<[&dyn Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + AutoTrait; 3] as main::{closure#1}::Bar>::method)
             fn method(&self) {}
         }
     };
diff --git a/src/test/ui/symbol-names/impl1.v0.stderr b/src/test/ui/symbol-names/impl1.v0.stderr
index 48f7473b6a0..33caad71f52 100644
--- a/src/test/ui/symbol-names/impl1.v0.stderr
+++ b/src/test/ui/symbol-names/impl1.v0.stderr
@@ -64,7 +64,7 @@ error: demangling-alt(<[&dyn impl1::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ..
 LL |             #[rustc_symbol_name]
    |             ^^^^^^^^^^^^^^^^^^^^
 
-error: def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as main::{closure#1}::Bar>::method)
+error: def-path(<[&dyn Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + AutoTrait; 3] as main::{closure#1}::Bar>::method)
   --> $DIR/impl1.rs:69:13
    |
 LL |             #[rustc_def_path]
diff --git a/src/test/ui/thir-tree.stdout b/src/test/ui/thir-tree.stdout
index 5fcdfca18d6..7fb90581f8a 100644
--- a/src/test/ui/thir-tree.stdout
+++ b/src/test/ui/thir-tree.stdout
@@ -33,7 +33,9 @@ Thir {
                 region_scope: Node(2),
                 lint_level: Explicit(
                     HirId {
-                        owner: DefId(0:3 ~ thir_tree[8f1d]::main),
+                        owner: OwnerId {
+                            def_id: DefId(0:3 ~ thir_tree[8f1d]::main),
+                        },
                         local_id: 2,
                     },
                 ),
diff --git a/src/test/ui/traits/associated_type_bound/check-trait-object-bounds-2.stderr b/src/test/ui/traits/associated_type_bound/check-trait-object-bounds-2.stderr
index 4084f69a6f0..10e82c54e0f 100644
--- a/src/test/ui/traits/associated_type_bound/check-trait-object-bounds-2.stderr
+++ b/src/test/ui/traits/associated_type_bound/check-trait-object-bounds-2.stderr
@@ -4,7 +4,7 @@ error[E0277]: expected a `FnOnce<(&i32,)>` closure, found `i32`
 LL |     f::<dyn for<'x> X<'x, F = i32>>();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `FnOnce<(&i32,)>` closure, found `i32`
    |
-   = help: the trait `for<'r> FnOnce<(&'r i32,)>` is not implemented for `i32`
+   = help: the trait `for<'a> FnOnce<(&'a i32,)>` is not implemented for `i32`
 note: required by a bound in `f`
   --> $DIR/check-trait-object-bounds-2.rs:8:9
    |
diff --git a/src/test/ui/traits/copy-impl-cannot-normalize.stderr b/src/test/ui/traits/copy-impl-cannot-normalize.stderr
index afdad160919..68b95b42b34 100644
--- a/src/test/ui/traits/copy-impl-cannot-normalize.stderr
+++ b/src/test/ui/traits/copy-impl-cannot-normalize.stderr
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `T: TraitFoo` is not satisfied
-  --> $DIR/copy-impl-cannot-normalize.rs:22:1
+  --> $DIR/copy-impl-cannot-normalize.rs:22:18
    |
 LL | impl<T> Copy for Foo<T> {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `TraitFoo` is not implemented for `T`
+   |                  ^^^^^^ the trait `TraitFoo` is not implemented for `T`
    |
 help: consider restricting type parameter `T`
    |
diff --git a/src/test/ui/type-alias-impl-trait/implied_bounds.rs b/src/test/ui/type-alias-impl-trait/implied_bounds.rs
new file mode 100644
index 00000000000..53cbf8d2290
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/implied_bounds.rs
@@ -0,0 +1,51 @@
+#![feature(type_alias_impl_trait)]
+
+type WithLifetime<'a> = impl Equals<SelfType = ()>;
+fn _defining_use<'a>() -> WithLifetime<'a> {}
+
+trait Convert<'a> {
+    type Witness;
+    fn convert<'b, T: ?Sized>(_proof: &'b Self::Witness, x: &'a T) -> &'b T;
+}
+
+impl<'a> Convert<'a> for () {
+    type Witness = WithLifetime<'a>;
+
+    fn convert<'b, T: ?Sized>(_proof: &'b WithLifetime<'a>, x: &'a T) -> &'b T {
+        // compiler used to think it gets to assume 'a: 'b here because
+        // of the `&'b WithLifetime<'a>` argument
+        x
+        //~^ ERROR lifetime may not live long enough
+    }
+}
+
+fn extend_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T {
+    WithLifetime::<'a>::convert_helper::<(), T>(&(), x)
+}
+
+trait Equals {
+    type SelfType;
+    fn convert_helper<'a, 'b, W: Convert<'a, Witness = Self>, T: ?Sized>(
+        proof: &'b Self::SelfType,
+        x: &'a T,
+    ) -> &'b T;
+}
+
+impl<S> Equals for S {
+    type SelfType = Self;
+    fn convert_helper<'a, 'b, W: Convert<'a, Witness = Self>, T: ?Sized>(
+        proof: &'b Self,
+        x: &'a T,
+    ) -> &'b T {
+        W::convert(proof, x)
+    }
+}
+
+fn main() {
+    let r;
+    {
+        let x = String::from("Hello World?");
+        r = extend_lifetime(&x);
+    }
+    println!("{}", r);
+}
diff --git a/src/test/ui/type-alias-impl-trait/implied_bounds.stderr b/src/test/ui/type-alias-impl-trait/implied_bounds.stderr
new file mode 100644
index 00000000000..6f11b66634b
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/implied_bounds.stderr
@@ -0,0 +1,16 @@
+error: lifetime may not live long enough
+  --> $DIR/implied_bounds.rs:17:9
+   |
+LL | impl<'a> Convert<'a> for () {
+   |      -- lifetime `'a` defined here
+...
+LL |     fn convert<'b, T: ?Sized>(_proof: &'b WithLifetime<'a>, x: &'a T) -> &'b T {
+   |                -- lifetime `'b` defined here
+...
+LL |         x
+   |         ^ associated function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/type-alias-impl-trait/implied_bounds2.rs b/src/test/ui/type-alias-impl-trait/implied_bounds2.rs
new file mode 100644
index 00000000000..b4c4c013cd2
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/implied_bounds2.rs
@@ -0,0 +1,10 @@
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+
+type Ty<'a, A> = impl Sized + 'a;
+fn defining<'a, A>() -> Ty<'a, A> {}
+fn assert_static<T: 'static>() {}
+fn test<'a, A>() where Ty<'a, A>: 'static, { assert_static::<Ty<'a, A>>() }
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/implied_bounds3.rs b/src/test/ui/type-alias-impl-trait/implied_bounds3.rs
new file mode 100644
index 00000000000..e39c613281d
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/implied_bounds3.rs
@@ -0,0 +1,18 @@
+// check-pass
+
+fn foo<F>(_: F)
+where
+    F: 'static,
+{
+}
+
+fn from<F: Send>(f: F) -> impl Send {
+    f
+}
+
+fn bar<T>() {
+    foo(from(|| ()))
+}
+
+fn main() {
+}
diff --git a/src/test/ui/type-alias-impl-trait/implied_bounds_closure.rs b/src/test/ui/type-alias-impl-trait/implied_bounds_closure.rs
new file mode 100644
index 00000000000..4cf35f95190
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/implied_bounds_closure.rs
@@ -0,0 +1,31 @@
+trait StaticDefaultRef: 'static {
+    fn default_ref() -> &'static Self;
+}
+
+impl StaticDefaultRef for str {
+    fn default_ref() -> &'static str {
+        ""
+    }
+}
+
+fn into_impl(x: &str) -> &(impl ?Sized + AsRef<str> + StaticDefaultRef + '_) {
+    x
+}
+
+fn extend_lifetime<'a>(x: &'a str) -> &'static str {
+    let t = into_impl(x);
+    helper(|_| t) //~ ERROR lifetime may not live long enough
+}
+
+fn helper<T: ?Sized + AsRef<str> + StaticDefaultRef>(f: impl FnOnce(&T) -> &T) -> &'static str {
+    f(T::default_ref()).as_ref()
+}
+
+fn main() {
+    let r;
+    {
+        let x = String::from("Hello World?");
+        r = extend_lifetime(&x);
+    }
+    println!("{}", r);
+}
diff --git a/src/test/ui/type-alias-impl-trait/implied_bounds_closure.stderr b/src/test/ui/type-alias-impl-trait/implied_bounds_closure.stderr
new file mode 100644
index 00000000000..151564c3b45
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/implied_bounds_closure.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+  --> $DIR/implied_bounds_closure.rs:17:16
+   |
+LL | fn extend_lifetime<'a>(x: &'a str) -> &'static str {
+   |                    -- lifetime `'a` defined here
+LL |     let t = into_impl(x);
+LL |     helper(|_| t)
+   |                ^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/type-alias-impl-trait/implied_bounds_from_types.rs b/src/test/ui/type-alias-impl-trait/implied_bounds_from_types.rs
new file mode 100644
index 00000000000..8023cd24f0b
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/implied_bounds_from_types.rs
@@ -0,0 +1,51 @@
+#![feature(type_alias_impl_trait)]
+
+type WithLifetime<T> = impl Equals<SelfType = ()>;
+fn _defining_use<T>() -> WithLifetime<T> {}
+
+trait Convert<'a> {
+    type Witness;
+    fn convert<'b, T: ?Sized>(_proof: &'b Self::Witness, x: &'a T) -> &'b T;
+}
+
+impl<'a> Convert<'a> for () {
+    type Witness = WithLifetime<&'a ()>;
+
+    fn convert<'b, T: ?Sized>(_proof: &'b WithLifetime<&'a ()>, x: &'a T) -> &'b T {
+        // compiler used to think it gets to assume 'a: 'b here because
+        // of the `&'b WithLifetime<&'a ()>` argument
+        x
+        //~^ ERROR lifetime may not live long enough
+    }
+}
+
+fn extend_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T {
+    WithLifetime::<&'a ()>::convert_helper::<(), T>(&(), x)
+}
+
+trait Equals {
+    type SelfType;
+    fn convert_helper<'a, 'b, W: Convert<'a, Witness = Self>, T: ?Sized>(
+        proof: &'b Self::SelfType,
+        x: &'a T,
+    ) -> &'b T;
+}
+
+impl<S> Equals for S {
+    type SelfType = Self;
+    fn convert_helper<'a, 'b, W: Convert<'a, Witness = Self>, T: ?Sized>(
+        proof: &'b Self,
+        x: &'a T,
+    ) -> &'b T {
+        W::convert(proof, x)
+    }
+}
+
+fn main() {
+    let r;
+    {
+        let x = String::from("Hello World?");
+        r = extend_lifetime(&x);
+    }
+    println!("{}", r);
+}
diff --git a/src/test/ui/type-alias-impl-trait/implied_bounds_from_types.stderr b/src/test/ui/type-alias-impl-trait/implied_bounds_from_types.stderr
new file mode 100644
index 00000000000..cbc5e607318
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/implied_bounds_from_types.stderr
@@ -0,0 +1,16 @@
+error: lifetime may not live long enough
+  --> $DIR/implied_bounds_from_types.rs:17:9
+   |
+LL | impl<'a> Convert<'a> for () {
+   |      -- lifetime `'a` defined here
+...
+LL |     fn convert<'b, T: ?Sized>(_proof: &'b WithLifetime<&'a ()>, x: &'a T) -> &'b T {
+   |                -- lifetime `'b` defined here
+...
+LL |         x
+   |         ^ associated function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check.rs b/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check.rs
new file mode 100644
index 00000000000..b6a7264a529
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check.rs
@@ -0,0 +1,27 @@
+#![feature(type_alias_impl_trait)]
+
+// known-bug: #99840
+// this should not compile
+// check-pass
+
+type Alias = impl Sized;
+
+fn constrain() -> Alias {
+    1i32
+}
+
+trait HideIt {
+    type Assoc;
+}
+
+impl HideIt for () {
+    type Assoc = Alias;
+}
+
+pub trait Yay {}
+
+impl Yay for <() as HideIt>::Assoc {}
+// impl Yay for i32 {} // this already errors
+// impl Yay for u32 {} // this also already errors
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check3.rs b/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check3.rs
new file mode 100644
index 00000000000..6e5b8f491ea
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check3.rs
@@ -0,0 +1,43 @@
+#![feature(type_alias_impl_trait)]
+
+mod test_lifetime_param {
+    type Ty<'a> = impl Sized;
+    fn defining(a: &str) -> Ty<'_> { a }
+    fn assert_static<'a: 'static>() {}
+    //~^ WARN: unnecessary lifetime parameter `'a`
+    fn test<'a>() where Ty<'a>: 'static { assert_static::<'a>() }
+    //~^ ERROR: lifetime may not live long enough
+}
+
+mod test_higher_kinded_lifetime_param {
+    type Ty<'a> = impl Sized;
+    fn defining(a: &str) -> Ty<'_> { a }
+    fn assert_static<'a: 'static>() {}
+    //~^ WARN: unnecessary lifetime parameter `'a`
+    fn test<'a>() where for<'b> Ty<'b>: 'a { assert_static::<'a>() }
+    //~^ ERROR: lifetime may not live long enough
+}
+
+mod test_higher_kinded_lifetime_param2 {
+    fn assert_static<'a: 'static>() {}
+    //~^ WARN: unnecessary lifetime parameter `'a`
+    fn test<'a>() { assert_static::<'a>() }
+    //~^ ERROR: lifetime may not live long enough
+}
+
+mod test_type_param {
+    type Ty<A> = impl Sized;
+    fn defining<A>(s: A) -> Ty<A> { s }
+    fn assert_static<A: 'static>() {}
+    fn test<A>() where Ty<A>: 'static { assert_static::<A>() }
+    //~^ ERROR: parameter type `A` may not live long enough
+}
+
+mod test_implied_from_fn_sig {
+    type Opaque<T: 'static> = impl Sized;
+    fn defining<T: 'static>() -> Opaque<T> {}
+    fn assert_static<T: 'static>() {}
+    fn test<T>(_: Opaque<T>) { assert_static::<T>(); }
+}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check3.stderr b/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check3.stderr
new file mode 100644
index 00000000000..887620a4d50
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check3.stderr
@@ -0,0 +1,58 @@
+warning: unnecessary lifetime parameter `'a`
+  --> $DIR/implied_lifetime_wf_check3.rs:6:22
+   |
+LL |     fn assert_static<'a: 'static>() {}
+   |                      ^^
+   |
+   = help: you can use the `'static` lifetime directly, in place of `'a`
+
+warning: unnecessary lifetime parameter `'a`
+  --> $DIR/implied_lifetime_wf_check3.rs:15:22
+   |
+LL |     fn assert_static<'a: 'static>() {}
+   |                      ^^
+   |
+   = help: you can use the `'static` lifetime directly, in place of `'a`
+
+warning: unnecessary lifetime parameter `'a`
+  --> $DIR/implied_lifetime_wf_check3.rs:22:22
+   |
+LL |     fn assert_static<'a: 'static>() {}
+   |                      ^^
+   |
+   = help: you can use the `'static` lifetime directly, in place of `'a`
+
+error: lifetime may not live long enough
+  --> $DIR/implied_lifetime_wf_check3.rs:8:43
+   |
+LL |     fn test<'a>() where Ty<'a>: 'static { assert_static::<'a>() }
+   |             -- lifetime `'a` defined here ^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/implied_lifetime_wf_check3.rs:17:46
+   |
+LL |     fn test<'a>() where for<'b> Ty<'b>: 'a { assert_static::<'a>() }
+   |             -- lifetime `'a` defined here    ^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/implied_lifetime_wf_check3.rs:24:21
+   |
+LL |     fn test<'a>() { assert_static::<'a>() }
+   |             --      ^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+   |             |
+   |             lifetime `'a` defined here
+
+error[E0310]: the parameter type `A` may not live long enough
+  --> $DIR/implied_lifetime_wf_check3.rs:32:41
+   |
+LL |     fn test<A>() where Ty<A>: 'static { assert_static::<A>() }
+   |                                         ^^^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     fn test<A: 'static>() where Ty<A>: 'static { assert_static::<A>() }
+   |              +++++++++
+
+error: aborting due to 4 previous errors; 3 warnings emitted
+
+For more information about this error, try `rustc --explain E0310`.
diff --git a/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.rs b/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.rs
new file mode 100644
index 00000000000..ac32dbde04b
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.rs
@@ -0,0 +1,11 @@
+#![feature(type_alias_impl_trait)]
+
+mod test_type_param_static {
+    type Ty<A> = impl Sized + 'static;
+    //~^ ERROR: the parameter type `A` may not live long enough
+    fn defining<A: 'static>(s: A) -> Ty<A> { s }
+    fn assert_static<A: 'static>() {}
+    fn test<A>() where Ty<A>: 'static { assert_static::<A>() }
+}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.stderr b/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.stderr
new file mode 100644
index 00000000000..47bc31e78c3
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.stderr
@@ -0,0 +1,14 @@
+error[E0310]: the parameter type `A` may not live long enough
+  --> $DIR/implied_lifetime_wf_check4_static.rs:4:18
+   |
+LL |     type Ty<A> = impl Sized + 'static;
+   |                  ^^^^^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     type Ty<A: 'static> = impl Sized + 'static;
+   |              +++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0310`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr
index f14bf6b0f7f..6344f114a91 100644
--- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr
@@ -4,7 +4,7 @@ error[E0308]: mismatched types
 LL |         |x| x
    |         ^^^^^ one type is more general than the other
    |
-   = note: expected trait `for<'r> Fn<(&'r X,)>`
+   = note: expected trait `for<'a> Fn<(&'a X,)>`
               found trait `Fn<(&X,)>`
 note: this closure does not fulfill the lifetime requirements
   --> $DIR/issue-57611-trait-alias.rs:21:9
diff --git a/src/test/ui/type-alias-impl-trait/issue-58662-generator-with-lifetime.rs b/src/test/ui/type-alias-impl-trait/issue-58662-generator-with-lifetime.rs
index f20ddf02071..477b61390ed 100644
--- a/src/test/ui/type-alias-impl-trait/issue-58662-generator-with-lifetime.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-58662-generator-with-lifetime.rs
@@ -16,7 +16,7 @@ fn rand_generator<'a>(rng: &'a ()) -> RandGenerator<'a> {
     }
 }
 
-pub type RandGeneratorWithIndirection<'a> = impl Generator<Return = (), Yield = u64> + 'a;
+pub type RandGeneratorWithIndirection<'c> = impl Generator<Return = (), Yield = u64> + 'c;
 pub fn rand_generator_with_indirection<'a>(rng: &'a ()) -> RandGeneratorWithIndirection<'a> {
     fn helper<'b>(rng: &'b ()) -> impl 'b + Generator<Return = (), Yield = u64> {
         move || {
diff --git a/src/test/ui/type-alias-impl-trait/issue-58662-simplified.rs b/src/test/ui/type-alias-impl-trait/issue-58662-simplified.rs
new file mode 100644
index 00000000000..27ca7d0fdc9
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-58662-simplified.rs
@@ -0,0 +1,20 @@
+// check-pass
+
+#![feature(generators, generator_trait)]
+#![feature(type_alias_impl_trait)]
+
+trait Trait {}
+
+impl<T> Trait for T {}
+
+type Foo<'c> = impl Trait + 'c;
+fn foo<'a>(rng: &'a ()) -> Foo<'a> {
+    fn helper<'b>(rng: &'b ()) -> impl 'b + Trait {
+        rng
+    }
+
+    helper(rng)
+}
+
+fn main() {
+}
diff --git a/src/test/ui/type-alias-impl-trait/unbounded_opaque_type.rs b/src/test/ui/type-alias-impl-trait/unbounded_opaque_type.rs
new file mode 100644
index 00000000000..f43ad7dce1d
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/unbounded_opaque_type.rs
@@ -0,0 +1,14 @@
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+type Opaque<T> = impl Sized;
+fn defining<T>() -> Opaque<T> {}
+struct Ss<'a, T>(&'a Opaque<T>);
+
+
+fn test<'a, T>(_: Ss<'a, T>) {
+    // test that we have an implied bound `Opaque<T>: 'a` from fn signature
+    None::<&'a Opaque<T>>;
+}
+
+fn main() {}
diff --git a/src/test/ui/typeck/issue-69378-ice-on-invalid-type-node-after-recovery.stderr b/src/test/ui/typeck/issue-69378-ice-on-invalid-type-node-after-recovery.stderr
index 6bc9c8498c9..fc7c23a2252 100644
--- a/src/test/ui/typeck/issue-69378-ice-on-invalid-type-node-after-recovery.stderr
+++ b/src/test/ui/typeck/issue-69378-ice-on-invalid-type-node-after-recovery.stderr
@@ -2,7 +2,9 @@ error: expected identifier, found `0`
   --> $DIR/issue-69378-ice-on-invalid-type-node-after-recovery.rs:3:14
    |
 LL | struct Foo { 0: u8 }
-   |              ^ expected identifier
+   |        ---   ^ expected identifier
+   |        |
+   |        while parsing this struct
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr
index 9833304c636..802696e1b2f 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr
@@ -1,4 +1,4 @@
-error[E0277]: expected a `Fn<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
+error[E0277]: expected a `Fn<(&isize,)>` closure, found `for<'a> unsafe fn(&'a isize) -> isize {square}`
   --> $DIR/unboxed-closures-unsafe-extern-fn.rs:20:21
    |
 LL |     let x = call_it(&square, 22);
@@ -6,7 +6,7 @@ LL |     let x = call_it(&square, 22);
    |             |
    |             required by a bound introduced by this call
    |
-   = help: the trait `for<'r> Fn<(&'r isize,)>` is not implemented for fn item `for<'r> unsafe fn(&'r isize) -> isize {square}`
+   = help: the trait `for<'a> Fn<(&'a isize,)>` is not implemented for fn item `for<'a> unsafe fn(&'a isize) -> isize {square}`
    = note: unsafe function cannot be called generically without an unsafe block
 note: required by a bound in `call_it`
   --> $DIR/unboxed-closures-unsafe-extern-fn.rs:9:15
@@ -14,7 +14,7 @@ note: required by a bound in `call_it`
 LL | fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize {
    |               ^^^^^^^^^^^^^^^^^^^ required by this bound in `call_it`
 
-error[E0277]: expected a `FnMut<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
+error[E0277]: expected a `FnMut<(&isize,)>` closure, found `for<'a> unsafe fn(&'a isize) -> isize {square}`
   --> $DIR/unboxed-closures-unsafe-extern-fn.rs:25:25
    |
 LL |     let y = call_it_mut(&mut square, 22);
@@ -22,7 +22,7 @@ LL |     let y = call_it_mut(&mut square, 22);
    |             |
    |             required by a bound introduced by this call
    |
-   = help: the trait `for<'r> FnMut<(&'r isize,)>` is not implemented for fn item `for<'r> unsafe fn(&'r isize) -> isize {square}`
+   = help: the trait `for<'a> FnMut<(&'a isize,)>` is not implemented for fn item `for<'a> unsafe fn(&'a isize) -> isize {square}`
    = note: unsafe function cannot be called generically without an unsafe block
 note: required by a bound in `call_it_mut`
   --> $DIR/unboxed-closures-unsafe-extern-fn.rs:12:19
@@ -30,7 +30,7 @@ note: required by a bound in `call_it_mut`
 LL | fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize {
    |                   ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `call_it_mut`
 
-error[E0277]: expected a `FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
+error[E0277]: expected a `FnOnce<(&isize,)>` closure, found `for<'a> unsafe fn(&'a isize) -> isize {square}`
   --> $DIR/unboxed-closures-unsafe-extern-fn.rs:30:26
    |
 LL |     let z = call_it_once(square, 22);
@@ -38,7 +38,7 @@ LL |     let z = call_it_once(square, 22);
    |             |
    |             required by a bound introduced by this call
    |
-   = help: the trait `for<'r> FnOnce<(&'r isize,)>` is not implemented for fn item `for<'r> unsafe fn(&'r isize) -> isize {square}`
+   = help: the trait `for<'a> FnOnce<(&'a isize,)>` is not implemented for fn item `for<'a> unsafe fn(&'a isize) -> isize {square}`
    = note: unsafe function cannot be called generically without an unsafe block
 note: required by a bound in `call_it_once`
   --> $DIR/unboxed-closures-unsafe-extern-fn.rs:15:20
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr b/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr
index 54c92e0cd04..0bbb9836c58 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr
@@ -1,42 +1,42 @@
-error[E0277]: expected a `Fn<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
+error[E0277]: expected a `Fn<(&isize,)>` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}`
   --> $DIR/unboxed-closures-wrong-abi.rs:20:21
    |
 LL |     let x = call_it(&square, 22);
-   |             ------- ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
+   |             ------- ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}`
    |             |
    |             required by a bound introduced by this call
    |
-   = help: the trait `for<'r> Fn<(&'r isize,)>` is not implemented for fn item `for<'r> extern "C" fn(&'r isize) -> isize {square}`
+   = help: the trait `for<'a> Fn<(&'a isize,)>` is not implemented for fn item `for<'a> extern "C" fn(&'a isize) -> isize {square}`
 note: required by a bound in `call_it`
   --> $DIR/unboxed-closures-wrong-abi.rs:9:15
    |
 LL | fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize {
    |               ^^^^^^^^^^^^^^^^^^^ required by this bound in `call_it`
 
-error[E0277]: expected a `FnMut<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
+error[E0277]: expected a `FnMut<(&isize,)>` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}`
   --> $DIR/unboxed-closures-wrong-abi.rs:25:25
    |
 LL |     let y = call_it_mut(&mut square, 22);
-   |             ----------- ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
+   |             ----------- ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}`
    |             |
    |             required by a bound introduced by this call
    |
-   = help: the trait `for<'r> FnMut<(&'r isize,)>` is not implemented for fn item `for<'r> extern "C" fn(&'r isize) -> isize {square}`
+   = help: the trait `for<'a> FnMut<(&'a isize,)>` is not implemented for fn item `for<'a> extern "C" fn(&'a isize) -> isize {square}`
 note: required by a bound in `call_it_mut`
   --> $DIR/unboxed-closures-wrong-abi.rs:12:19
    |
 LL | fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize {
    |                   ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `call_it_mut`
 
-error[E0277]: expected a `FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
+error[E0277]: expected a `FnOnce<(&isize,)>` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}`
   --> $DIR/unboxed-closures-wrong-abi.rs:30:26
    |
 LL |     let z = call_it_once(square, 22);
-   |             ------------ ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
+   |             ------------ ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}`
    |             |
    |             required by a bound introduced by this call
    |
-   = help: the trait `for<'r> FnOnce<(&'r isize,)>` is not implemented for fn item `for<'r> extern "C" fn(&'r isize) -> isize {square}`
+   = help: the trait `for<'a> FnOnce<(&'a isize,)>` is not implemented for fn item `for<'a> extern "C" fn(&'a isize) -> isize {square}`
 note: required by a bound in `call_it_once`
   --> $DIR/unboxed-closures-wrong-abi.rs:15:20
    |
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr
index 2fedb5b92c2..31a66790ce0 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr
@@ -6,7 +6,7 @@ LL |     let x = call_it(&square, 22);
    |             |
    |             required by a bound introduced by this call
    |
-   = help: the trait `for<'r> Fn<(&'r isize,)>` is not implemented for fn item `unsafe fn(isize) -> isize {square}`
+   = help: the trait `for<'a> Fn<(&'a isize,)>` is not implemented for fn item `unsafe fn(isize) -> isize {square}`
    = note: unsafe function cannot be called generically without an unsafe block
 note: required by a bound in `call_it`
   --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:10:15
@@ -22,7 +22,7 @@ LL |     let y = call_it_mut(&mut square, 22);
    |             |
    |             required by a bound introduced by this call
    |
-   = help: the trait `for<'r> FnMut<(&'r isize,)>` is not implemented for fn item `unsafe fn(isize) -> isize {square}`
+   = help: the trait `for<'a> FnMut<(&'a isize,)>` is not implemented for fn item `unsafe fn(isize) -> isize {square}`
    = note: unsafe function cannot be called generically without an unsafe block
 note: required by a bound in `call_it_mut`
   --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:13:19
@@ -38,7 +38,7 @@ LL |     let z = call_it_once(square, 22);
    |             |
    |             required by a bound introduced by this call
    |
-   = help: the trait `for<'r> FnOnce<(&'r isize,)>` is not implemented for fn item `unsafe fn(isize) -> isize {square}`
+   = help: the trait `for<'a> FnOnce<(&'a isize,)>` is not implemented for fn item `unsafe fn(isize) -> isize {square}`
    = note: unsafe function cannot be called generically without an unsafe block
 note: required by a bound in `call_it_once`
   --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:16:20
diff --git a/src/test/ui/uninhabited/privately-uninhabited-mir-call.stderr b/src/test/ui/uninhabited/privately-uninhabited-mir-call.stderr
index 95c209f47c9..0dfd22a30ac 100644
--- a/src/test/ui/uninhabited/privately-uninhabited-mir-call.stderr
+++ b/src/test/ui/uninhabited/privately-uninhabited-mir-call.stderr
@@ -6,6 +6,11 @@ LL |     let y: &mut u32;
 ...
 LL |     *y = 2;
    |     ^^^^^^ `y` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let y: &mut u32 = todo!();
+   |                     +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/union/union-copy.stderr b/src/test/ui/union/union-copy.stderr
index 8ecdafdde20..53ee4dd2e5b 100644
--- a/src/test/ui/union/union-copy.stderr
+++ b/src/test/ui/union/union-copy.stderr
@@ -1,11 +1,11 @@
 error[E0204]: the trait `Copy` may not be implemented for this type
-  --> $DIR/union-copy.rs:12:6
+  --> $DIR/union-copy.rs:12:15
    |
 LL |     a: std::mem::ManuallyDrop<String>
    |     --------------------------------- this field does not implement `Copy`
 ...
 LL | impl Copy for W {}
-   |      ^^^^
+   |               ^
    |
 note: the `Copy` impl for `ManuallyDrop<String>` requires that `String: Copy`
   --> $DIR/union-copy.rs:8:8
diff --git a/src/test/ui/where-clauses/higher-ranked-fn-type.quiet.stderr b/src/test/ui/where-clauses/higher-ranked-fn-type.quiet.stderr
new file mode 100644
index 00000000000..d9950a3d9b7
--- /dev/null
+++ b/src/test/ui/where-clauses/higher-ranked-fn-type.quiet.stderr
@@ -0,0 +1,18 @@
+error[E0277]: the trait bound `for<'b> for<'b> fn(&'b ()): Foo` is not satisfied
+  --> $DIR/higher-ranked-fn-type.rs:20:5
+   |
+LL |     called()
+   |     ^^^^^^ the trait `for<'b> Foo` is not implemented for `for<'b> fn(&'b ())`
+   |
+note: required by a bound in `called`
+  --> $DIR/higher-ranked-fn-type.rs:12:25
+   |
+LL | fn called()
+   |    ------ required by a bound in this
+LL | where
+LL |     for<'b> fn(&'b ()): Foo,
+   |                         ^^^ required by this bound in `called`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/where-clauses/higher-ranked-fn-type.rs b/src/test/ui/where-clauses/higher-ranked-fn-type.rs
new file mode 100644
index 00000000000..0d8893e08d3
--- /dev/null
+++ b/src/test/ui/where-clauses/higher-ranked-fn-type.rs
@@ -0,0 +1,25 @@
+// revisions: quiet verbose
+// [verbose]compile-flags: -Zverbose
+
+#![allow(unused_parens)]
+
+trait Foo {
+    type Assoc;
+}
+
+fn called()
+where
+    for<'b> fn(&'b ()): Foo,
+{
+}
+
+fn caller()
+where
+    (for<'a> fn(&'a ())): Foo,
+{
+    called()
+    //[quiet]~^ ERROR the trait bound `for<'b> for<'b> fn(&'b ()): Foo` is not satisfied
+    //[verbose]~^^ ERROR the trait bound `for<'b> fn(&ReLateBound(
+}
+
+fn main() {}
diff --git a/src/test/ui/where-clauses/higher-ranked-fn-type.verbose.stderr b/src/test/ui/where-clauses/higher-ranked-fn-type.verbose.stderr
new file mode 100644
index 00000000000..24660ec3539
--- /dev/null
+++ b/src/test/ui/where-clauses/higher-ranked-fn-type.verbose.stderr
@@ -0,0 +1,18 @@
+error[E0277]: the trait bound `for<'b> fn(&ReLateBound(DebruijnIndex(1), BoundRegion { var: 0, kind: BrNamed(DefId(0:6 ~ higher_ranked_fn_type[1209]::called::'b), 'b) }) ()): Foo` is not satisfied
+  --> $DIR/higher-ranked-fn-type.rs:20:5
+   |
+LL |     called()
+   |     ^^^^^^ the trait `for<'b> Foo` is not implemented for `fn(&ReLateBound(DebruijnIndex(1), BoundRegion { var: 0, kind: BrNamed(DefId(0:6 ~ higher_ranked_fn_type[1209]::called::'b), 'b) }) ())`
+   |
+note: required by a bound in `called`
+  --> $DIR/higher-ranked-fn-type.rs:12:25
+   |
+LL | fn called()
+   |    ------ required by a bound in this
+LL | where
+LL |     for<'b> fn(&'b ()): Foo,
+   |                         ^^^ required by this bound in `called`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 73ba3f35e0205844418260722c11602113179c4
+Subproject f5fed93ba24607980647962c59863bbabb03ce1
diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs
index 54c7456a2a3..80bb83af43b 100644
--- a/src/tools/clippy/clippy_dev/src/lib.rs
+++ b/src/tools/clippy/clippy_dev/src/lib.rs
@@ -1,5 +1,4 @@
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(once_cell)]
 #![feature(rustc_private)]
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
diff --git a/src/tools/clippy/clippy_lints/src/default_union_representation.rs b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
index d559ad423df..3905a6c2e21 100644
--- a/src/tools/clippy/clippy_lints/src/default_union_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
@@ -4,7 +4,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::sym;
-use rustc_typeck::hir_ty_to_ty;
+use rustc_hir_analysis::hir_ty_to_ty;
 
 declare_clippy_lint! {
     /// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 501f9ef78ae..e54d71fc8e4 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -704,7 +704,7 @@ fn walk_parents<'tcx>(
                 span,
                 ..
             }) if span.ctxt() == ctxt => {
-                let ty = cx.tcx.type_of(def_id);
+                let ty = cx.tcx.type_of(def_id.def_id);
                 Some(ty_auto_deref_stability(cx, ty, precedence).position_for_result(cx))
             },
 
diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs
index eb158d850fa..f48ba526d51 100644
--- a/src/tools/clippy/clippy_lints/src/doc.rs
+++ b/src/tools/clippy/clippy_lints/src/doc.rs
@@ -233,11 +233,11 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
                     let body = cx.tcx.hir().body(body_id);
                     let mut fpu = FindPanicUnwrap {
                         cx,
-                        typeck_results: cx.tcx.typeck(item.def_id),
+                        typeck_results: cx.tcx.typeck(item.def_id.def_id),
                         panic_span: None,
                     };
                     fpu.visit_expr(body.value);
-                    lint_for_missing_headers(cx, item.def_id, item.span, sig, headers, Some(body_id), fpu.panic_span);
+                    lint_for_missing_headers(cx, item.def_id.def_id, item.span, sig, headers, Some(body_id), fpu.panic_span);
                 }
             },
             hir::ItemKind::Impl(impl_) => {
@@ -268,7 +268,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
         let headers = check_attrs(cx, &self.valid_idents, attrs);
         if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind {
             if !in_external_macro(cx.tcx.sess, item.span) {
-                lint_for_missing_headers(cx, item.def_id, item.span, sig, headers, None, None);
+                lint_for_missing_headers(cx, item.def_id.def_id, item.span, sig, headers, None, None);
             }
         }
     }
@@ -283,11 +283,11 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
             let body = cx.tcx.hir().body(body_id);
             let mut fpu = FindPanicUnwrap {
                 cx,
-                typeck_results: cx.tcx.typeck(item.def_id),
+                typeck_results: cx.tcx.typeck(item.def_id.def_id),
                 panic_span: None,
             };
             fpu.visit_expr(body.value);
-            lint_for_missing_headers(cx, item.def_id, item.span, sig, headers, Some(body_id), fpu.panic_span);
+            lint_for_missing_headers(cx, item.def_id.def_id, item.span, sig, headers, Some(body_id), fpu.panic_span);
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/enum_variants.rs b/src/tools/clippy/clippy_lints/src/enum_variants.rs
index cd36f9fcd72..c39a909b3cc 100644
--- a/src/tools/clippy/clippy_lints/src/enum_variants.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_variants.rs
@@ -297,7 +297,7 @@ impl LateLintPass<'_> for EnumVariantNames {
             }
         }
         if let ItemKind::Enum(ref def, _) = item.kind {
-            if !(self.avoid_breaking_exported_api && cx.access_levels.is_exported(item.def_id)) {
+            if !(self.avoid_breaking_exported_api && cx.access_levels.is_exported(item.def_id.def_id)) {
                 check_variant(cx, self.threshold, def, item_name, item.span);
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index 327865e4c85..8ccc969646e 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -10,7 +10,7 @@ use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
 use rustc_span::symbol::kw;
 use rustc_target::spec::abi::Abi;
-use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
+use rustc_hir_analysis::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 
 #[derive(Copy, Clone)]
 pub struct BoxedLocal {
@@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
             }
         }
 
-        let parent_id = cx.tcx.hir().get_parent_item(hir_id);
+        let parent_id = cx.tcx.hir().get_parent_item(hir_id).def_id;
         let parent_node = cx.tcx.hir().find_by_def_id(parent_id);
 
         let mut trait_self_ty = None;
@@ -177,7 +177,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
         }
     }
 
-    fn fake_read(&mut self, _: &rustc_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
+    fn fake_read(&mut self, _: &rustc_hir_analysis::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
 }
 
 impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> {
diff --git a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
index 173d41b4b05..f3d9ebc5f12 100644
--- a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
+++ b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
@@ -73,7 +73,7 @@ impl LateLintPass<'_> for ExhaustiveItems {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
         if_chain! {
             if let ItemKind::Enum(..) | ItemKind::Struct(..) = item.kind;
-            if cx.access_levels.is_exported(item.def_id);
+            if cx.access_levels.is_exported(item.def_id.def_id);
             let attrs = cx.tcx.hir().attrs(item.hir_id());
             if !attrs.iter().any(|a| a.has_name(sym::non_exhaustive));
             then {
diff --git a/src/tools/clippy/clippy_lints/src/exit.rs b/src/tools/clippy/clippy_lints/src/exit.rs
index cbf52d19334..407dd1b3957 100644
--- a/src/tools/clippy/clippy_lints/src/exit.rs
+++ b/src/tools/clippy/clippy_lints/src/exit.rs
@@ -33,7 +33,7 @@ impl<'tcx> LateLintPass<'tcx> for Exit {
             if let ExprKind::Path(ref path) = path_expr.kind;
             if let Some(def_id) = cx.qpath_res(path, path_expr.hir_id).opt_def_id();
             if match_def_path(cx, def_id, &paths::EXIT);
-            let parent = cx.tcx.hir().get_parent_item(e.hir_id);
+            let parent = cx.tcx.hir().get_parent_item(e.hir_id).def_id;
             if let Some(Node::Item(Item{kind: ItemKind::Fn(..), ..})) = cx.tcx.hir().find_by_def_id(parent);
             // If the next item up is a function we check if it is an entry point
             // and only then emit a linter warning
diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
index 1f69f34a229..ef24a5d06ad 100644
--- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
+++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
@@ -107,7 +107,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h
                 let body = cx.tcx.hir().body(body_id);
                 let mut fpu = FindPanicUnwrap {
                     lcx: cx,
-                    typeck_results: cx.tcx.typeck(impl_item.id.def_id),
+                    typeck_results: cx.tcx.typeck(impl_item.id.def_id.def_id),
                     result: Vec::new(),
                 };
                 fpu.visit_expr(body.value);
diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
index 00a4937763e..d6d33bda173 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -21,7 +21,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>
     let attrs = cx.tcx.hir().attrs(item.hir_id());
     let attr = cx.tcx.get_attr(item.def_id.to_def_id(), sym::must_use);
     if let hir::ItemKind::Fn(ref sig, _generics, ref body_id) = item.kind {
-        let is_public = cx.access_levels.is_exported(item.def_id);
+        let is_public = cx.access_levels.is_exported(item.def_id.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
         if let Some(attr) = attr {
             check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
@@ -31,7 +31,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>
                 sig.decl,
                 cx.tcx.hir().body(*body_id),
                 item.span,
-                item.def_id,
+                item.def_id.def_id,
                 item.span.with_hi(sig.decl.output.span().hi()),
                 "this function could have a `#[must_use]` attribute",
             );
@@ -41,19 +41,19 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>
 
 pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
     if let hir::ImplItemKind::Fn(ref sig, ref body_id) = item.kind {
-        let is_public = cx.access_levels.is_exported(item.def_id);
+        let is_public = cx.access_levels.is_exported(item.def_id.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
         let attrs = cx.tcx.hir().attrs(item.hir_id());
         let attr = cx.tcx.get_attr(item.def_id.to_def_id(), sym::must_use);
         if let Some(attr) = attr {
             check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
-        } else if is_public && !is_proc_macro(cx.sess(), attrs) && trait_ref_of_method(cx, item.def_id).is_none() {
+        } else if is_public && !is_proc_macro(cx.sess(), attrs) && trait_ref_of_method(cx, item.def_id.def_id).is_none() {
             check_must_use_candidate(
                 cx,
                 sig.decl,
                 cx.tcx.hir().body(*body_id),
                 item.span,
-                item.def_id,
+                item.def_id.def_id,
                 item.span.with_hi(sig.decl.output.span().hi()),
                 "this method could have a `#[must_use]` attribute",
             );
@@ -63,7 +63,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
 
 pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
     if let hir::TraitItemKind::Fn(ref sig, ref eid) = item.kind {
-        let is_public = cx.access_levels.is_exported(item.def_id);
+        let is_public = cx.access_levels.is_exported(item.def_id.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
 
         let attrs = cx.tcx.hir().attrs(item.hir_id());
@@ -78,7 +78,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
                     sig.decl,
                     body,
                     item.span,
-                    item.def_id,
+                    item.def_id.def_id,
                     item.span.with_hi(sig.decl.output.span().hi()),
                     "this method could have a `#[must_use]` attribute",
                 );
@@ -171,7 +171,7 @@ fn is_mutable_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, tys: &mut DefIdSet)
         return false; // ignore `_` patterns
     }
     if cx.tcx.has_typeck_results(pat.hir_id.owner.to_def_id()) {
-        is_mutable_ty(cx, cx.tcx.typeck(pat.hir_id.owner).pat_ty(pat), pat.span, tys)
+        is_mutable_ty(cx, cx.tcx.typeck(pat.hir_id.owner.def_id).pat_ty(pat), pat.span, tys)
     } else {
         false
     }
@@ -218,7 +218,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> {
                     if self.cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id())
                         && is_mutable_ty(
                             self.cx,
-                            self.cx.tcx.typeck(arg.hir_id.owner).expr_ty(arg),
+                            self.cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg),
                             arg.span,
                             &mut tys,
                         )
@@ -236,7 +236,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> {
                     if self.cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id())
                         && is_mutable_ty(
                             self.cx,
-                            self.cx.tcx.typeck(arg.hir_id.owner).expr_ty(arg),
+                            self.cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg),
                             arg.span,
                             &mut tys,
                         )
diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
index 3bbfa52e810..0b50431fbaa 100644
--- a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
@@ -28,7 +28,7 @@ pub(super) fn check_fn<'tcx>(
 pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
     if let hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(eid)) = item.kind {
         let body = cx.tcx.hir().body(eid);
-        check_raw_ptr(cx, sig.header.unsafety, sig.decl, body, item.def_id);
+        check_raw_ptr(cx, sig.header.unsafety, sig.decl, body, item.def_id.def_id);
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs
index 9591405cb06..113c4e9f509 100644
--- a/src/tools/clippy/clippy_lints/src/functions/result.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/result.rs
@@ -34,9 +34,9 @@ fn result_err_ty<'tcx>(
 
 pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, large_err_threshold: u64) {
     if let hir::ItemKind::Fn(ref sig, _generics, _) = item.kind
-        && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id, item.span)
+        && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id.def_id, item.span)
     {
-        if cx.access_levels.is_exported(item.def_id) {
+        if cx.access_levels.is_exported(item.def_id.def_id) {
             let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
             check_result_unit_err(cx, err_ty, fn_header_span);
         }
@@ -47,10 +47,10 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, l
 pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::ImplItem<'tcx>, large_err_threshold: u64) {
     // Don't lint if method is a trait's implementation, we can't do anything about those
     if let hir::ImplItemKind::Fn(ref sig, _) = item.kind
-        && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id, item.span)
-        && trait_ref_of_method(cx, item.def_id).is_none()
+        && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id.def_id, item.span)
+        && trait_ref_of_method(cx, item.def_id.def_id).is_none()
     {
-        if cx.access_levels.is_exported(item.def_id) {
+        if cx.access_levels.is_exported(item.def_id.def_id) {
             let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
             check_result_unit_err(cx, err_ty, fn_header_span);
         }
@@ -61,8 +61,8 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::ImplItem
 pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::TraitItem<'tcx>, large_err_threshold: u64) {
     if let hir::TraitItemKind::Fn(ref sig, _) = item.kind {
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
-        if let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id, item.span) {
-            if cx.access_levels.is_exported(item.def_id) {
+        if let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id.def_id, item.span) {
+            if cx.access_levels.is_exported(item.def_id.def_id) {
                 check_result_unit_err(cx, err_ty, fn_header_span);
             }
             check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold);
diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
index 4f9680f60fe..a920c3bba2a 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
@@ -12,7 +12,7 @@ use rustc_middle::ty::{Ty, TypeckResults};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 use rustc_span::symbol::sym;
-use rustc_typeck::hir_ty_to_ty;
+use rustc_hir_analysis::hir_ty_to_ty;
 
 use if_chain::if_chain;
 
@@ -112,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
             }
         }
 
-        if !cx.access_levels.is_exported(item.def_id) {
+        if !cx.access_levels.is_exported(item.def_id.def_id) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
index 17d867aacb5..cb6c2ec0fb9 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
@@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
             if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::String);
 
             // Filters instances of to_string which are required by a trait
-            if trait_ref_of_method(cx, impl_item.def_id).is_none();
+            if trait_ref_of_method(cx, impl_item.def_id.def_id).is_none();
 
             then {
                 show_lint(cx, impl_item);
diff --git a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
index b56d87c5348..2027c23d328 100644
--- a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
@@ -44,7 +44,7 @@ impl<'tcx> LateLintPass<'tcx> for IterNotReturningIterator {
         let name = item.ident.name.as_str();
         if matches!(name, "iter" | "iter_mut") {
             if let TraitItemKind::Fn(fn_sig, _) = &item.kind {
-                check_sig(cx, name, fn_sig, item.def_id);
+                check_sig(cx, name, fn_sig, item.def_id.def_id);
             }
         }
     }
@@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for IterNotReturningIterator {
             )
         {
             if let ImplItemKind::Fn(fn_sig, _) = &item.kind {
-                check_sig(cx, name, fn_sig, item.def_id);
+                check_sig(cx, name, fn_sig, item.def_id.def_id);
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
index 984c5cd4e37..d6eb53ae29b 100644
--- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
+++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
@@ -7,7 +7,7 @@ use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::{self, ConstKind};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{BytePos, Pos, Span};
-use rustc_typeck::hir_ty_to_ty;
+use rustc_hir_analysis::hir_ty_to_ty;
 
 declare_clippy_lint! {
     /// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 7ae8ef830fa..7d15dd4cb21 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -134,7 +134,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
             if item.ident.name == sym::len;
             if let ImplItemKind::Fn(sig, _) = &item.kind;
             if sig.decl.implicit_self.has_implicit_self();
-            if cx.access_levels.is_exported(item.def_id);
+            if cx.access_levels.is_exported(item.def_id.def_id);
             if matches!(sig.decl.output, FnRetTy::Return(_));
             if let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id());
             if imp.of_trait.is_none();
@@ -210,7 +210,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items
         }
     }
 
-    if cx.access_levels.is_exported(visited_trait.def_id) && trait_items.iter().any(|i| is_named_self(cx, i, sym::len))
+    if cx.access_levels.is_exported(visited_trait.def_id.def_id) && trait_items.iter().any(|i| is_named_self(cx, i, sym::len))
     {
         let mut current_and_super_traits = DefIdSet::default();
         fill_trait_set(visited_trait.def_id.to_def_id(), &mut current_and_super_traits, cx);
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 298566cb5b6..c3db194c4ad 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -5,7 +5,6 @@
 #![feature(drain_filter)]
 #![feature(iter_intersperse)]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(lint_reasons)]
 #![feature(never_type)]
 #![feature(once_cell)]
@@ -44,7 +43,7 @@ extern crate rustc_session;
 extern crate rustc_span;
 extern crate rustc_target;
 extern crate rustc_trait_selection;
-extern crate rustc_typeck;
+extern crate rustc_hir_analysis;
 
 #[macro_use]
 extern crate clippy_utils;
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 643a7cfd577..399a03187d9 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -102,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
         if let ImplItemKind::Fn(ref sig, id) = item.kind {
-            let report_extra_lifetimes = trait_ref_of_method(cx, item.def_id).is_none();
+            let report_extra_lifetimes = trait_ref_of_method(cx, item.def_id.def_id).is_none();
             check_fn_inner(
                 cx,
                 sig.decl,
@@ -276,7 +276,7 @@ fn could_use_elision<'tcx>(
         let mut checker = BodyLifetimeChecker {
             lifetimes_used_in_body: false,
         };
-        checker.visit_expr(body.value);
+        checker.visit_expr(&body.value);
         if checker.lifetimes_used_in_body {
             return false;
         }
diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
index fce2d54639c..6d585c2e45d 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
@@ -8,7 +8,7 @@ use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
 use rustc_middle::{mir::FakeReadCause, ty};
 use rustc_span::source_map::Span;
-use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
+use rustc_hir_analysis::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 
 pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'_>) {
     if_chain! {
@@ -69,7 +69,7 @@ fn check_for_mutation<'tcx>(
         ExprUseVisitor::new(
             &mut delegate,
             &infcx,
-            body.hir_id.owner,
+            body.hir_id.owner.def_id,
             cx.param_env,
             cx.typeck_results(),
         )
@@ -114,7 +114,7 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> {
         }
     }
 
-    fn fake_read(&mut self, _: &rustc_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
+    fn fake_read(&mut self, _: &rustc_hir_analysis::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
 }
 
 impl MutatePairDelegate<'_, '_> {
diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs
index 4801a84eb92..f1f58db80b3 100644
--- a/src/tools/clippy/clippy_lints/src/loops/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs
@@ -10,7 +10,7 @@ use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{sym, Symbol};
-use rustc_typeck::hir_ty_to_ty;
+use rustc_hir_analysis::hir_ty_to_ty;
 use std::iter::Iterator;
 
 #[derive(Debug, PartialEq, Eq)]
diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
index 2b04475c7a9..53e7565bd33 100644
--- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
@@ -166,7 +166,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
             if let Some((id, span)) = iter.next()
                 && iter.next().is_none()
             {
-                self.potential_enums.push((item.def_id, id, item.span, span));
+                self.potential_enums.push((item.def_id.def_id, id, item.span, span));
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
index 634eef82e53..58ea43e69d9 100644
--- a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
@@ -11,7 +11,7 @@ use rustc_hir::LangItem::OptionNone;
 use rustc_hir::{Arm, BindingAnnotation, ByRef, Expr, ExprKind, FnRetTy, Guard, Node, Pat, PatKind, Path, QPath};
 use rustc_lint::LateContext;
 use rustc_span::sym;
-use rustc_typeck::hir_ty_to_ty;
+use rustc_hir_analysis::hir_ty_to_ty;
 
 pub(crate) fn check_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
     if arms.len() > 1 && expr_ty_matches_p_ty(cx, ex, expr) && check_all_arms(cx, ex, arms) {
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index cdde4c54d63..428a354ec6b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -115,7 +115,7 @@ use rustc_middle::ty::{self, TraitRef, Ty};
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{sym, Span};
-use rustc_typeck::hir_ty_to_ty;
+use rustc_hir_analysis::hir_ty_to_ty;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -3250,7 +3250,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             return;
         }
         let name = impl_item.ident.name.as_str();
-        let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
+        let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
         let item = cx.tcx.hir().expect_item(parent);
         let self_ty = cx.tcx.type_of(item.def_id);
 
@@ -3259,7 +3259,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind;
             if let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next();
 
-            let method_sig = cx.tcx.fn_sig(impl_item.def_id);
+            let method_sig = cx.tcx.fn_sig(impl_item.def_id.def_id);
             let method_sig = cx.tcx.erase_late_bound_regions(method_sig);
 
             let first_arg_ty = method_sig.inputs().iter().next();
@@ -3269,7 +3269,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
 
             then {
                 // if this impl block implements a trait, lint in trait definition instead
-                if !implements_trait && cx.access_levels.is_exported(impl_item.def_id) {
+                if !implements_trait && cx.access_levels.is_exported(impl_item.def_id.def_id) {
                     // check missing trait implementations
                     for method_config in &TRAIT_METHODS {
                         if name == method_config.method_name &&
@@ -3301,7 +3301,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
 
                 if sig.decl.implicit_self.has_implicit_self()
                     && !(self.avoid_breaking_exported_api
-                        && cx.access_levels.is_exported(impl_item.def_id))
+                        && cx.access_levels.is_exported(impl_item.def_id.def_id))
                 {
                     wrong_self_convention::check(
                         cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index 79d784c342c..559f32a563e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -18,7 +18,7 @@ use rustc_middle::ty::{self, ParamTy, PredicateKind, ProjectionPredicate, TraitP
 use rustc_semver::RustcVersion;
 use rustc_span::{sym, Symbol};
 use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause};
-use rustc_typeck::check::{FnCtxt, Inherited};
+use rustc_hir_analysis::check::{FnCtxt, Inherited};
 use std::cmp::max;
 
 use super::UNNECESSARY_TO_OWNED;
diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
index bc304c081b9..00376f0d790 100644
--- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
@@ -13,7 +13,7 @@ use rustc_middle::lint::in_external_macro;
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::Span;
-use rustc_typeck::hir_ty_to_ty;
+use rustc_hir_analysis::hir_ty_to_ty;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -136,7 +136,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
 
         // Const fns are not allowed as methods in a trait.
         {
-            let parent = cx.tcx.hir().get_parent_item(hir_id);
+            let parent = cx.tcx.hir().get_parent_item(hir_id).def_id;
             if parent != CRATE_DEF_ID {
                 if let hir::Node::Item(item) = cx.tcx.hir().get_by_def_id(parent) {
                     if let hir::ItemKind::Trait(..) = &item.kind {
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index 3701fdb4adb..47219556676 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -131,7 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
             hir::ItemKind::Fn(..) => {
                 // ignore main()
                 if it.ident.name == sym::main {
-                    let at_root = cx.tcx.local_parent(it.def_id) == CRATE_DEF_ID;
+                    let at_root = cx.tcx.local_parent(it.def_id.def_id) == CRATE_DEF_ID;
                     if at_root {
                         return;
                     }
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index 07bc2ca5d3c..9d5764ac092 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -88,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
             return;
         }
 
-        if !cx.access_levels.is_exported(it.def_id) {
+        if !cx.access_levels.is_exported(it.def_id.def_id) {
             return;
         }
         match it.kind {
@@ -142,7 +142,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
         }
 
         // If the item being implemented is not exported, then we don't need #[inline]
-        if !cx.access_levels.is_exported(impl_item.def_id) {
+        if !cx.access_levels.is_exported(impl_item.def_id.def_id) {
             return;
         }
 
@@ -159,7 +159,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
         };
 
         if let Some(trait_def_id) = trait_def_id {
-            if trait_def_id.is_local() && !cx.access_levels.is_exported(impl_item.def_id) {
+            if trait_def_id.is_local() && !cx.access_levels.is_exported(impl_item.def_id.def_id) {
                 // If a trait is being implemented for an item, and the
                 // trait is not exported, we don't need #[inline]
                 return;
diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs
index 4db103bbc13..25d6ca83a94 100644
--- a/src/tools/clippy/clippy_lints/src/mut_key.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_key.rs
@@ -89,7 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType {
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'tcx>) {
         if let hir::ImplItemKind::Fn(ref sig, ..) = item.kind {
-            if trait_ref_of_method(cx, item.def_id).is_none() {
+            if trait_ref_of_method(cx, item.def_id.def_id).is_none() {
                 check_sig(cx, item.hir_id(), sig.decl);
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 060037ed496..4f46872439c 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -22,7 +22,7 @@ use rustc_span::{sym, Span};
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::misc::can_type_implement_copy;
-use rustc_typeck::expr_use_visitor as euv;
+use rustc_hir_analysis::expr_use_visitor as euv;
 use std::borrow::Cow;
 
 declare_clippy_lint! {
@@ -341,5 +341,5 @@ impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt {
 
     fn mutate(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {}
 
-    fn fake_read(&mut self, _: &rustc_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
+    fn fake_read(&mut self, _: &rustc_hir_analysis::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
 }
diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs
index 5c45ee6d94a..357a71693d2 100644
--- a/src/tools/clippy/clippy_lints/src/new_without_default.rs
+++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs
@@ -84,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
                             // can't be implemented for unsafe new
                             return;
                         }
-                        if cx.tcx.is_doc_hidden(impl_item.def_id) {
+                        if cx.tcx.is_doc_hidden(impl_item.def_id.def_id) {
                             // shouldn't be implemented when it is hidden in docs
                             return;
                         }
@@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
                         if_chain! {
                             if sig.decl.inputs.is_empty();
                             if name == sym::new;
-                            if cx.access_levels.is_reachable(impl_item.def_id);
+                            if cx.access_levels.is_reachable(impl_item.def_id.def_id);
                             let self_def_id = cx.tcx.hir().get_parent_item(id);
                             let self_ty = cx.tcx.type_of(self_def_id);
                             if self_ty == return_ty(cx, id);
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index b1588452732..48ff737dae7 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -20,7 +20,7 @@ use rustc_middle::ty::adjustment::Adjust;
 use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{sym, InnerSpan, Span, DUMMY_SP};
-use rustc_typeck::hir_ty_to_ty;
+use rustc_hir_analysis::hir_ty_to_ty;
 
 // FIXME: this is a correctness problem but there's no suitable
 // warn-by-default category.
@@ -286,7 +286,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
         if let ImplItemKind::Const(hir_ty, body_id) = &impl_item.kind {
-            let item_def_id = cx.tcx.hir().get_parent_item(impl_item.hir_id());
+            let item_def_id = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
             let item = cx.tcx.hir().expect_item(item_def_id);
 
             match &item.kind {
diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
index 6217110a1f3..d64a9cf71e1 100644
--- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
@@ -243,7 +243,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
                 ..
             })) => {
                 #[allow(trivial_casts)]
-                if let Some(Node::Item(item)) = get_parent_node(cx.tcx, cx.tcx.hir().local_def_id_to_hir_id(def_id))
+                if let Some(Node::Item(item)) = get_parent_node(cx.tcx, def_id.into())
                     && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.def_id)
                     && let Some(trait_item_id) = cx.tcx.associated_item(def_id).trait_item_def_id
                 {
diff --git a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
index 945a09a647c..f134c6c4cdb 100644
--- a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
@@ -11,7 +11,7 @@ use rustc_lint::LateContext;
 use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty::BorrowKind;
 use rustc_trait_selection::infer::TyCtxtInferExt;
-use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
+use rustc_hir_analysis::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 
 use super::ASSIGN_OP_PATTERN;
 
@@ -28,7 +28,7 @@ pub(super) fn check<'tcx>(
             if_chain! {
                 if let Some((_, lang_item)) = binop_traits(op.node);
                 if let Ok(trait_id) = cx.tcx.lang_items().require(lang_item);
-                let parent_fn = cx.tcx.hir().get_parent_item(e.hir_id);
+                let parent_fn = cx.tcx.hir().get_parent_item(e.hir_id).def_id;
                 if trait_ref_of_method(cx, parent_fn)
                     .map_or(true, |t| t.path.res.def_id() != trait_id);
                 if implements_trait(cx, ty, trait_id, &[rty.into()]);
diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
index 0960b050c24..6b2eea48932 100644
--- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
@@ -261,7 +261,7 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue {
         }
 
         if let hir::TraitItemKind::Fn(method_sig, _) = &item.kind {
-            self.check_poly_fn(cx, item.def_id, method_sig.decl, None);
+            self.check_poly_fn(cx, item.def_id.def_id, method_sig.decl, None);
         }
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
index 323326381d4..3c6ca9d9897 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
@@ -46,8 +46,8 @@ impl_lint_pass!(RedundantPubCrate => [REDUNDANT_PUB_CRATE]);
 impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
         if_chain! {
-            if cx.tcx.visibility(item.def_id) == ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id());
-            if !cx.access_levels.is_exported(item.def_id) && self.is_exported.last() == Some(&false);
+            if cx.tcx.visibility(item.def_id.def_id) == ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id());
+            if !cx.access_levels.is_exported(item.def_id.def_id) && self.is_exported.last() == Some(&false);
             if is_not_macro_export(item);
             then {
                 let span = item.span.with_hi(item.ident.span.hi());
@@ -70,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
         }
 
         if let ItemKind::Mod { .. } = item.kind {
-            self.is_exported.push(cx.access_levels.is_exported(item.def_id));
+            self.is_exported.push(cx.access_levels.is_exported(item.def_id.def_id));
         }
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
index 60be6bd335f..16d702a3868 100644
--- a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
@@ -128,7 +128,7 @@ impl<'tcx> LateLintPass<'tcx> for ReturnSelfNotMustUse {
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'tcx>) {
         if let TraitItemKind::Fn(ref sig, _) = item.kind {
-            check_method(cx, sig.decl, item.def_id, item.span, item.hir_id());
+            check_method(cx, sig.decl, item.def_id.def_id, item.span, item.hir_id());
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/self_named_constructors.rs b/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
index 9cea4d88067..1ac538f4c7c 100644
--- a/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
+++ b/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
@@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors {
             _ => return,
         }
 
-        let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
+        let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
         let item = cx.tcx.hir().expect_item(parent);
         let self_ty = cx.tcx.type_of(item.def_id);
         let ret_ty = return_ty(cx, impl_item.hir_id());
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
index 6add20c1fb7..d47ed459387 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
@@ -64,11 +64,11 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl {
 
             // Check for more than one binary operation in the implemented function
             // Linting when multiple operations are involved can result in false positives
-            let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id);
+            let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id).def_id;
             if let hir::Node::ImplItem(impl_item) = cx.tcx.hir().get_by_def_id(parent_fn);
             if let hir::ImplItemKind::Fn(_, body_id) = impl_item.kind;
             let body = cx.tcx.hir().body(body_id);
-            let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id);
+            let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id).def_id;
             if let Some(trait_ref) = trait_ref_of_method(cx, parent_fn);
             let trait_id = trait_ref.path.res.def_id();
             if ![binop_trait_id, op_assign_trait_id].contains(&trait_id);
diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
index a25be93b8d6..2be22884027 100644
--- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
@@ -128,7 +128,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
                 if !bound_predicate.span.from_expansion();
                 if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind;
                 if let Some(PathSegment {
-                    res: Res::SelfTy{ trait_: Some(def_id), alias_to: _ }, ..
+                    res: Res::SelfTyParam { trait_: def_id }, ..
                 }) = segments.first();
                 if let Some(
                     Node::Item(
diff --git a/src/tools/clippy/clippy_lints/src/transmute/utils.rs b/src/tools/clippy/clippy_lints/src/transmute/utils.rs
index 8bdadf24402..fdf847bf445 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/utils.rs
@@ -2,7 +2,7 @@ use rustc_hir::Expr;
 use rustc_lint::LateContext;
 use rustc_middle::ty::{cast::CastKind, Ty};
 use rustc_span::DUMMY_SP;
-use rustc_typeck::check::{cast::{self, CastCheckResult}, FnCtxt, Inherited};
+use rustc_hir_analysis::check::{cast::{self, CastCheckResult}, FnCtxt, Inherited};
 
 // check if the component types of the transmuted collection and the result have different ABI,
 // size or alignment
@@ -42,7 +42,7 @@ pub(super) fn can_be_expressed_as_pointer_cast<'tcx>(
 /// messages. This function will panic if that occurs.
 fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> Option<CastKind> {
     let hir_id = e.hir_id;
-    let local_def_id = hir_id.owner;
+    let local_def_id = hir_id.owner.def_id;
 
     Inherited::build(cx.tcx, local_def_id).enter(|inherited| {
         let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, hir_id);
diff --git a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
index 94945b2e1a9..1268c23206a 100644
--- a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
+++ b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
@@ -104,7 +104,7 @@ fn get_bounds_if_impl_trait<'tcx>(cx: &LateContext<'tcx>, qpath: &QPath<'_>, id:
         if let Some(Node::GenericParam(generic_param)) = cx.tcx.hir().get_if_local(did);
         if let GenericParamKind::Type { synthetic, .. } = generic_param.kind;
         if synthetic;
-        if let Some(generics) = cx.tcx.hir().get_generics(id.owner);
+        if let Some(generics) = cx.tcx.hir().get_generics(id.owner.def_id);
         if let Some(pred) = generics.bounds_for_param(did.expect_local()).next();
         then {
             Some(pred.bounds)
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index 353a6f6b899..aca55817c52 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -313,7 +313,7 @@ impl_lint_pass!(Types => [BOX_COLLECTION, VEC_BOX, OPTION_OPTION, LINKEDLIST, BO
 impl<'tcx> LateLintPass<'tcx> for Types {
     fn check_fn(&mut self, cx: &LateContext<'_>, _: FnKind<'_>, decl: &FnDecl<'_>, _: &Body<'_>, _: Span, id: HirId) {
         let is_in_trait_impl =
-            if let Some(hir::Node::Item(item)) = cx.tcx.hir().find_by_def_id(cx.tcx.hir().get_parent_item(id)) {
+            if let Some(hir::Node::Item(item)) = cx.tcx.hir().find_by_def_id(cx.tcx.hir().get_parent_item(id).def_id) {
                 matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
             } else {
                 false
@@ -333,7 +333,7 @@ impl<'tcx> LateLintPass<'tcx> for Types {
     }
 
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        let is_exported = cx.access_levels.is_exported(item.def_id);
+        let is_exported = cx.access_levels.is_exported(item.def_id.def_id);
 
         match item.kind {
             ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _) => self.check_ty(
@@ -353,7 +353,7 @@ impl<'tcx> LateLintPass<'tcx> for Types {
         match item.kind {
             ImplItemKind::Const(ty, _) => {
                 let is_in_trait_impl = if let Some(hir::Node::Item(item)) =
-                    cx.tcx.hir().find_by_def_id(cx.tcx.hir().get_parent_item(item.hir_id()))
+                    cx.tcx.hir().find_by_def_id(cx.tcx.hir().get_parent_item(item.hir_id()).def_id)
                 {
                     matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
                 } else {
@@ -390,7 +390,7 @@ impl<'tcx> LateLintPass<'tcx> for Types {
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &TraitItem<'_>) {
-        let is_exported = cx.access_levels.is_exported(item.def_id);
+        let is_exported = cx.access_levels.is_exported(item.def_id.def_id);
 
         let context = CheckTyContext {
             is_exported,
diff --git a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
index a1312fcda0b..d81c5c83845 100644
--- a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
+++ b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
@@ -5,7 +5,7 @@ use rustc_errors::Applicability;
 use rustc_hir::{self as hir, def_id::DefId, QPath, TyKind};
 use rustc_lint::LateContext;
 use rustc_span::symbol::sym;
-use rustc_typeck::hir_ty_to_ty;
+use rustc_hir_analysis::hir_ty_to_ty;
 
 use super::{utils, REDUNDANT_ALLOCATION};
 
diff --git a/src/tools/clippy/clippy_lints/src/types/vec_box.rs b/src/tools/clippy/clippy_lints/src/types/vec_box.rs
index b2f536ca781..236f9955722 100644
--- a/src/tools/clippy/clippy_lints/src/types/vec_box.rs
+++ b/src/tools/clippy/clippy_lints/src/types/vec_box.rs
@@ -8,7 +8,7 @@ use rustc_lint::LateContext;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::TypeVisitable;
 use rustc_span::symbol::sym;
-use rustc_typeck::hir_ty_to_ty;
+use rustc_hir_analysis::hir_ty_to_ty;
 
 use super::VEC_BOX;
 
diff --git a/src/tools/clippy/clippy_lints/src/unused_self.rs b/src/tools/clippy/clippy_lints/src/unused_self.rs
index 51c65d898cf..713fe06bad4 100644
--- a/src/tools/clippy/clippy_lints/src/unused_self.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_self.rs
@@ -54,14 +54,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf {
         if impl_item.span.from_expansion() {
             return;
         }
-        let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
+        let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
         let parent_item = cx.tcx.hir().expect_item(parent);
         let assoc_item = cx.tcx.associated_item(impl_item.def_id);
         if_chain! {
             if let ItemKind::Impl(Impl { of_trait: None, .. }) = parent_item.kind;
             if assoc_item.fn_has_self_parameter;
             if let ImplItemKind::Fn(.., body_id) = &impl_item.kind;
-            if !cx.access_levels.is_exported(impl_item.def_id) || !self.avoid_breaking_exported_api;
+            if !cx.access_levels.is_exported(impl_item.def_id.def_id) || !self.avoid_breaking_exported_api;
             let body = cx.tcx.hir().body(*body_id);
             if let [self_param, ..] = body.params;
             if !is_local_used(cx, body, self_param.pat.hir_id);
diff --git a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
index 46020adcaa2..baa53ba664f 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
@@ -111,7 +111,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tc
         let body = cx.tcx.hir().body(body_id);
         let mut fpu = FindExpectUnwrap {
             lcx: cx,
-            typeck_results: cx.tcx.typeck(impl_item.def_id),
+            typeck_results: cx.tcx.typeck(impl_item.def_id.def_id),
             result: Vec::new(),
         };
         fpu.visit_expr(body.value);
diff --git a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
index 02bf09ed506..2c71f35d490 100644
--- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
+++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
@@ -105,7 +105,7 @@ impl LateLintPass<'_> for UpperCaseAcronyms {
     fn check_item(&mut self, cx: &LateContext<'_>, it: &Item<'_>) {
         // do not lint public items or in macros
         if in_external_macro(cx.sess(), it.span)
-            || (self.avoid_breaking_exported_api && cx.access_levels.is_exported(it.def_id))
+            || (self.avoid_breaking_exported_api && cx.access_levels.is_exported(it.def_id.def_id))
         {
             return;
         }
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index 44ab9bca795..2c4f5075e98 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -16,7 +16,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::Span;
-use rustc_typeck::hir_ty_to_ty;
+use rustc_hir_analysis::hir_ty_to_ty;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -106,7 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
             if !is_from_proc_macro(cx, item); // expensive, should be last check
             then {
                 StackItem::Check {
-                    impl_id: item.def_id,
+                    impl_id: item.def_id.def_id,
                     in_body: 0,
                     types_to_skip: std::iter::once(self_ty.hir_id).collect(),
                 }
@@ -206,7 +206,12 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
                 ref types_to_skip,
             }) = self.stack.last();
             if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind;
-            if !matches!(path.res, Res::SelfTy { .. } | Res::Def(DefKind::TyParam, _));
+            if !matches!(
+                path.res,
+                Res::SelfTyParam { .. }
+                | Res::SelfTyAlias { .. }
+                | Res::Def(DefKind::TyParam, _)
+            );
             if !types_to_skip.contains(&hir_ty.hir_id);
             let ty = if in_body > 0 {
                 cx.typeck_results().node_type(hir_ty.hir_id)
@@ -230,7 +235,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
         }
         match expr.kind {
             ExprKind::Struct(QPath::Resolved(_, path), ..) => match path.res {
-                Res::SelfTy { .. } => (),
+                Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => (),
                 Res::Def(DefKind::Variant, _) => lint_path_to_variant(cx, path),
                 _ => span_lint(cx, path.span),
             },
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 4003fff27c0..1df3135c962 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -140,7 +140,7 @@ impl<'tcx> LateLintPass<'tcx> for Author {
 
 fn check_item(cx: &LateContext<'_>, hir_id: HirId) {
     let hir = cx.tcx.hir();
-    if let Some(body_id) = hir.maybe_body_owned_by(hir_id.expect_owner()) {
+    if let Some(body_id) = hir.maybe_body_owned_by(hir_id.expect_owner().def_id) {
         check_node(cx, hir_id, |v| {
             v.expr(&v.bind("expr", hir.body(body_id).value));
         });
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
index 17d9a041857..78c036186f5 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
@@ -32,7 +32,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::Symbol;
 use rustc_span::{sym, BytePos, Span};
-use rustc_typeck::hir_ty_to_ty;
+use rustc_hir_analysis::hir_ty_to_ty;
 
 use std::borrow::{Borrow, Cow};
 
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
index 5418eca382d..2604b1ee7c5 100644
--- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
@@ -120,14 +120,14 @@ impl LateLintPass<'_> for WildcardImports {
         if is_test_module_or_function(cx.tcx, item) {
             self.test_modules_deep = self.test_modules_deep.saturating_add(1);
         }
-        let module = cx.tcx.parent_module_from_def_id(item.def_id);
-        if cx.tcx.visibility(item.def_id) != ty::Visibility::Restricted(module.to_def_id()) {
+        let module = cx.tcx.parent_module_from_def_id(item.def_id.def_id);
+        if cx.tcx.visibility(item.def_id.def_id) != ty::Visibility::Restricted(module.to_def_id()) {
             return;
         }
         if_chain! {
             if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind;
             if self.warn_on_all || !self.check_exceptions(item, use_path.segments);
-            let used_imports = cx.tcx.names_imported_by_glob_use(item.def_id);
+            let used_imports = cx.tcx.names_imported_by_glob_use(item.def_id.def_id);
             if !used_imports.is_empty(); // Already handled by `unused_imports`
             then {
                 let mut applicability = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
index 8dc43c0e294..703ba2ef4b0 100644
--- a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
@@ -7,7 +7,7 @@ use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_middle::ty::{Adt, Ty, TypeVisitable};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::sym;
-use rustc_typeck::hir_ty_to_ty;
+use rustc_hir_analysis::hir_ty_to_ty;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -72,7 +72,7 @@ fn in_trait_impl(cx: &LateContext<'_>, hir_id: HirId) -> bool {
     let second_parent_id = cx
         .tcx
         .hir()
-        .get_parent_item(cx.tcx.hir().local_def_id_to_hir_id(parent_id));
+        .get_parent_item(parent_id.into()).def_id;
     if let Some(Node::Item(item)) = cx.tcx.hir().find_by_def_id(second_parent_id) {
         if let ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = item.kind {
             return true;
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 62da850a15e..8f79c07c977 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -3,7 +3,6 @@
 #![feature(control_flow_enum)]
 #![feature(let_chains)]
 #![feature(lint_reasons)]
-#![cfg_attr(bootstrap, feature(let_else))]
 #![feature(once_cell)]
 #![feature(rustc_private)]
 #![recursion_limit = "512"]
@@ -33,7 +32,7 @@ extern crate rustc_session;
 extern crate rustc_span;
 extern crate rustc_target;
 extern crate rustc_trait_selection;
-extern crate rustc_typeck;
+extern crate rustc_hir_analysis;
 
 #[macro_use]
 pub mod sym_helper;
@@ -78,7 +77,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::unhash::UnhashMap;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_ID};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
 use rustc_hir::hir_id::{HirIdMap, HirIdSet};
 use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
 use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
@@ -212,7 +211,7 @@ pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<
 /// }
 /// ```
 pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool {
-    let parent_id = cx.tcx.hir().get_parent_item(id);
+    let parent_id = cx.tcx.hir().get_parent_item(id).def_id;
     match cx.tcx.hir().get_by_def_id(parent_id) {
         Node::Item(&Item {
             kind: ItemKind::Const(..) | ItemKind::Static(..),
@@ -597,8 +596,8 @@ pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, def_id: LocalDefId) ->
     let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
     let parent_impl = cx.tcx.hir().get_parent_item(hir_id);
     if_chain! {
-        if parent_impl != CRATE_DEF_ID;
-        if let hir::Node::Item(item) = cx.tcx.hir().get_by_def_id(parent_impl);
+        if parent_impl != hir::CRATE_OWNER_ID;
+        if let hir::Node::Item(item) = cx.tcx.hir().get_by_def_id(parent_impl.def_id);
         if let hir::ItemKind::Impl(impl_) = &item.kind;
         then {
             return impl_.of_trait.as_ref();
@@ -1104,7 +1103,7 @@ pub fn is_in_panic_handler(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 
 /// Gets the name of the item the expression is in, if available.
 pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
-    let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id);
+    let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id).def_id;
     match cx.tcx.hir().find_by_def_id(parent_id) {
         Some(
             Node::Item(Item { ident, .. })
@@ -1387,7 +1386,7 @@ pub fn is_integer_literal(expr: &Expr<'_>, value: u128) -> bool {
 /// Examples of coercions can be found in the Nomicon at
 /// <https://doc.rust-lang.org/nomicon/coercions.html>.
 ///
-/// See `rustc_middle::ty::adjustment::Adjustment` and `rustc_typeck::check::coercion` for more
+/// See `rustc_middle::ty::adjustment::Adjustment` and `rustc_hir_analysis::check::coercion` for more
 /// information on adjustments and coercions.
 pub fn is_adjusted(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
     cx.typeck_results().adjustments().get(e.hir_id).is_some()
@@ -1536,7 +1535,7 @@ pub fn is_self(slf: &Param<'_>) -> bool {
 
 pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool {
     if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind {
-        if let Res::SelfTy { .. } = path.res {
+        if let Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } = path.res {
             return true;
         }
     }
@@ -1648,7 +1647,7 @@ pub fn any_parent_has_attr(tcx: TyCtxt<'_>, node: HirId, symbol: Symbol) -> bool
             return true;
         }
         prev_enclosing_node = Some(enclosing_node);
-        enclosing_node = map.local_def_id_to_hir_id(map.get_parent_item(enclosing_node));
+        enclosing_node = map.get_parent_item(enclosing_node).into();
     }
 
     false
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 405f0228683..f7ce7191772 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -367,10 +367,21 @@ fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option<RustcVersion>) -> bo
                 // Checking MSRV is manually necessary because `rustc` has no such concept. This entire
                 // function could be removed if `rustc` provided a MSRV-aware version of `is_const_fn`.
                 // as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262.
+
+                // HACK(nilstrieb): CURRENT_RUSTC_VERSION can return versions like 1.66.0-dev. `rustc-semver` doesn't accept
+                //                  the `-dev` version number so we have to strip it off.
+                let short_version = since
+                    .as_str()
+                    .split('-')
+                    .next()
+                    .expect("rustc_attr::StabilityLevel::Stable::since` is empty");
+
+                let since = rustc_span::Symbol::intern(short_version);
+
                 crate::meets_msrv(
                     msrv,
                     RustcVersion::parse(since.as_str())
-                        .expect("`rustc_attr::StabilityLevel::Stable::since` is ill-formatted"),
+                        .unwrap_or_else(|err| panic!("`rustc_attr::StabilityLevel::Stable::since` is ill-formatted: `{since}`, {err:?}")),
                 )
             } else {
                 // Unstable const fn with the feature enabled.
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index f08275a4ac7..e53c40e9576 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -16,7 +16,7 @@ use rustc_middle::hir::place::ProjectionKind;
 use rustc_middle::mir::{FakeReadCause, Mutability};
 use rustc_middle::ty;
 use rustc_span::source_map::{BytePos, CharPos, Pos, Span, SyntaxContext};
-use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
+use rustc_hir_analysis::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 use std::borrow::Cow;
 use std::fmt::{Display, Write as _};
 use std::ops::{Add, Neg, Not, Sub};
@@ -1056,7 +1056,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
 
     fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
 
-    fn fake_read(&mut self, _: &rustc_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
+    fn fake_read(&mut self, _: &rustc_hir_analysis::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
 }
 
 #[cfg(test)]
diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs
index 3af5dfb62f9..76bfec75726 100644
--- a/src/tools/clippy/clippy_utils/src/usage.rs
+++ b/src/tools/clippy/clippy_utils/src/usage.rs
@@ -9,7 +9,7 @@ use rustc_lint::LateContext;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty;
-use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
+use rustc_hir_analysis::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 
 /// Returns a set of mutated local variable IDs, or `None` if mutations could not be determined.
 pub fn mutated_variables<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> Option<HirIdSet> {
@@ -21,7 +21,7 @@ pub fn mutated_variables<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) ->
         ExprUseVisitor::new(
             &mut delegate,
             &infcx,
-            expr.hir_id.owner,
+            expr.hir_id.owner.def_id,
             cx.param_env,
             cx.typeck_results(),
         )
@@ -73,7 +73,7 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate {
         self.update(cmt);
     }
 
-    fn fake_read(&mut self, _: &rustc_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
+    fn fake_read(&mut self, _: &rustc_hir_analysis::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
 }
 
 pub struct ParamBindingIdCollector {
diff --git a/src/tools/clippy/tests/ui/crashes/ice-7126.rs b/src/tools/clippy/tests/ui/crashes/ice-7126.rs
index ca563ba0978..b2dc2248b55 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-7126.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-7126.rs
@@ -1,13 +1,13 @@
 // This test requires a feature gated const fn and will stop working in the future.
 
-#![feature(const_btree_new)]
+#![feature(const_btree_len)]
 
 use std::collections::BTreeMap;
 
-struct Foo(BTreeMap<i32, i32>);
+struct Foo(usize);
 impl Foo {
     fn new() -> Self {
-        Self(BTreeMap::new())
+        Self(BTreeMap::len(&BTreeMap::<u8, u8>::new()))
     }
 }
 
diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed
index 539239fc18f..7263abac15d 100644
--- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed
+++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed
@@ -8,7 +8,7 @@
 
 use std::mem::{size_of, transmute};
 
-// rustc_typeck::check::cast contains documentation about when a cast `e as U` is
+// rustc_hir_analysis::check::cast contains documentation about when a cast `e as U` is
 // valid, which we quote from below.
 fn main() {
     // We should see an error message for each transmute, and no error messages for
diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs
index b9e446dc89a..d8e4421d4c1 100644
--- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs
+++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs
@@ -8,7 +8,7 @@
 
 use std::mem::{size_of, transmute};
 
-// rustc_typeck::check::cast contains documentation about when a cast `e as U` is
+// rustc_hir_analysis::check::cast contains documentation about when a cast `e as U` is
 // valid, which we quote from below.
 fn main() {
     // We should see an error message for each transmute, and no error messages for
diff --git a/src/tools/jsondoclint/src/item_kind.rs b/src/tools/jsondoclint/src/item_kind.rs
index ad8e96a0bd8..6d986e57501 100644
--- a/src/tools/jsondoclint/src/item_kind.rs
+++ b/src/tools/jsondoclint/src/item_kind.rs
@@ -142,8 +142,7 @@ impl Kind {
             ItemEnum::Static(_) => Static,
             ItemEnum::Macro(_) => Macro,
             ItemEnum::ProcMacro(_) => ProcMacro,
-            // https://github.com/rust-lang/rust/issues/100961
-            ItemEnum::PrimitiveType(_) => Primitive,
+            ItemEnum::Primitive(_) => Primitive,
             ItemEnum::ForeignType => ForeignType,
             ItemEnum::ExternCrate { .. } => ExternCrate,
             ItemEnum::AssocConst { .. } => AssocConst,
diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs
index a0e77127dc2..94af4c5e9e1 100644
--- a/src/tools/jsondoclint/src/validator.rs
+++ b/src/tools/jsondoclint/src/validator.rs
@@ -4,8 +4,8 @@ use std::hash::Hash;
 use rustdoc_json_types::{
     Constant, Crate, DynTrait, Enum, FnDecl, Function, FunctionPointer, GenericArg, GenericArgs,
     GenericBound, GenericParamDef, Generics, Id, Impl, Import, ItemEnum, Method, Module, OpaqueTy,
-    Path, ProcMacro, Static, Struct, StructKind, Term, Trait, TraitAlias, Type, TypeBinding,
-    TypeBindingKind, Typedef, Union, Variant, WherePredicate,
+    Path, Primitive, ProcMacro, Static, Struct, StructKind, Term, Trait, TraitAlias, Type,
+    TypeBinding, TypeBindingKind, Typedef, Union, Variant, WherePredicate,
 };
 
 use crate::{item_kind::Kind, Error, ErrorKind};
@@ -76,7 +76,7 @@ impl<'a> Validator<'a> {
                 ItemEnum::ForeignType => {} // nop
                 ItemEnum::Macro(x) => self.check_macro(x),
                 ItemEnum::ProcMacro(x) => self.check_proc_macro(x),
-                ItemEnum::PrimitiveType(x) => self.check_primitive_type(x),
+                ItemEnum::Primitive(x) => self.check_primitive_type(x),
                 ItemEnum::Module(x) => self.check_module(x),
                 // FIXME: Why don't these have their own structs?
                 ItemEnum::ExternCrate { .. } => {}
@@ -219,8 +219,8 @@ impl<'a> Validator<'a> {
         // nop
     }
 
-    fn check_primitive_type(&mut self, _: &'a str) {
-        // nop
+    fn check_primitive_type(&mut self, x: &'a Primitive) {
+        x.impls.iter().for_each(|i| self.add_impl_id(i));
     }
 
     fn check_generics(&mut self, x: &'a Generics) {
diff --git a/src/tools/miri/tests/fail/invalid_bool.rs b/src/tools/miri/tests/fail/invalid_bool.rs
index 525f8831c1c..dde414f4177 100644
--- a/src/tools/miri/tests/fail/invalid_bool.rs
+++ b/src/tools/miri/tests/fail/invalid_bool.rs
@@ -1,7 +1,7 @@
 // Validation makes this fail in the wrong place
 // Make sure we find these even with many checks disabled.
 //@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation
-#![feature(bench_black_box)]
+
 
 fn main() {
     let b = unsafe { std::mem::transmute::<u8, bool>(2) };
diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs
index 48dd99441eb..ce62fb0de04 100644
--- a/src/tools/miri/tests/pass/float.rs
+++ b/src/tools/miri/tests/pass/float.rs
@@ -1,4 +1,4 @@
-#![feature(stmt_expr_attributes, bench_black_box)]
+#![feature(stmt_expr_attributes)]
 #![allow(arithmetic_overflow)]
 use std::fmt::Debug;
 use std::hint::black_box;
diff --git a/src/tools/miri/tests/pass/u128.rs b/src/tools/miri/tests/pass/u128.rs
index 0ef7a514cb6..6def529dbe7 100644
--- a/src/tools/miri/tests/pass/u128.rs
+++ b/src/tools/miri/tests/pass/u128.rs
@@ -1,4 +1,3 @@
-#![feature(bench_black_box)]
 use std::hint::black_box as b;
 
 fn main() {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
index 344036dd813..e106c4c2cfd 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
@@ -1,7 +1,7 @@
 //! In certain situations, rust automatically inserts derefs as necessary: for
 //! example, field accesses `foo.bar` still work when `foo` is actually a
 //! reference to a type with the field `bar`. This is an approximation of the
-//! logic in rustc (which lives in librustc_typeck/check/autoderef.rs).
+//! logic in rustc (which lives in rustc_hir_analysis/check/autoderef.rs).
 
 use std::sync::Arc;
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
index e37763e8ea7..9dbeba4f9f4 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -2,7 +2,7 @@
 //! the type of each expression and pattern.
 //!
 //! For type inference, compare the implementations in rustc (the various
-//! check_* methods in librustc_typeck/check/mod.rs are a good entry point) and
+//! check_* methods in rustc_hir_analysis/check/mod.rs are a good entry point) and
 //! IntelliJ-Rust (org.rust.lang.core.types.infer). Our entry point for
 //! inference here is the `infer` function, which infers the types of all
 //! expressions in a given function.
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
index f54440bf5b3..8df25c83c6e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
@@ -3,7 +3,7 @@
 //! like going from `&Vec<T>` to `&[T]`.
 //!
 //! See <https://doc.rust-lang.org/nomicon/coercions.html> and
-//! `librustc_typeck/check/coercion.rs`.
+//! `rustc_hir_analysis/check/coercion.rs`.
 
 use std::{iter, sync::Arc};
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
index 41fcef73d9b..cc21990d553 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
@@ -1,7 +1,7 @@
 //! This module is concerned with finding methods that a given type provides.
 //! For details about how this works in rustc, see the method lookup page in the
 //! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html)
-//! and the corresponding code mostly in librustc_typeck/check/method/probe.rs.
+//! and the corresponding code mostly in rustc_hir_analysis/check/method/probe.rs.
 use std::{iter, ops::ControlFlow, sync::Arc};
 
 use arrayvec::ArrayVec;
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 9aab66b1d21..d4733107e79 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -73,14 +73,11 @@ const EXCEPTIONS_BOOTSTRAP: &[(&str, &str)] = &[
 /// these and all their dependencies *must not* be in the exception list.
 const RUNTIME_CRATES: &[&str] = &["std", "core", "alloc", "test", "panic_abort", "panic_unwind"];
 
-/// Crates whose dependencies must be explicitly permitted.
-const RESTRICTED_DEPENDENCY_CRATES: &[&str] = &["rustc_driver", "rustc_codegen_llvm"];
-
 /// Crates rustc is allowed to depend on. Avoid adding to the list if possible.
 ///
 /// This list is here to provide a speed-bump to adding a new dependency to
 /// rustc. Please check with the compiler team before adding an entry.
-const PERMITTED_DEPENDENCIES: &[&str] = &[
+const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "addr2line",
     "adler",
     "ahash",
@@ -307,7 +304,7 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
 ];
 
 const FORBIDDEN_TO_HAVE_DUPLICATES: &[&str] = &[
-    // These two crates take quite a long time to build, so don't allow two versions of them
+    // This crate takes quite a long time to build, so don't allow two versions of them
     // to accidentally sneak into our dependency graph, in order to ensure we keep our CI times
     // under control.
     "cargo",
@@ -324,12 +321,12 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
         .features(cargo_metadata::CargoOpt::AllFeatures);
     let metadata = t!(cmd.exec());
     let runtime_ids = compute_runtime_crates(&metadata);
-    check_exceptions(&metadata, EXCEPTIONS, runtime_ids, bad);
-    check_dependencies(
+    check_license_exceptions(&metadata, EXCEPTIONS, runtime_ids, bad);
+    check_permitted_dependencies(
         &metadata,
-        "main workspace",
-        PERMITTED_DEPENDENCIES,
-        RESTRICTED_DEPENDENCY_CRATES,
+        "rustc",
+        PERMITTED_RUSTC_DEPENDENCIES,
+        &["rustc_driver", "rustc_codegen_llvm"],
         bad,
     );
     check_crate_duplicate(&metadata, FORBIDDEN_TO_HAVE_DUPLICATES, bad);
@@ -342,8 +339,8 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
         .features(cargo_metadata::CargoOpt::AllFeatures);
     let metadata = t!(cmd.exec());
     let runtime_ids = HashSet::new();
-    check_exceptions(&metadata, EXCEPTIONS_CRANELIFT, runtime_ids, bad);
-    check_dependencies(
+    check_license_exceptions(&metadata, EXCEPTIONS_CRANELIFT, runtime_ids, bad);
+    check_permitted_dependencies(
         &metadata,
         "cranelift",
         PERMITTED_CRANELIFT_DEPENDENCIES,
@@ -358,13 +355,13 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
         .features(cargo_metadata::CargoOpt::AllFeatures);
     let metadata = t!(cmd.exec());
     let runtime_ids = HashSet::new();
-    check_exceptions(&metadata, EXCEPTIONS_BOOTSTRAP, runtime_ids, bad);
+    check_license_exceptions(&metadata, EXCEPTIONS_BOOTSTRAP, runtime_ids, bad);
 }
 
 /// Check that all licenses are in the valid list in `LICENSES`.
 ///
-/// Packages listed in `EXCEPTIONS` are allowed for tools.
-fn check_exceptions(
+/// Packages listed in `exceptions` are allowed for tools.
+fn check_license_exceptions(
     metadata: &Metadata,
     exceptions: &[(&str, &str)],
     runtime_ids: HashSet<&PackageId>,
@@ -434,11 +431,11 @@ fn check_exceptions(
     }
 }
 
-/// Checks the dependency of `RESTRICTED_DEPENDENCY_CRATES` at the given path. Changes `bad` to
+/// Checks the dependency of `restricted_dependency_crates` at the given path. Changes `bad` to
 /// `true` if a check failed.
 ///
-/// Specifically, this checks that the dependencies are on the `PERMITTED_DEPENDENCIES`.
-fn check_dependencies(
+/// Specifically, this checks that the dependencies are on the `permitted_dependencies`.
+fn check_permitted_dependencies(
     metadata: &Metadata,
     descr: &str,
     permitted_dependencies: &[&'static str],