about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast_lowering/messages.ftl3
-rw-r--r--compiler/rustc_ast_lowering/src/errors.rs7
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs38
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs32
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs15
-rw-r--r--compiler/rustc_ast_lowering/src/path.rs1
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs23
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs36
-rw-r--r--compiler/rustc_borrowck/src/lib.rs11
-rw-r--r--compiler/rustc_borrowck/src/path_utils.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/constraint_conversion.rs118
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs69
-rw-r--r--compiler/rustc_borrowck/src/type_check/input_output.rs76
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs38
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs69
-rw-r--r--compiler/rustc_codegen_gcc/src/attributes.rs3
-rw-r--r--compiler/rustc_codegen_gcc/src/type_of.rs2
-rw-r--r--compiler/rustc_codegen_llvm/messages.ftl2
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/errors.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs1
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs16
-rw-r--r--compiler/rustc_codegen_llvm/src/mono_item.rs25
-rw-r--r--compiler/rustc_codegen_llvm/src/type_of.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs6
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs8
-rw-r--r--compiler/rustc_const_eval/src/const_eval/valtrees.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs1
-rw-r--r--compiler/rustc_const_eval/src/interpret/intern.rs116
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs1
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs6
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs29
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs32
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs23
-rw-r--r--compiler/rustc_const_eval/src/util/type_name.rs1
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0724.md7
-rw-r--r--compiler/rustc_error_messages/src/lib.rs2
-rw-r--r--compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs22
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs20
-rw-r--r--compiler/rustc_errors/src/emitter.rs42
-rw-r--r--compiler/rustc_errors/src/json.rs52
-rw-r--r--compiler/rustc_errors/src/lib.rs256
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs3
-rw-r--r--compiler/rustc_feature/src/removed.rs3
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_hir/src/hir.rs6
-rw-r--r--compiler/rustc_hir/src/lang_items.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/errors.rs51
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs24
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/variance/constraints.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs116
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs103
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs1
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs117
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs72
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs156
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs3
-rw-r--r--compiler/rustc_infer/src/infer/canonical/mod.rs8
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs17
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs5
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs7
-rw-r--r--compiler/rustc_infer/src/infer/freshen.rs9
-rw-r--r--compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs25
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs11
-rw-r--r--compiler/rustc_infer/src/infer/outlives/components.rs5
-rw-r--r--compiler/rustc_infer/src/infer/outlives/mod.rs13
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs80
-rw-r--r--compiler/rustc_infer/src/infer/relate/combine.rs38
-rw-r--r--compiler/rustc_infer/src/infer/resolve.rs9
-rw-r--r--compiler/rustc_interface/src/tests.rs1
-rw-r--r--compiler/rustc_lint/src/context/diagnostics.rs50
-rw-r--r--compiler/rustc_lint/src/lib.rs5
-rw-r--r--compiler/rustc_lint/src/types.rs1
-rw-r--r--compiler/rustc_lint/src/unused.rs2
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs51
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h1
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp15
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp2
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs4
-rw-r--r--compiler/rustc_middle/src/infer/unify_key.rs42
-rw-r--r--compiler/rustc_middle/src/middle/codegen_fn_attrs.rs23
-rw-r--r--compiler/rustc_middle/src/middle/lang_items.rs15
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs29
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs2
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs3
-rw-r--r--compiler/rustc_middle/src/mir/query.rs3
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs1
-rw-r--r--compiler/rustc_middle/src/mir/tcx.rs3
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs8
-rw-r--r--compiler/rustc_middle/src/query/mod.rs5
-rw-r--r--compiler/rustc_middle/src/traits/select.rs9
-rw-r--r--compiler/rustc_middle/src/ty/context.rs3
-rw-r--r--compiler/rustc_middle/src/ty/error.rs2
-rw-r--r--compiler/rustc_middle/src/ty/fast_reject.rs7
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs16
-rw-r--r--compiler/rustc_middle/src/ty/generic_args.rs10
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs54
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs6
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs9
-rw-r--r--compiler/rustc_middle/src/ty/print/mod.rs22
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs42
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs7
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs4
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs351
-rw-r--r--compiler/rustc_middle/src/ty/util.rs15
-rw-r--r--compiler/rustc_middle/src/ty/walk.rs1
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs3
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs3
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs3
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/mod.rs18
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs3
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs113
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs18
-rw-r--r--compiler/rustc_mir_dataflow/src/elaborate_drops.rs3
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs8
-rw-r--r--compiler/rustc_mir_dataflow/src/value_analysis.rs6
-rw-r--r--compiler/rustc_mir_transform/src/abort_unwinding_calls.rs1
-rw-r--r--compiler/rustc_mir_transform/src/check_unsafety.rs4
-rw-r--r--compiler/rustc_mir_transform/src/const_prop_lint.rs3
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs3
-rw-r--r--compiler/rustc_mir_transform/src/coroutine/by_move_body.rs156
-rw-r--r--compiler/rustc_mir_transform/src/coverage/counters.rs70
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mod.rs89
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs4
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs1
-rw-r--r--compiler/rustc_mir_transform/src/ffi_unwind_calls.rs1
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs11
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs2
-rw-r--r--compiler/rustc_mir_transform/src/inline/cycle.rs2
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs4
-rw-r--r--compiler/rustc_mir_transform/src/pass_manager.rs9
-rw-r--r--compiler/rustc_mir_transform/src/remove_zsts.rs1
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs180
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs2
-rw-r--r--compiler/rustc_monomorphize/src/partitioning.rs6
-rw-r--r--compiler/rustc_next_trait_solver/src/canonicalizer.rs3
-rw-r--r--compiler/rustc_passes/messages.ftl3
-rw-r--r--compiler/rustc_passes/src/check_attr.rs10
-rw-r--r--compiler/rustc_passes/src/dead.rs91
-rw-r--r--compiler/rustc_passes/src/errors.rs11
-rw-r--r--compiler/rustc_passes/src/liveness.rs5
-rw-r--r--compiler/rustc_pattern_analysis/src/errors.rs5
-rw-r--r--compiler/rustc_pattern_analysis/src/lib.rs8
-rw-r--r--compiler/rustc_pattern_analysis/src/pat.rs32
-rw-r--r--compiler/rustc_pattern_analysis/src/pat_column.rs4
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs72
-rw-r--r--compiler/rustc_pattern_analysis/src/usefulness.rs101
-rw-r--r--compiler/rustc_privacy/src/lib.rs1
-rw-r--r--compiler/rustc_resolve/messages.ftl17
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs10
-rw-r--r--compiler/rustc_resolve/src/errors.rs25
-rw-r--r--compiler/rustc_resolve/src/ident.rs30
-rw-r--r--compiler/rustc_resolve/src/late.rs46
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs38
-rw-r--r--compiler/rustc_resolve/src/lib.rs6
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_session/src/session.rs7
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/mir.rs3
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/ty.rs3
-rw-r--r--compiler/rustc_span/src/source_map/tests.rs49
-rw-r--r--compiler/rustc_span/src/symbol.rs5
-rw-r--r--compiler/rustc_symbol_mangling/src/legacy.rs40
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs8
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs8
-rw-r--r--compiler/rustc_target/src/spec/mod.rs12
-rw-r--r--compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs35
-rw-r--r--compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs1
-rw-r--r--compiler/rustc_trait_selection/src/regions.rs3
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/mod.rs25
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs134
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs115
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs63
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs89
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs193
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs20
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs78
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs52
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs21
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_match.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs8
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs77
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs30
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs11
-rw-r--r--compiler/rustc_ty_utils/src/needs_drop.rs6
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs4
-rw-r--r--compiler/rustc_type_ir/src/ty_kind.rs32
-rw-r--r--library/core/src/intrinsics.rs8
-rw-r--r--library/core/src/lib.rs1
-rw-r--r--library/core/src/ops/async_function.rs25
-rw-r--r--library/core/src/ptr/const_ptr.rs4
-rw-r--r--library/core/src/ptr/mod.rs7
-rw-r--r--library/core/src/ptr/mut_ptr.rs8
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/core/tests/macros.rs1
-rw-r--r--library/proc_macro/src/bridge/client.rs9
-rw-r--r--library/proc_macro/src/bridge/handle.rs10
-rw-r--r--library/proc_macro/src/bridge/mod.rs1
-rw-r--r--library/std/src/sys_common/mod.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs34
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs116
-rw-r--r--src/bootstrap/src/core/builder.rs256
-rwxr-xr-xsrc/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh2
-rw-r--r--src/doc/rustc/src/SUMMARY.md1
-rw-r--r--src/doc/rustc/src/platform-support.md1
-rw-r--r--src/doc/rustc/src/platform-support/arm-none-eabi.md1
-rw-r--r--src/doc/rustc/src/platform-support/armv8r-none-eabihf.md40
-rw-r--r--src/doc/unstable-book/src/compiler-flags/direct-access-external-data.md16
-rw-r--r--src/doc/unstable-book/src/library-features/async-fn-traits.md13
-rw-r--r--src/librustdoc/clean/mod.rs1
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs1
-rw-r--r--src/librustdoc/passes/lint/check_code_block_syntax.rs2
-rw-r--r--src/tools/build-manifest/src/main.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs3
-rw-r--r--src/tools/clippy/tests/ui/author/blocks.stdout4
-rw-r--r--src/tools/compiletest/src/runtest.rs1
-rw-r--r--src/tools/miri/src/borrow_tracker/mod.rs2
-rw-r--r--src/tools/miri/src/machine.rs34
-rw-r--r--src/tools/miri/src/provenance_gc.rs1
-rw-r--r--src/tools/miri/src/shims/foreign_items.rs12
-rw-r--r--src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs1
-rw-r--r--src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs6
-rw-r--r--src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.rs12
-rw-r--r--src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.stderr14
-rw-r--r--src/tools/miri/tests/pass/align_offset_symbolic.rs23
-rw-r--r--src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs1
-rw-r--r--src/tools/miri/tests/pass/dyn-upcast.rs3
-rw-r--r--src/tools/miri/tests/pass/weak_memory/weak.rs1
-rw-r--r--src/tools/rustfmt/src/parse/session.rs20
-rw-r--r--src/tools/tidy/src/ui_tests.rs5
-rw-r--r--tests/assembly/targets/targets-elf.rs3
-rw-r--r--tests/codegen-units/item-collection/instantiation-through-vtable.rs4
-rw-r--r--tests/codegen-units/item-collection/trait-method-default-impl.rs3
-rw-r--r--tests/codegen-units/item-collection/unsizing.rs2
-rw-r--r--tests/codegen/cffi/ffi-returns-twice.rs11
-rw-r--r--tests/codegen/direct-access-external-data.rs21
-rw-r--r--tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-abort.mir47
-rw-r--r--tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-unwind.mir47
-rw-r--r--tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-abort.mir47
-rw-r--r--tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-unwind.mir47
-rw-r--r--tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir10
-rw-r--r--tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir10
-rw-r--r--tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-abort.mir16
-rw-r--r--tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-unwind.mir16
-rw-r--r--tests/mir-opt/async_closure_shims.rs46
-rw-r--r--tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir2
-rw-r--r--tests/mir-opt/fn_ptr_shim.rs2
-rw-r--r--tests/mir-opt/inline/cycle.g.Inline.panic-abort.diff21
-rw-r--r--tests/mir-opt/inline/cycle.g.Inline.panic-unwind.diff29
-rw-r--r--tests/mir-opt/inline/cycle.rs4
-rw-r--r--tests/mir-opt/inline/inline_cycle_generic.main.Inline.panic-abort.diff6
-rw-r--r--tests/mir-opt/inline/inline_cycle_generic.main.Inline.panic-unwind.diff6
-rw-r--r--tests/mir-opt/issue_99325.main.built.after.32bit.mir4
-rw-r--r--tests/mir-opt/issue_99325.main.built.after.64bit.mir4
-rw-r--r--tests/mir-opt/remove_storage_markers.rs5
-rw-r--r--tests/mir-opt/retag.rs2
-rw-r--r--tests/mir-opt/simplify_if.rs5
-rw-r--r--tests/mir-opt/slice_drop_shim.rs6
-rw-r--r--tests/mir-opt/sroa/lifetimes.rs5
-rw-r--r--tests/mir-opt/sroa/structs.rs125
-rw-r--r--tests/mir-opt/unusual_item_types.rs2
-rw-r--r--tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs1
-rw-r--r--tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr36
-rw-r--r--tests/ui-fulldeps/rustc_encodable_hygiene.rs2
-rw-r--r--tests/ui/anon-params/anon-params-deprecated.fixed1
-rw-r--r--tests/ui/anon-params/anon-params-deprecated.rs1
-rw-r--r--tests/ui/anon-params/anon-params-deprecated.stderr6
-rw-r--r--tests/ui/associated-consts/associated-const-outer-ty-refs.rs3
-rw-r--r--tests/ui/associated-consts/associated-const-type-parameters.rs2
-rw-r--r--tests/ui/associated-consts/associated-const-type-parameters.stderr10
-rw-r--r--tests/ui/associated-type-bounds/dyn-impl-trait-type.rs2
-rw-r--r--tests/ui/associated-type-bounds/dyn-impl-trait-type.stderr12
-rw-r--r--tests/ui/associated-type-bounds/dyn-rpit-and-let.rs2
-rw-r--r--tests/ui/associated-type-bounds/dyn-rpit-and-let.stderr12
-rw-r--r--tests/ui/associated-type-bounds/rpit.rs2
-rw-r--r--tests/ui/associated-type-bounds/rpit.stderr12
-rw-r--r--tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.fixed1
-rw-r--r--tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.rs1
-rw-r--r--tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.stderr2
-rw-r--r--tests/ui/associated-type-bounds/trait-alias-impl-trait.rs1
-rw-r--r--tests/ui/associated-types/associated-types-for-unimpl-trait.fixed1
-rw-r--r--tests/ui/associated-types/associated-types-for-unimpl-trait.rs1
-rw-r--r--tests/ui/associated-types/associated-types-for-unimpl-trait.stderr2
-rw-r--r--tests/ui/associated-types/associated-types-in-bound-type-arg.rs2
-rw-r--r--tests/ui/associated-types/associated-types-issue-20220.rs2
-rw-r--r--tests/ui/associated-types/associated-types-issue-20220.stderr10
-rw-r--r--tests/ui/associated-types/associated-types-issue-20371.rs2
-rw-r--r--tests/ui/associated-types/associated-types-nested-projections.rs2
-rw-r--r--tests/ui/associated-types/associated-types-nested-projections.stderr13
-rw-r--r--tests/ui/associated-types/associated-types-normalize-in-bounds-ufcs.rs2
-rw-r--r--tests/ui/associated-types/associated-types-normalize-in-bounds.rs2
-rw-r--r--tests/ui/associated-types/associated-types-projection-bound-in-supertraits.rs2
-rw-r--r--tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.rs2
-rw-r--r--tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.stderr13
-rw-r--r--tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed1
-rw-r--r--tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.rs1
-rw-r--r--tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr2
-rw-r--r--tests/ui/associated-types/associated-types-projection-to-unrelated-trait.rs2
-rw-r--r--tests/ui/associated-types/associated-types-qualified-path-with-trait-with-type-parameters.rs2
-rw-r--r--tests/ui/associated-types/associated-types-resolve-lifetime.rs2
-rw-r--r--tests/ui/associated-types/impl-wf-cycle-5.fixed2
-rw-r--r--tests/ui/associated-types/impl-wf-cycle-5.rs2
-rw-r--r--tests/ui/associated-types/impl-wf-cycle-5.stderr4
-rw-r--r--tests/ui/associated-types/impl-wf-cycle-6.fixed2
-rw-r--r--tests/ui/associated-types/impl-wf-cycle-6.rs2
-rw-r--r--tests/ui/associated-types/impl-wf-cycle-6.stderr4
-rw-r--r--tests/ui/async-await/async-borrowck-escaping-closure-error.rs3
-rw-r--r--tests/ui/async-await/async-borrowck-escaping-closure-error.stderr21
-rw-r--r--tests/ui/async-await/async-closures/arg-mismatch.rs15
-rw-r--r--tests/ui/async-await/async-closures/arg-mismatch.stderr21
-rw-r--r--tests/ui/async-await/async-closures/async-fn-mut-for-async-fn.rs21
-rw-r--r--tests/ui/async-await/async-closures/async-fn-once-for-async-fn.rs21
-rw-r--r--tests/ui/async-await/async-closures/auxiliary/block-on.rs20
-rw-r--r--tests/ui/async-await/async-closures/await-inference-guidance.rs16
-rw-r--r--tests/ui/async-await/async-closures/brand.rs25
-rw-r--r--tests/ui/async-await/async-closures/def-path.rs4
-rw-r--r--tests/ui/async-await/async-closures/def-path.stderr4
-rw-r--r--tests/ui/async-await/async-closures/drop.rs38
-rw-r--r--tests/ui/async-await/async-closures/drop.run.stdout5
-rw-r--r--tests/ui/async-await/async-closures/higher-ranked-return.rs18
-rw-r--r--tests/ui/async-await/async-closures/higher-ranked-return.stderr14
-rw-r--r--tests/ui/async-await/async-closures/higher-ranked.rs16
-rw-r--r--tests/ui/async-await/async-closures/higher-ranked.stderr17
-rw-r--r--tests/ui/async-await/async-closures/is-not-fn.rs12
-rw-r--r--tests/ui/async-await/async-closures/is-not-fn.stderr19
-rw-r--r--tests/ui/async-await/async-closures/mangle.rs35
-rw-r--r--tests/ui/async-await/async-closures/move-consuming-capture.rs20
-rw-r--r--tests/ui/async-await/async-closures/move-consuming-capture.stderr17
-rw-r--r--tests/ui/async-await/async-closures/move-is-async-fn.rs21
-rw-r--r--tests/ui/async-await/async-closures/mutate.rs19
-rw-r--r--tests/ui/async-await/async-closures/not-lending.rs21
-rw-r--r--tests/ui/async-await/async-closures/not-lending.stderr24
-rw-r--r--tests/ui/async-await/async-closures/return-type-mismatch.rs14
-rw-r--r--tests/ui/async-await/async-closures/return-type-mismatch.stderr14
-rw-r--r--tests/ui/async-await/async-closures/wrong-fn-kind.rs16
-rw-r--r--tests/ui/async-await/async-closures/wrong-fn-kind.stderr22
-rw-r--r--tests/ui/async-await/in-trait/auxiliary/bad-region.rs7
-rw-r--r--tests/ui/async-await/in-trait/bad-region.rs17
-rw-r--r--tests/ui/async-await/in-trait/bad-region.stderr14
-rw-r--r--tests/ui/async-await/issue-74072-lifetime-name-annotations.rs4
-rw-r--r--tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr87
-rw-r--r--tests/ui/auto-traits/auto-trait-validation.fixed1
-rw-r--r--tests/ui/auto-traits/auto-trait-validation.rs1
-rw-r--r--tests/ui/auto-traits/auto-trait-validation.stderr8
-rw-r--r--tests/ui/auto-traits/auto-traits.rs4
-rw-r--r--tests/ui/auto-traits/auto-traits.stderr16
-rw-r--r--tests/ui/binding/irrefutable-if-let-without-else.fixed25
-rw-r--r--tests/ui/binding/irrefutable-if-let-without-else.rs28
-rw-r--r--tests/ui/binding/irrefutable-if-let-without-else.stderr61
-rw-r--r--tests/ui/box/unit/unique-object-noncopyable.stderr3
-rw-r--r--tests/ui/box/unit/unique-pinned-nocopy.stderr3
-rw-r--r--tests/ui/builtin-superkinds/builtin-superkinds-in-metadata2.rs2
-rw-r--r--tests/ui/builtin-superkinds/builtin-superkinds-simple2.rs2
-rw-r--r--tests/ui/builtin-superkinds/builtin-superkinds-typaram.rs2
-rw-r--r--tests/ui/cast/cast-rfc0401-vtable-kinds.rs2
-rw-r--r--tests/ui/cast/cast-rfc0401-vtable-kinds.stderr10
-rw-r--r--tests/ui/cast/fat-ptr-cast-rpass.rs2
-rw-r--r--tests/ui/cast/fat-ptr-cast-rpass.stderr12
-rw-r--r--tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.rs12
-rw-r--r--tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr13
-rw-r--r--tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.rs12
-rw-r--r--tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr21
-rw-r--r--tests/ui/check-cfg/cfg-value-for-cfg-name.rs18
-rw-r--r--tests/ui/check-cfg/cfg-value-for-cfg-name.stderr22
-rw-r--r--tests/ui/closures/2229_closure_analysis/match/match-edge-cases_1.stderr13
-rw-r--r--tests/ui/closures/binder/async-closure-with-binder.rs7
-rw-r--r--tests/ui/closures/binder/async-closure-with-binder.stderr16
-rw-r--r--tests/ui/coercion/issue-14589.rs2
-rw-r--r--tests/ui/coercion/issue-14589.stderr12
-rw-r--r--tests/ui/coherence/coherence-multidispatch-tuple.rs2
-rw-r--r--tests/ui/const-generics/associated-type-bound.rs2
-rw-r--r--tests/ui/const-generics/condition-in-trait-const-arg.rs2
-rw-r--r--tests/ui/const-generics/dyn-supertraits.rs6
-rw-r--r--tests/ui/const-generics/dyn-supertraits.stderr22
-rw-r--r--tests/ui/const-generics/issues/issue-69654-run-pass.rs2
-rw-r--r--tests/ui/const-generics/issues/issue-69654-run-pass.stderr10
-rw-r--r--tests/ui/consts/const-block-item.rs2
-rw-r--r--tests/ui/consts/const-block-item.stderr10
-rw-r--r--tests/ui/consts/const-eval/raw-pointer-ub.rs2
-rw-r--r--tests/ui/consts/const_in_pattern/accept_structural.rs14
-rw-r--r--tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs3
-rw-r--r--tests/ui/consts/const_in_pattern/custom-eq-branch-warn.rs38
-rw-r--r--tests/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr14
-rw-r--r--tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr68
-rw-r--r--tests/ui/consts/const_in_pattern/issue-44333.stderr34
-rw-r--r--tests/ui/consts/const_in_pattern/issue-73431.stderr1
-rw-r--r--tests/ui/consts/const_in_pattern/reject_non_structural.rs2
-rw-r--r--tests/ui/consts/const_in_pattern/reject_non_structural.stderr19
-rw-r--r--tests/ui/consts/const_in_pattern/warn_corner_cases.rs41
-rw-r--r--tests/ui/consts/const_in_pattern/warn_corner_cases.stderr36
-rw-r--r--tests/ui/consts/issue-89088.stderr17
-rw-r--r--tests/ui/consts/underscore_const_names.rs4
-rw-r--r--tests/ui/default-method-parsing.rs2
-rw-r--r--tests/ui/delegation/target-expr-pass.rs6
-rw-r--r--tests/ui/delegation/target-expr-pass.stderr22
-rw-r--r--tests/ui/derives/derive-assoc-type-not-impl.stderr3
-rw-r--r--tests/ui/deriving/deriving-bounds.rs2
-rw-r--r--tests/ui/drop/drop-struct-as-object.rs2
-rw-r--r--tests/ui/drop/drop-struct-as-object.stderr12
-rw-r--r--tests/ui/dynamically-sized-types/dst-coercions.rs2
-rw-r--r--tests/ui/dynamically-sized-types/dst-coercions.stderr12
-rw-r--r--tests/ui/empty-type-parameter-list.rs2
-rw-r--r--tests/ui/empty-type-parameter-list.stderr10
-rw-r--r--tests/ui/error-codes/E0401.stderr4
-rw-r--r--tests/ui/explicit/explicit-call-to-supertrait-dtor.fixed1
-rw-r--r--tests/ui/explicit/explicit-call-to-supertrait-dtor.rs1
-rw-r--r--tests/ui/explicit/explicit-call-to-supertrait-dtor.stderr2
-rw-r--r--tests/ui/extern/no-mangle-associated-fn.rs2
-rw-r--r--tests/ui/extern/no-mangle-associated-fn.stderr10
-rw-r--r--tests/ui/feature-gates/feature-gate-ffi_returns_twice.rs6
-rw-r--r--tests/ui/feature-gates/feature-gate-ffi_returns_twice.stderr13
-rw-r--r--tests/ui/ffi_returns_twice.rs15
-rw-r--r--tests/ui/ffi_returns_twice.stderr21
-rw-r--r--tests/ui/generic-associated-types/issue-88360.fixed1
-rw-r--r--tests/ui/generic-associated-types/issue-88360.rs1
-rw-r--r--tests/ui/generic-associated-types/issue-88360.stderr2
-rw-r--r--tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.rs2
-rw-r--r--tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr6
-rw-r--r--tests/ui/generics/generic-no-mangle.fixed2
-rw-r--r--tests/ui/generics/generic-no-mangle.rs2
-rw-r--r--tests/ui/higher-ranked/trait-bounds/issue-30786.stderr12
-rw-r--r--tests/ui/impl-trait/equality-in-canonical-query.clone.stderr2
-rw-r--r--tests/ui/impl-trait/example-st.rs2
-rw-r--r--tests/ui/impl-trait/example-st.stderr10
-rw-r--r--tests/ui/impl-trait/in-trait/suggest-missing-item.fixed1
-rw-r--r--tests/ui/impl-trait/in-trait/suggest-missing-item.rs1
-rw-r--r--tests/ui/impl-trait/in-trait/suggest-missing-item.stderr2
-rw-r--r--tests/ui/impl-trait/type-alias-generic-param.rs2
-rw-r--r--tests/ui/impl-trait/type-alias-generic-param.stderr10
-rw-r--r--tests/ui/inner-static-type-parameter.stderr2
-rw-r--r--tests/ui/issues/issue-14399.rs2
-rw-r--r--tests/ui/issues/issue-14399.stderr12
-rw-r--r--tests/ui/issues/issue-15858.rs2
-rw-r--r--tests/ui/issues/issue-15858.stderr12
-rw-r--r--tests/ui/issues/issue-17351.rs2
-rw-r--r--tests/ui/issues/issue-17351.stderr12
-rw-r--r--tests/ui/issues/issue-18173.rs2
-rw-r--r--tests/ui/issues/issue-20055-box-trait.rs2
-rw-r--r--tests/ui/issues/issue-20055-box-trait.stderr12
-rw-r--r--tests/ui/issues/issue-21909.rs2
-rw-r--r--tests/ui/issues/issue-23485.rs2
-rw-r--r--tests/ui/issues/issue-23485.stderr13
-rw-r--r--tests/ui/issues/issue-2989.rs4
-rw-r--r--tests/ui/issues/issue-2989.stderr10
-rw-r--r--tests/ui/issues/issue-34074.rs2
-rw-r--r--tests/ui/issues/issue-34503.rs2
-rw-r--r--tests/ui/issues/issue-34503.stderr14
-rw-r--r--tests/ui/issues/issue-3563-3.rs2
-rw-r--r--tests/ui/issues/issue-3563-3.stderr13
-rw-r--r--tests/ui/issues/issue-50571.fixed1
-rw-r--r--tests/ui/issues/issue-50571.rs1
-rw-r--r--tests/ui/issues/issue-50571.stderr2
-rw-r--r--tests/ui/issues/issue-7575.rs2
-rw-r--r--tests/ui/issues/issue-7575.stderr10
-rw-r--r--tests/ui/issues/issue-7911.rs2
-rw-r--r--tests/ui/issues/issue-7911.stderr12
-rw-r--r--tests/ui/issues/issue-8248.rs2
-rw-r--r--tests/ui/issues/issue-8248.stderr12
-rw-r--r--tests/ui/issues/issue-9951.rs2
-rw-r--r--tests/ui/issues/issue-9951.stderr12
-rw-r--r--tests/ui/lint/dead-code/associated-type.rs2
-rw-r--r--tests/ui/lint/dead-code/issue-41883.rs29
-rw-r--r--tests/ui/lint/dead-code/issue-41883.stderr36
-rw-r--r--tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.rs2
-rw-r--r--tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.stderr12
-rw-r--r--tests/ui/lint/future-incompat-json-test.stderr2
-rw-r--r--tests/ui/lint/issue-20343.rs3
-rw-r--r--tests/ui/macros/issue-22463.rs2
-rw-r--r--tests/ui/methods/method-call-err-msg.stderr5
-rw-r--r--tests/ui/methods/method-lookup-order.rs1
-rw-r--r--tests/ui/methods/method-recursive-blanket-impl.rs2
-rw-r--r--tests/ui/methods/method-recursive-blanket-impl.stderr10
-rw-r--r--tests/ui/methods/method-two-trait-defer-resolution-2.rs2
-rw-r--r--tests/ui/methods/method-two-trait-defer-resolution-2.stderr12
-rw-r--r--tests/ui/methods/method-two-traits-distinguished-via-where-clause.rs2
-rw-r--r--tests/ui/methods/method-two-traits-distinguished-via-where-clause.stderr10
-rw-r--r--tests/ui/mir/mir_raw_fat_ptr.rs2
-rw-r--r--tests/ui/mir/mir_raw_fat_ptr.stderr12
-rw-r--r--tests/ui/moves/issue-22536-copy-mustnt-zero.rs2
-rw-r--r--tests/ui/moves/issue-22536-copy-mustnt-zero.stderr13
-rw-r--r--tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed1
-rw-r--r--tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs1
-rw-r--r--tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr4
-rw-r--r--tests/ui/overloaded/issue-14958.rs2
-rw-r--r--tests/ui/overloaded/issue-14958.stderr12
-rw-r--r--tests/ui/overloaded/overloaded-index-in-field.rs2
-rw-r--r--tests/ui/overloaded/overloaded-index-in-field.stderr15
-rw-r--r--tests/ui/parallel-rustc/cache-after-waiting-issue-111528.rs16
-rw-r--r--tests/ui/parallel-rustc/cache-after-waiting-issue-111528.stderr8
-rw-r--r--tests/ui/parallel-rustc/export-symbols-deadlock-issue-118205-2.rs7
-rw-r--r--tests/ui/parallel-rustc/export-symbols-deadlock-issue-118205.rs22
-rw-r--r--tests/ui/parallel-rustc/hello_world.rs6
-rw-r--r--tests/ui/parallel-rustc/read-stolen-value-issue-111520.rs18
-rw-r--r--tests/ui/parser/parse-assoc-type-lt.rs2
-rw-r--r--tests/ui/parser/suggest-assoc-const.fixed1
-rw-r--r--tests/ui/parser/suggest-assoc-const.rs1
-rw-r--r--tests/ui/parser/suggest-assoc-const.stderr2
-rw-r--r--tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.fixed1
-rw-r--r--tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.rs1
-rw-r--r--tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.stderr2
-rw-r--r--tests/ui/pattern/issue-22546.rs2
-rw-r--r--tests/ui/pattern/issue-22546.stderr10
-rw-r--r--tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.rs16
-rw-r--r--tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr61
-rw-r--r--tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr18
-rw-r--r--tests/ui/pattern/usefulness/consts-opaque.stderr104
-rw-r--r--tests/ui/privacy/sealed-traits/re-exported-trait.fixed1
-rw-r--r--tests/ui/privacy/sealed-traits/re-exported-trait.rs1
-rw-r--r--tests/ui/privacy/sealed-traits/re-exported-trait.stderr4
-rw-r--r--tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.fixed1
-rw-r--r--tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.rs1
-rw-r--r--tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.stderr1
-rw-r--r--tests/ui/regions/regions-no-variance-from-fn-generics.rs2
-rw-r--r--tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr6
-rw-r--r--tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr6
-rw-r--r--tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.fixed1
-rw-r--r--tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs1
-rw-r--r--tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.stderr6
-rw-r--r--tests/ui/resolve/issue-12796.rs2
-rw-r--r--tests/ui/resolve/issue-12796.stderr4
-rw-r--r--tests/ui/resolve/issue-65025-extern-static-parent-generics.stderr2
-rw-r--r--tests/ui/resolve/issue-65035-static-with-parent-generics.stderr10
-rw-r--r--tests/ui/resolve/use-self-in-inner-fn.rs4
-rw-r--r--tests/ui/resolve/use-self-in-inner-fn.stderr4
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr19
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr19
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr19
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr19
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.stderr130
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs2
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr40
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr34
-rw-r--r--tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.current.stderr15
-rw-r--r--tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.next.stderr15
-rw-r--r--tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs2
-rw-r--r--tests/ui/rust-2018/issue-51008-1.rs2
-rw-r--r--tests/ui/rust-2018/issue-51008.rs2
-rw-r--r--tests/ui/sized/coinductive-2.rs2
-rw-r--r--tests/ui/sized/coinductive-2.stderr10
-rw-r--r--tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs2
-rw-r--r--tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr27
-rw-r--r--tests/ui/specialization/assoc-ty-graph-cycle.rs2
-rw-r--r--tests/ui/specialization/defaultimpl/out-of-order.rs2
-rw-r--r--tests/ui/specialization/defaultimpl/overlap-projection.rs2
-rw-r--r--tests/ui/specialization/specialization-out-of-order.rs2
-rw-r--r--tests/ui/specialization/specialization-overlap-projection.rs2
-rw-r--r--tests/ui/specialization/specialization-supertraits.rs2
-rw-r--r--tests/ui/statics/static-impl.rs2
-rw-r--r--tests/ui/statics/static-impl.stderr13
-rw-r--r--tests/ui/stdlib-unit-tests/raw-fat-ptr.rs2
-rw-r--r--tests/ui/stdlib-unit-tests/raw-fat-ptr.stderr12
-rw-r--r--tests/ui/structs-enums/enum-null-pointer-opt.rs2
-rw-r--r--tests/ui/structs-enums/enum-null-pointer-opt.stderr12
-rw-r--r--tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr12
-rw-r--r--tests/ui/suggestions/bound-suggestions.fixed5
-rw-r--r--tests/ui/suggestions/bound-suggestions.rs5
-rw-r--r--tests/ui/suggestions/bound-suggestions.stderr10
-rw-r--r--tests/ui/suggestions/constrain-trait.fixed1
-rw-r--r--tests/ui/suggestions/constrain-trait.rs1
-rw-r--r--tests/ui/suggestions/constrain-trait.stderr4
-rw-r--r--tests/ui/suggestions/issue-109195.rs20
-rw-r--r--tests/ui/suggestions/issue-109195.stderr69
-rw-r--r--tests/ui/suggestions/lifetimes/type-param-bound-scope.fixed1
-rw-r--r--tests/ui/suggestions/lifetimes/type-param-bound-scope.rs1
-rw-r--r--tests/ui/suggestions/lifetimes/type-param-bound-scope.stderr10
-rw-r--r--tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.fixed1
-rw-r--r--tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.rs1
-rw-r--r--tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.stderr4
-rw-r--r--tests/ui/suggestions/missing-bound-in-manual-copy-impl.fixed1
-rw-r--r--tests/ui/suggestions/missing-bound-in-manual-copy-impl.rs1
-rw-r--r--tests/ui/suggestions/missing-bound-in-manual-copy-impl.stderr2
-rw-r--r--tests/ui/suggestions/missing-trait-item.fixed1
-rw-r--r--tests/ui/suggestions/missing-trait-item.rs1
-rw-r--r--tests/ui/suggestions/missing-trait-item.stderr4
-rw-r--r--tests/ui/symbol-names/basic.legacy.stderr4
-rw-r--r--tests/ui/symbol-names/issue-60925.legacy.stderr4
-rw-r--r--tests/ui/threads-sendsync/sync-send-atomics.rs2
-rw-r--r--tests/ui/traits/alias/bounds.rs2
-rw-r--r--tests/ui/traits/alias/bounds.stderr10
-rw-r--r--tests/ui/traits/alias/syntax.rs2
-rw-r--r--tests/ui/traits/bound/impl-comparison-duplicates.rs2
-rw-r--r--tests/ui/traits/bound/recursion.rs2
-rw-r--r--tests/ui/traits/composition-trivial.rs2
-rw-r--r--tests/ui/traits/cycle-generic-bound.rs2
-rw-r--r--tests/ui/traits/default-method/bound-subst4.rs2
-rw-r--r--tests/ui/traits/default-method/bound-subst4.stderr13
-rw-r--r--tests/ui/traits/default-method/mut.rs2
-rw-r--r--tests/ui/traits/impl-inherent-prefer-over-trait.rs2
-rw-r--r--tests/ui/traits/impl-inherent-prefer-over-trait.stderr12
-rw-r--r--tests/ui/traits/impl-object-overlap-issue-23853.rs2
-rw-r--r--tests/ui/traits/impl-object-overlap-issue-23853.stderr12
-rw-r--r--tests/ui/traits/impl.rs2
-rw-r--r--tests/ui/traits/impl.stderr12
-rw-r--r--tests/ui/traits/issue-38033.rs2
-rw-r--r--tests/ui/traits/issue-38033.stderr13
-rw-r--r--tests/ui/traits/issue-56488.rs2
-rw-r--r--tests/ui/traits/issue-59029-2.rs2
-rw-r--r--tests/ui/traits/issue-6128.rs2
-rw-r--r--tests/ui/traits/issue-6128.stderr14
-rw-r--r--tests/ui/traits/method-on-unbounded-type-param.rs15
-rw-r--r--tests/ui/traits/method-on-unbounded-type-param.stderr84
-rw-r--r--tests/ui/traits/multidispatch-conditional-impl-not-considered.rs2
-rw-r--r--tests/ui/traits/multidispatch-conditional-impl-not-considered.stderr10
-rw-r--r--tests/ui/traits/multidispatch-infer-convert-target.rs2
-rw-r--r--tests/ui/traits/multidispatch-infer-convert-target.stderr12
-rw-r--r--tests/ui/traits/negative-impls/negative-specializes-negative.rs2
-rw-r--r--tests/ui/traits/next-solver/normalize-region-obligations.rs9
-rw-r--r--tests/ui/traits/next-solver/normalize-type-outlives-in-param-env.rs18
-rw-r--r--tests/ui/traits/next-solver/normalize-type-outlives.rs13
-rw-r--r--tests/ui/traits/next-solver/specialization-transmute.rs2
-rw-r--r--tests/ui/traits/next-solver/specialization-transmute.stderr2
-rw-r--r--tests/ui/traits/trait-upcasting/lifetime.rs4
-rw-r--r--tests/ui/traits/trait-upcasting/lifetime.stderr25
-rw-r--r--tests/ui/traits/trait-upcasting/replace-vptr.rs4
-rw-r--r--tests/ui/traits/trait-upcasting/replace-vptr.stderr20
-rw-r--r--tests/ui/traits/use-before-def.rs2
-rw-r--r--tests/ui/traits/wf-object/reverse-order.rs2
-rw-r--r--tests/ui/trivial_casts-rpass.rs2
-rw-r--r--tests/ui/trivial_casts-rpass.stderr12
-rw-r--r--tests/ui/type-alias-impl-trait/issue-58887.rs2
-rw-r--r--tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr2
-rw-r--r--tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.fixed1
-rw-r--r--tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.rs1
-rw-r--r--tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.stderr2
-rw-r--r--tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.fixed1
-rw-r--r--tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.rs1
-rw-r--r--tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.stderr2
-rw-r--r--tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.fixed1
-rw-r--r--tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.rs1
-rw-r--r--tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.stderr2
-rw-r--r--tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.fixed2
-rw-r--r--tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.rs2
-rw-r--r--tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.stderr2
-rw-r--r--tests/ui/where-clauses/issue-50825-1.rs2
-rw-r--r--tests/ui/where-clauses/where-clause-bounds-inconsistency.rs2
-rw-r--r--tests/ui/where-clauses/where-clause-early-bound-lifetimes.rs2
-rw-r--r--tests/ui/where-clauses/where-clause-early-bound-lifetimes.stderr12
-rw-r--r--tests/ui/where-clauses/where-clause-method-substituion-rpass.rs2
-rw-r--r--tests/ui/where-clauses/where-clause-method-substituion-rpass.stderr12
-rw-r--r--tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed2
-rw-r--r--tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.rs2
-rw-r--r--tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr6
-rw-r--r--tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.fixed1
-rw-r--r--tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.rs1
-rw-r--r--tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.stderr4
-rw-r--r--triagebot.toml1
659 files changed, 7868 insertions, 2232 deletions
diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl
index e0dc227ca4c..37e45379ba9 100644
--- a/compiler/rustc_ast_lowering/messages.ftl
+++ b/compiler/rustc_ast_lowering/messages.ftl
@@ -123,9 +123,6 @@ ast_lowering_never_pattern_with_guard =
     a guard on a never pattern will never be run
     .suggestion = remove this guard
 
-ast_lowering_not_supported_for_lifetime_binder_async_closure =
-    `for<...>` binders on `async` closures are not currently supported
-
 ast_lowering_previously_used_here = previously used here
 
 ast_lowering_register1 = register `{$reg1_name}`
diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs
index 7658dfa5d5f..ec92afee47a 100644
--- a/compiler/rustc_ast_lowering/src/errors.rs
+++ b/compiler/rustc_ast_lowering/src/errors.rs
@@ -326,13 +326,6 @@ pub struct MisplacedRelaxTraitBound {
     pub span: Span,
 }
 
-#[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering_not_supported_for_lifetime_binder_async_closure)]
-pub struct NotSupportedForLifetimeBinderAsyncClosure {
-    #[primary_span]
-    pub span: Span,
-}
-
 #[derive(Diagnostic)]
 #[diag(ast_lowering_match_arm_with_no_body)]
 pub struct MatchArmWithNoBody {
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 3b00a84e67e..c4798887637 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -1,9 +1,10 @@
+use std::assert_matches::assert_matches;
+
 use super::errors::{
     AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot,
     ClosureCannotBeStatic, CoroutineTooManyParameters,
     FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody,
-    NeverPatternWithBody, NeverPatternWithGuard, NotSupportedForLifetimeBinderAsyncClosure,
-    UnderscoreExprLhsAssign,
+    NeverPatternWithBody, NeverPatternWithGuard, UnderscoreExprLhsAssign,
 };
 use super::ResolverAstLoweringExt;
 use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs};
@@ -1028,30 +1029,27 @@ impl<'hir> LoweringContext<'_, 'hir> {
         fn_decl_span: Span,
         fn_arg_span: Span,
     ) -> hir::ExprKind<'hir> {
-        if let &ClosureBinder::For { span, .. } = binder {
-            self.dcx().emit_err(NotSupportedForLifetimeBinderAsyncClosure { span });
-        }
-
         let (binder_clause, generic_params) = self.lower_closure_binder(binder);
 
+        assert_matches!(
+            coroutine_kind,
+            CoroutineKind::Async { .. },
+            "only async closures are supported currently"
+        );
+
         let body = self.with_new_scopes(fn_decl_span, |this| {
+            let inner_decl =
+                FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
+
             // Transform `async |x: u8| -> X { ... }` into
             // `|x: u8| || -> X { ... }`.
             let body_id = this.lower_body(|this| {
-                let async_ret_ty = if let FnRetTy::Ty(ty) = &decl.output {
-                    let itctx = ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock);
-                    Some(hir::FnRetTy::Return(this.lower_ty(ty, &itctx)))
-                } else {
-                    None
-                };
-
                 let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
-                    decl,
+                    &inner_decl,
                     |this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)),
                     body.span,
                     coroutine_kind,
                     hir::CoroutineSource::Closure,
-                    async_ret_ty,
                 );
 
                 let hir_id = this.lower_node_id(coroutine_kind.closure_id());
@@ -1062,15 +1060,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
             body_id
         });
 
-        let outer_decl =
-            FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
-
         let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
         // We need to lower the declaration outside the new scope, because we
         // have to conserve the state of being inside a loop condition for the
         // closure argument types.
         let fn_decl =
-            self.lower_fn_decl(&outer_decl, closure_id, fn_decl_span, FnDeclKind::Closure, None);
+            self.lower_fn_decl(&decl, closure_id, fn_decl_span, FnDeclKind::Closure, None);
 
         let c = self.arena.alloc(hir::Closure {
             def_id: self.local_def_id(closure_id),
@@ -1081,7 +1076,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
             body,
             fn_decl_span: self.lower_span(fn_decl_span),
             fn_arg_span: Some(self.lower_span(fn_arg_span)),
-            kind: hir::ClosureKind::Closure,
+            // Lower this as a `CoroutineClosure`. That will ensure that HIR typeck
+            // knows that a `FnDecl` output type like `-> &str` actually means
+            // "coroutine that returns &str", rather than directly returning a `&str`.
+            kind: hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async),
             constness: hir::Constness::NotConst,
         });
         hir::ExprKind::Closure(c)
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 987f74af0a4..7b81ed4875c 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -498,8 +498,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     }
                 }
 
-                let res =
-                    self.expect_full_res_from_use(id).map(|res| self.lower_res(res)).collect();
+                let res = self.lower_import_res(id, path.span);
                 let path = self.lower_use_path(res, &path, ParamMode::Explicit);
                 hir::ItemKind::Use(path, hir::UseKind::Single)
             }
@@ -535,7 +534,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 // for that we return the `{}` import (called the
                 // `ListStem`).
 
-                let prefix = Path { segments, span: prefix.span.to(path.span), tokens: None };
+                let span = prefix.span.to(path.span);
+                let prefix = Path { segments, span, tokens: None };
 
                 // Add all the nested `PathListItem`s to the HIR.
                 for &(ref use_tree, id) in trees {
@@ -569,9 +569,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     });
                 }
 
-                let res =
-                    self.expect_full_res_from_use(id).map(|res| self.lower_res(res)).collect();
-                let path = self.lower_use_path(res, &prefix, ParamMode::Explicit);
+                let path = if trees.is_empty() && !prefix.segments.is_empty() {
+                    // For empty lists we need to lower the prefix so it is checked for things
+                    // like stability later.
+                    let res = self.lower_import_res(id, span);
+                    self.lower_use_path(res, &prefix, ParamMode::Explicit)
+                } else {
+                    // For non-empty lists we can just drop all the data, the prefix is already
+                    // present in HIR as a part of nested imports.
+                    self.arena.alloc(hir::UsePath { res: smallvec![], segments: &[], span })
+                };
                 hir::ItemKind::Use(path, hir::UseKind::ListStem)
             }
         }
@@ -1091,7 +1098,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 body.span,
                 coroutine_kind,
                 hir::CoroutineSource::Fn,
-                None,
             );
 
             // FIXME(async_fn_track_caller): Can this be moved above?
@@ -1113,7 +1119,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
         body_span: Span,
         coroutine_kind: CoroutineKind,
         coroutine_source: hir::CoroutineSource,
-        return_type_hint: Option<hir::FnRetTy<'hir>>,
     ) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>) {
         let mut parameters: Vec<hir::Param<'_>> = Vec::new();
         let mut statements: Vec<hir::Stmt<'_>> = Vec::new();
@@ -1283,12 +1288,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
         };
         let closure_id = coroutine_kind.closure_id();
         let coroutine_expr = self.make_desugared_coroutine_expr(
-            // FIXME(async_closures): This should only move locals,
-            // and not upvars. Capturing closure upvars by ref doesn't
-            // work right now anyways, so whatever.
-            CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
+            // The default capture mode here is by-ref. Later on during upvar analysis,
+            // we will force the captured arguments to by-move, but for async closures,
+            // we want to make sure that we avoid unnecessarily moving captures, or else
+            // all async closures would default to `FnOnce` as their calling mode.
+            CaptureBy::Ref,
             closure_id,
-            return_type_hint,
+            None,
             body_span,
             desugaring_kind,
             coroutine_source,
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index c0b6922fc05..063b6627050 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -33,6 +33,7 @@
 #![allow(internal_features)]
 #![feature(rustdoc_internals)]
 #![doc(rust_logo)]
+#![feature(assert_matches)]
 #![feature(box_patterns)]
 #![feature(let_chains)]
 #![deny(rustc::untranslatable_diagnostic)]
@@ -63,7 +64,7 @@ use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
 use rustc_session::parse::{add_feature_diagnostics, feature_err};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{DesugaringKind, Span, DUMMY_SP};
-use smallvec::SmallVec;
+use smallvec::{smallvec, SmallVec};
 use std::collections::hash_map::Entry;
 use thin_vec::ThinVec;
 
@@ -298,7 +299,6 @@ enum ImplTraitPosition {
     Path,
     Variable,
     Trait,
-    AsyncBlock,
     Bound,
     Generic,
     ExternFnParam,
@@ -325,7 +325,6 @@ impl std::fmt::Display for ImplTraitPosition {
             ImplTraitPosition::Path => "paths",
             ImplTraitPosition::Variable => "the type of variable bindings",
             ImplTraitPosition::Trait => "traits",
-            ImplTraitPosition::AsyncBlock => "async blocks",
             ImplTraitPosition::Bound => "bounds",
             ImplTraitPosition::Generic => "generics",
             ImplTraitPosition::ExternFnParam => "`extern fn` parameters",
@@ -751,8 +750,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         self.resolver.get_partial_res(id).map_or(Res::Err, |pr| pr.expect_full_res())
     }
 
-    fn expect_full_res_from_use(&mut self, id: NodeId) -> impl Iterator<Item = Res<NodeId>> {
-        self.resolver.get_import_res(id).present_items()
+    fn lower_import_res(&mut self, id: NodeId, span: Span) -> SmallVec<[Res; 3]> {
+        let res = self.resolver.get_import_res(id).present_items();
+        let res: SmallVec<_> = res.map(|res| self.lower_res(res)).collect();
+        if res.is_empty() {
+            self.dcx().span_delayed_bug(span, "no resolution for an import");
+            return smallvec![Res::Err];
+        }
+        res
     }
 
     fn make_lang_item_qpath(&mut self, lang_item: hir::LangItem, span: Span) -> hir::QPath<'hir> {
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index b58ac5c3dae..76c7e530a6b 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -196,6 +196,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         p: &Path,
         param_mode: ParamMode,
     ) -> &'hir hir::UsePath<'hir> {
+        assert!((1..=3).contains(&res.len()));
         self.arena.alloc(hir::UsePath {
             res,
             segments: self.arena.alloc_from_iter(p.segments.iter().map(|segment| {
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index b0b7cc076ba..6debb3362b0 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -858,7 +858,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             use crate::session_diagnostics::CaptureVarCause::*;
             match kind {
                 hir::ClosureKind::Coroutine(_) => MoveUseInCoroutine { var_span },
-                hir::ClosureKind::Closure => MoveUseInClosure { var_span },
+                hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
+                    MoveUseInClosure { var_span }
+                }
             }
         });
 
@@ -905,7 +907,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 hir::ClosureKind::Coroutine(_) => {
                     BorrowUsePlaceCoroutine { place: desc_place, var_span, is_single_var: true }
                 }
-                hir::ClosureKind::Closure => {
+                hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
                     BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: true }
                 }
             }
@@ -1056,7 +1058,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                                     var_span,
                                     is_single_var: true,
                                 },
-                                hir::ClosureKind::Closure => BorrowUsePlaceClosure {
+                                hir::ClosureKind::Closure
+                                | hir::ClosureKind::CoroutineClosure(_) => BorrowUsePlaceClosure {
                                     place: desc_place,
                                     var_span,
                                     is_single_var: true,
@@ -1140,7 +1143,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         var_span,
                         is_single_var: false,
                     },
-                    hir::ClosureKind::Closure => {
+                    hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
                         BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: false }
                     }
                 }
@@ -1158,7 +1161,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         hir::ClosureKind::Coroutine(_) => {
                             FirstBorrowUsePlaceCoroutine { place: borrow_place_desc, var_span }
                         }
-                        hir::ClosureKind::Closure => {
+                        hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
                             FirstBorrowUsePlaceClosure { place: borrow_place_desc, var_span }
                         }
                     }
@@ -1175,7 +1178,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         hir::ClosureKind::Coroutine(_) => {
                             SecondBorrowUsePlaceCoroutine { place: desc_place, var_span }
                         }
-                        hir::ClosureKind::Closure => {
+                        hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
                             SecondBorrowUsePlaceClosure { place: desc_place, var_span }
                         }
                     }
@@ -2942,7 +2945,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     use crate::session_diagnostics::CaptureVarCause::*;
                     match kind {
                         hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span },
-                        hir::ClosureKind::Closure => BorrowUseInClosure { var_span },
+                        hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
+                            BorrowUseInClosure { var_span }
+                        }
                     }
                 });
 
@@ -2958,7 +2963,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             use crate::session_diagnostics::CaptureVarCause::*;
             match kind {
                 hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span },
-                hir::ClosureKind::Closure => BorrowUseInClosure { var_span },
+                hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
+                    BorrowUseInClosure { var_span }
+                }
             }
         });
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index b35d4e16ecc..59f3aa706ed 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -614,7 +614,7 @@ impl UseSpans<'_> {
                         PartialAssignment => AssignPartInCoroutine { path_span },
                     });
                 }
-                hir::ClosureKind::Closure => {
+                hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
                     err.subdiagnostic(match action {
                         Borrow => BorrowInClosure { path_span },
                         MatchOn | Use => UseInClosure { path_span },
@@ -1253,7 +1253,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     hir::ClosureKind::Coroutine(_) => {
                         CaptureVarCause::PartialMoveUseInCoroutine { var_span, is_partial }
                     }
-                    hir::ClosureKind::Closure => {
+                    hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
                         CaptureVarCause::PartialMoveUseInClosure { var_span, is_partial }
                     }
                 })
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 3fddf67f55b..55649ec2f16 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -1472,7 +1472,7 @@ fn suggest_ampmut<'tcx>(
 }
 
 fn is_closure_or_coroutine(ty: Ty<'_>) -> bool {
-    ty.is_closure() || ty.is_coroutine()
+    ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure()
 }
 
 /// Given a field that needs to be mutable, returns a span where the " mut " could go.
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 15e1066e983..c91b8eaab05 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -324,9 +324,13 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                 ty::BoundRegionKind::BrEnv => {
                     let def_ty = self.regioncx.universal_regions().defining_ty;
 
-                    let DefiningTy::Closure(_, args) = def_ty else {
-                        // Can't have BrEnv in functions, constants or coroutines.
-                        bug!("BrEnv outside of closure.");
+                    let closure_kind = match def_ty {
+                        DefiningTy::Closure(_, args) => args.as_closure().kind(),
+                        DefiningTy::CoroutineClosure(_, args) => args.as_coroutine_closure().kind(),
+                        _ => {
+                            // Can't have BrEnv in functions, constants or coroutines.
+                            bug!("BrEnv outside of closure.");
+                        }
                     };
                     let hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }) =
                         tcx.hir().expect_expr(self.mir_hir_id()).kind
@@ -334,21 +338,18 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                         bug!("Closure is not defined by a closure expr");
                     };
                     let region_name = self.synthesize_region_name();
-
-                    let closure_kind_ty = args.as_closure().kind_ty();
-                    let note = match closure_kind_ty.to_opt_closure_kind() {
-                        Some(ty::ClosureKind::Fn) => {
+                    let note = match closure_kind {
+                        ty::ClosureKind::Fn => {
                             "closure implements `Fn`, so references to captured variables \
                              can't escape the closure"
                         }
-                        Some(ty::ClosureKind::FnMut) => {
+                        ty::ClosureKind::FnMut => {
                             "closure implements `FnMut`, so references to captured variables \
                              can't escape the closure"
                         }
-                        Some(ty::ClosureKind::FnOnce) => {
+                        ty::ClosureKind::FnOnce => {
                             bug!("BrEnv in a `FnOnce` closure");
                         }
-                        None => bug!("Closure kind not inferred in borrow check"),
                     };
 
                     Some(RegionName {
@@ -692,7 +693,10 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                     hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
                         hir::CoroutineDesugaring::Async,
                         hir::CoroutineSource::Closure,
-                    )) => " of async closure",
+                    ))
+                    | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => {
+                        " of async closure"
+                    }
 
                     hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
                         hir::CoroutineDesugaring::Async,
@@ -719,7 +723,10 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                     hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
                         hir::CoroutineDesugaring::Gen,
                         hir::CoroutineSource::Closure,
-                    )) => " of gen closure",
+                    ))
+                    | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Gen) => {
+                        " of gen closure"
+                    }
 
                     hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
                         hir::CoroutineDesugaring::Gen,
@@ -743,7 +750,10 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                     hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
                         hir::CoroutineDesugaring::AsyncGen,
                         hir::CoroutineSource::Closure,
-                    )) => " of async gen closure",
+                    ))
+                    | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::AsyncGen) => {
+                        " of async gen closure"
+                    }
 
                     hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
                         hir::CoroutineDesugaring::AsyncGen,
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 8b5e548345c..bb64571889b 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -3,6 +3,7 @@
 #![allow(internal_features)]
 #![feature(rustdoc_internals)]
 #![doc(rust_logo)]
+#![feature(assert_matches)]
 #![feature(associated_type_bounds)]
 #![feature(box_patterns)]
 #![feature(let_chains)]
@@ -1303,7 +1304,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 // moved into the closure and subsequently used by the closure,
                 // in order to populate our used_mut set.
                 match **aggregate_kind {
-                    AggregateKind::Closure(def_id, _) | AggregateKind::Coroutine(def_id, _) => {
+                    AggregateKind::Closure(def_id, _)
+                    | AggregateKind::CoroutineClosure(def_id, _)
+                    | AggregateKind::Coroutine(def_id, _) => {
                         let def_id = def_id.expect_local();
                         let BorrowCheckResult { used_mut_upvars, .. } =
                             self.infcx.tcx.mir_borrowck(def_id);
@@ -1609,6 +1612,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     | ty::FnPtr(_)
                     | ty::Dynamic(_, _, _)
                     | ty::Closure(_, _)
+                    | ty::CoroutineClosure(_, _)
                     | ty::Coroutine(_, _)
                     | ty::CoroutineWitness(..)
                     | ty::Never
@@ -1633,7 +1637,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             return;
                         }
                     }
-                    ty::Closure(_, _) | ty::Coroutine(_, _) | ty::Tuple(_) => (),
+                    ty::Closure(..)
+                    | ty::CoroutineClosure(..)
+                    | ty::Coroutine(_, _)
+                    | ty::Tuple(_) => (),
                     ty::Bool
                     | ty::Char
                     | ty::Int(_)
diff --git a/compiler/rustc_borrowck/src/path_utils.rs b/compiler/rustc_borrowck/src/path_utils.rs
index 2d997dfadf0..4cfde47664e 100644
--- a/compiler/rustc_borrowck/src/path_utils.rs
+++ b/compiler/rustc_borrowck/src/path_utils.rs
@@ -164,7 +164,7 @@ pub(crate) fn is_upvar_field_projection<'tcx>(
     match place_ref.last_projection() {
         Some((place_base, ProjectionElem::Field(field, _ty))) => {
             let base_ty = place_base.ty(body, tcx).ty;
-            if (base_ty.is_closure() || base_ty.is_coroutine())
+            if (base_ty.is_closure() || base_ty.is_coroutine() || base_ty.is_coroutine_closure())
                 && (!by_ref || upvars[field.index()].is_by_ref())
             {
                 Some(field)
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index 52559f9039b..c97e3170166 100644
--- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -5,10 +5,13 @@ use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelega
 use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
 use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
 use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory};
-use rustc_middle::ty::GenericArgKind;
-use rustc_middle::ty::{self, TyCtxt};
-use rustc_middle::ty::{TypeFoldable, TypeVisitableExt};
+use rustc_middle::traits::query::NoSolution;
+use rustc_middle::traits::ObligationCause;
+use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
 use rustc_span::{Span, DUMMY_SP};
+use rustc_trait_selection::solve::deeply_normalize;
+use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
+use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
 
 use crate::{
     constraints::OutlivesConstraint,
@@ -33,6 +36,7 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> {
     /// our special inference variable there, we would mess that up.
     region_bound_pairs: &'a RegionBoundPairs<'tcx>,
     implicit_region_bound: ty::Region<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
     known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
     locations: Locations,
     span: Span,
@@ -47,6 +51,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
         universal_regions: &'a UniversalRegions<'tcx>,
         region_bound_pairs: &'a RegionBoundPairs<'tcx>,
         implicit_region_bound: ty::Region<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
         known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
         locations: Locations,
         span: Span,
@@ -59,6 +64,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
             universal_regions,
             region_bound_pairs,
             implicit_region_bound,
+            param_env,
             known_type_outlives_obligations,
             locations,
             span,
@@ -137,36 +143,68 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
         // Extract out various useful fields we'll need below.
         let ConstraintConversion {
             tcx,
+            infcx,
             region_bound_pairs,
             implicit_region_bound,
             known_type_outlives_obligations,
             ..
         } = *self;
 
-        let ty::OutlivesPredicate(k1, r2) = predicate;
-        match k1.unpack() {
-            GenericArgKind::Lifetime(r1) => {
-                let r1_vid = self.to_region_vid(r1);
-                let r2_vid = self.to_region_vid(r2);
-                self.add_outlives(r1_vid, r2_vid, constraint_category);
+        let mut outlives_predicates = vec![(predicate, constraint_category)];
+        for iteration in 0.. {
+            if outlives_predicates.is_empty() {
+                break;
+            }
+
+            if !self.tcx.recursion_limit().value_within_limit(iteration) {
+                bug!(
+                    "FIXME(-Znext-solver): Overflowed when processing region obligations: {outlives_predicates:#?}"
+                );
             }
 
-            GenericArgKind::Type(t1) => {
-                // we don't actually use this for anything, but
-                // the `TypeOutlives` code needs an origin.
-                let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
+            let mut next_outlives_predicates = vec![];
+            for (ty::OutlivesPredicate(k1, r2), constraint_category) in outlives_predicates {
+                match k1.unpack() {
+                    GenericArgKind::Lifetime(r1) => {
+                        let r1_vid = self.to_region_vid(r1);
+                        let r2_vid = self.to_region_vid(r2);
+                        self.add_outlives(r1_vid, r2_vid, constraint_category);
+                    }
 
-                TypeOutlives::new(
-                    &mut *self,
-                    tcx,
-                    region_bound_pairs,
-                    Some(implicit_region_bound),
-                    known_type_outlives_obligations,
-                )
-                .type_must_outlive(origin, t1, r2, constraint_category);
+                    GenericArgKind::Type(mut t1) => {
+                        // Normalize the type we receive from a `TypeOutlives` obligation
+                        // in the new trait solver.
+                        if infcx.next_trait_solver() {
+                            t1 = self.normalize_and_add_type_outlives_constraints(
+                                t1,
+                                &mut next_outlives_predicates,
+                            );
+                        }
+
+                        // we don't actually use this for anything, but
+                        // the `TypeOutlives` code needs an origin.
+                        let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
+
+                        TypeOutlives::new(
+                            &mut *self,
+                            tcx,
+                            region_bound_pairs,
+                            Some(implicit_region_bound),
+                            known_type_outlives_obligations,
+                        )
+                        .type_must_outlive(
+                            origin,
+                            t1,
+                            r2,
+                            constraint_category,
+                        );
+                    }
+
+                    GenericArgKind::Const(_) => unreachable!(),
+                }
             }
 
-            GenericArgKind::Const(_) => unreachable!(),
+            outlives_predicates = next_outlives_predicates;
         }
     }
 
@@ -232,6 +270,42 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
         debug!("add_type_test(type_test={:?})", type_test);
         self.constraints.type_tests.push(type_test);
     }
+
+    fn normalize_and_add_type_outlives_constraints(
+        &self,
+        ty: Ty<'tcx>,
+        next_outlives_predicates: &mut Vec<(
+            ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>,
+            ConstraintCategory<'tcx>,
+        )>,
+    ) -> Ty<'tcx> {
+        let result = CustomTypeOp::new(
+            |ocx| {
+                deeply_normalize(
+                    ocx.infcx.at(&ObligationCause::dummy_with_span(self.span), self.param_env),
+                    ty,
+                )
+                .map_err(|_| NoSolution)
+            },
+            "normalize type outlives obligation",
+        )
+        .fully_perform(self.infcx, self.span);
+
+        match result {
+            Ok(TypeOpOutput { output: ty, constraints, .. }) => {
+                if let Some(constraints) = constraints {
+                    assert!(
+                        constraints.member_constraints.is_empty(),
+                        "no member constraints expected from normalizing: {:#?}",
+                        constraints.member_constraints
+                    );
+                    next_outlives_predicates.extend(constraints.outlives.iter().copied());
+                }
+                ty
+            }
+            Err(_) => ty,
+        }
+    }
 }
 
 impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'tcx> {
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 d518f54fd25..2e0caf44819 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -8,8 +8,11 @@ use rustc_infer::infer::region_constraints::GenericKind;
 use rustc_infer::infer::InferCtxt;
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::traits::query::OutlivesBound;
+use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt};
-use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
+use rustc_span::{ErrorGuaranteed, DUMMY_SP};
+use rustc_trait_selection::solve::deeply_normalize;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
 use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
 use std::rc::Rc;
 use type_op::TypeOpOutput;
@@ -52,7 +55,6 @@ pub(crate) struct CreateResult<'tcx> {
 pub(crate) fn create<'tcx>(
     infcx: &InferCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
     implicit_region_bound: ty::Region<'tcx>,
     universal_regions: &Rc<UniversalRegions<'tcx>>,
     constraints: &mut MirTypeckRegionConstraints<'tcx>,
@@ -60,7 +62,6 @@ pub(crate) fn create<'tcx>(
     UniversalRegionRelationsBuilder {
         infcx,
         param_env,
-        known_type_outlives_obligations,
         implicit_region_bound,
         constraints,
         universal_regions: universal_regions.clone(),
@@ -178,7 +179,6 @@ impl UniversalRegionRelations<'_> {
 struct UniversalRegionRelationsBuilder<'this, 'tcx> {
     infcx: &'this InferCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
     universal_regions: Rc<UniversalRegions<'tcx>>,
     implicit_region_bound: ty::Region<'tcx>,
     constraints: &'this mut MirTypeckRegionConstraints<'tcx>,
@@ -222,6 +222,32 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
             self.relate_universal_regions(fr, fr_fn_body);
         }
 
+        // Normalize the assumptions we use to borrowck the program.
+        let mut constraints = vec![];
+        let mut known_type_outlives_obligations = vec![];
+        for bound in param_env.caller_bounds() {
+            let Some(mut outlives) = bound.as_type_outlives_clause() else { continue };
+
+            // In the new solver, normalize the type-outlives obligation assumptions.
+            if self.infcx.next_trait_solver() {
+                match deeply_normalize(
+                    self.infcx.at(&ObligationCause::misc(span, defining_ty_def_id), self.param_env),
+                    outlives,
+                ) {
+                    Ok(normalized_outlives) => {
+                        outlives = normalized_outlives;
+                    }
+                    Err(e) => {
+                        self.infcx.err_ctxt().report_fulfillment_errors(e);
+                    }
+                }
+            }
+
+            known_type_outlives_obligations.push(outlives);
+        }
+        let known_type_outlives_obligations =
+            self.infcx.tcx.arena.alloc_slice(&known_type_outlives_obligations);
+
         let unnormalized_input_output_tys = self
             .universal_regions
             .unnormalized_input_tys
@@ -239,7 +265,6 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
         //   the `relations` is built.
         let mut normalized_inputs_and_output =
             Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1);
-        let mut constraints = vec![];
         for ty in unnormalized_input_output_tys {
             debug!("build: input_or_output={:?}", ty);
             // We add implied bounds from both the unnormalized and normalized ty.
@@ -304,7 +329,19 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
         }
 
         for c in constraints {
-            self.push_region_constraints(c, span);
+            constraint_conversion::ConstraintConversion::new(
+                self.infcx,
+                &self.universal_regions,
+                &self.region_bound_pairs,
+                self.implicit_region_bound,
+                param_env,
+                known_type_outlives_obligations,
+                Locations::All(span),
+                span,
+                ConstraintCategory::Internal,
+                self.constraints,
+            )
+            .convert_all(c);
         }
 
         CreateResult {
@@ -313,30 +350,12 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
                 outlives: self.outlives.freeze(),
                 inverse_outlives: self.inverse_outlives.freeze(),
             }),
-            known_type_outlives_obligations: self.known_type_outlives_obligations,
+            known_type_outlives_obligations,
             region_bound_pairs: self.region_bound_pairs,
             normalized_inputs_and_output,
         }
     }
 
-    #[instrument(skip(self, data), level = "debug")]
-    fn push_region_constraints(&mut self, data: &QueryRegionConstraints<'tcx>, span: Span) {
-        debug!("constraints generated: {:#?}", data);
-
-        constraint_conversion::ConstraintConversion::new(
-            self.infcx,
-            &self.universal_regions,
-            &self.region_bound_pairs,
-            self.implicit_region_bound,
-            self.known_type_outlives_obligations,
-            Locations::All(span),
-            span,
-            ConstraintCategory::Internal,
-            self.constraints,
-        )
-        .convert_all(data);
-    }
-
     /// Update the type of a single local, which should represent
     /// either the return type of the MIR or one of its arguments. At
     /// the same time, compute and add any implied bounds that come
diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
index 59518f68ab1..a5a7ce4ea3e 100644
--- a/compiler/rustc_borrowck/src/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -7,13 +7,18 @@
 //! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
 //! contain revealed `impl Trait` values).
 
+use std::assert_matches::assert_matches;
+
 use itertools::Itertools;
-use rustc_infer::infer::BoundRegionConversionTime;
+use rustc_hir as hir;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::{BoundRegionConversionTime, RegionVariableOrigin};
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::Span;
 
-use crate::universal_regions::UniversalRegions;
+use crate::renumber::RegionCtxt;
+use crate::universal_regions::{DefiningTy, UniversalRegions};
 
 use super::{Locations, TypeChecker};
 
@@ -23,9 +28,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     #[instrument(skip(self, body), level = "debug")]
     pub(super) fn check_signature_annotation(&mut self, body: &Body<'tcx>) {
         let mir_def_id = body.source.def_id().expect_local();
+
         if !self.tcx().is_closure_or_coroutine(mir_def_id.to_def_id()) {
             return;
         }
+
         let user_provided_poly_sig = self.tcx().closure_user_provided_sig(mir_def_id);
 
         // Instantiate the canonicalized variables from user-provided signature
@@ -34,12 +41,75 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         // so that they represent the view from "inside" the closure.
         let user_provided_sig = self
             .instantiate_canonical_with_fresh_inference_vars(body.span, &user_provided_poly_sig);
-        let user_provided_sig = self.infcx.instantiate_binder_with_fresh_vars(
+        let mut user_provided_sig = self.infcx.instantiate_binder_with_fresh_vars(
             body.span,
             BoundRegionConversionTime::FnCall,
             user_provided_sig,
         );
 
+        // FIXME(async_closures): It's kind of wacky that we must apply this
+        // transformation here, since we do the same thing in HIR typeck.
+        // Maybe we could just fix up the canonicalized signature during HIR typeck?
+        if let DefiningTy::CoroutineClosure(_, args) =
+            self.borrowck_context.universal_regions.defining_ty
+        {
+            assert_matches!(
+                self.tcx().coroutine_kind(self.tcx().coroutine_for_closure(mir_def_id)),
+                Some(hir::CoroutineKind::Desugared(
+                    hir::CoroutineDesugaring::Async,
+                    hir::CoroutineSource::Closure
+                )),
+                "this needs to be modified if we're lowering non-async closures"
+            );
+            // Make sure to use the args from `DefiningTy` so the right NLL region vids are prepopulated
+            // into the type.
+            let args = args.as_coroutine_closure();
+            let tupled_upvars_ty = ty::CoroutineClosureSignature::tupled_upvars_by_closure_kind(
+                self.tcx(),
+                args.kind(),
+                Ty::new_tup(self.tcx(), user_provided_sig.inputs()),
+                args.tupled_upvars_ty(),
+                args.coroutine_captures_by_ref_ty(),
+                self.infcx.next_region_var(RegionVariableOrigin::MiscVariable(body.span), || {
+                    RegionCtxt::Unknown
+                }),
+            );
+
+            let next_ty_var = || {
+                self.infcx.next_ty_var(TypeVariableOrigin {
+                    span: body.span,
+                    kind: TypeVariableOriginKind::MiscVariable,
+                })
+            };
+            let output_ty = Ty::new_coroutine(
+                self.tcx(),
+                self.tcx().coroutine_for_closure(mir_def_id),
+                ty::CoroutineArgs::new(
+                    self.tcx(),
+                    ty::CoroutineArgsParts {
+                        parent_args: args.parent_args(),
+                        kind_ty: Ty::from_closure_kind(self.tcx(), args.kind()),
+                        return_ty: user_provided_sig.output(),
+                        tupled_upvars_ty,
+                        // For async closures, none of these can be annotated, so just fill
+                        // them with fresh ty vars.
+                        resume_ty: next_ty_var(),
+                        yield_ty: next_ty_var(),
+                        witness: next_ty_var(),
+                    },
+                )
+                .args,
+            );
+
+            user_provided_sig = self.tcx().mk_fn_sig(
+                user_provided_sig.inputs().iter().copied(),
+                output_ty,
+                user_provided_sig.c_variadic,
+                user_provided_sig.unsafety,
+                user_provided_sig.abi,
+            );
+        }
+
         let is_coroutine_with_implicit_resume_ty = self.tcx().is_coroutine(mir_def_id.to_def_id())
             && user_provided_sig.inputs().is_empty();
 
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 59c4d9a6c78..fd20d352203 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -156,10 +156,6 @@ pub(crate) fn type_check<'mir, 'tcx>(
     } = free_region_relations::create(
         infcx,
         param_env,
-        // FIXME(-Znext-solver): These are unnormalized. Normalize them.
-        infcx.tcx.arena.alloc_from_iter(
-            param_env.caller_bounds().iter().filter_map(|clause| clause.as_type_outlives_clause()),
-        ),
         implicit_region_bound,
         universal_regions,
         &mut constraints,
@@ -808,6 +804,14 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
                         }),
                     };
                 }
+                ty::CoroutineClosure(_, args) => {
+                    return match args.as_coroutine_closure().upvar_tys().get(field.index()) {
+                        Some(&ty) => Ok(ty),
+                        None => Err(FieldAccessError::OutOfRange {
+                            field_count: args.as_coroutine_closure().upvar_tys().len(),
+                        }),
+                    };
+                }
                 ty::Coroutine(_, args) => {
                     // Only prefix fields (upvars and current state) are
                     // accessible without a variant index.
@@ -1136,6 +1140,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             self.borrowck_context.universal_regions,
             self.region_bound_pairs,
             self.implicit_region_bound,
+            self.param_env,
             self.known_type_outlives_obligations,
             locations,
             locations.span(self.body),
@@ -1875,6 +1880,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     }),
                 }
             }
+            AggregateKind::CoroutineClosure(_, args) => {
+                match args.as_coroutine_closure().upvar_tys().get(field_index.as_usize()) {
+                    Some(ty) => Ok(*ty),
+                    None => Err(FieldAccessError::OutOfRange {
+                        field_count: args.as_coroutine_closure().upvar_tys().len(),
+                    }),
+                }
+            }
             AggregateKind::Array(ty) => Ok(ty),
             AggregateKind::Tuple => {
                 unreachable!("This should have been covered in check_rvalues");
@@ -2478,6 +2491,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 AggregateKind::Tuple => None,
                 AggregateKind::Closure(_, _) => None,
                 AggregateKind::Coroutine(_, _) => None,
+                AggregateKind::CoroutineClosure(_, _) => None,
             },
         }
     }
@@ -2705,7 +2719,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             // desugaring. A closure gets desugared to a struct, and
             // these extra requirements are basically like where
             // clauses on the struct.
-            AggregateKind::Closure(def_id, args) | AggregateKind::Coroutine(def_id, args) => (
+            AggregateKind::Closure(def_id, args)
+            | AggregateKind::CoroutineClosure(def_id, args)
+            | AggregateKind::Coroutine(def_id, args) => (
                 def_id,
                 self.prove_closure_bounds(
                     tcx,
@@ -2740,6 +2756,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 self.borrowck_context.universal_regions,
                 self.region_bound_pairs,
                 self.implicit_region_bound,
+                self.param_env,
                 self.known_type_outlives_obligations,
                 locations,
                 DUMMY_SP,                   // irrelevant; will be overridden.
@@ -2754,10 +2771,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         let typeck_root_args = ty::GenericArgs::identity_for_item(tcx, typeck_root_def_id);
 
         let parent_args = match tcx.def_kind(def_id) {
-            DefKind::Closure if tcx.is_coroutine(def_id.to_def_id()) => {
-                args.as_coroutine().parent_args()
+            // We don't want to dispatch on 3 different kind of closures here, so take
+            // advantage of the fact that the `parent_args` is the same length as the
+            // `typeck_root_args`.
+            DefKind::Closure => {
+                // FIXME(async_closures): It may be useful to add a debug assert here
+                // to actually call `type_of` and check the `parent_args` are the same
+                // length as the `typeck_root_args`.
+                &args[..typeck_root_args.len()]
             }
-            DefKind::Closure => args.as_closure().parent_args(),
             DefKind::InlineConst => args.as_inline_const().parent_args(),
             other => bug!("unexpected item {:?}", other),
         };
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index ae8a135f090..111eaaf60f7 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -97,6 +97,13 @@ pub enum DefiningTy<'tcx> {
     /// `ClosureArgs::coroutine_return_ty`.
     Coroutine(DefId, GenericArgsRef<'tcx>),
 
+    /// The MIR is a special kind of closure that returns coroutines.
+    ///
+    /// See the documentation on `CoroutineClosureSignature` for details
+    /// on how to construct the callable signature of the coroutine from
+    /// its args.
+    CoroutineClosure(DefId, GenericArgsRef<'tcx>),
+
     /// The MIR is a fn item with the given `DefId` and args. The signature
     /// of the function can be bound then with the `fn_sig` query.
     FnDef(DefId, GenericArgsRef<'tcx>),
@@ -119,6 +126,7 @@ impl<'tcx> DefiningTy<'tcx> {
     pub fn upvar_tys(self) -> &'tcx ty::List<Ty<'tcx>> {
         match self {
             DefiningTy::Closure(_, args) => args.as_closure().upvar_tys(),
+            DefiningTy::CoroutineClosure(_, args) => args.as_coroutine_closure().upvar_tys(),
             DefiningTy::Coroutine(_, args) => args.as_coroutine().upvar_tys(),
             DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => {
                 ty::List::empty()
@@ -131,7 +139,9 @@ impl<'tcx> DefiningTy<'tcx> {
     /// user's code.
     pub fn implicit_inputs(self) -> usize {
         match self {
-            DefiningTy::Closure(..) | DefiningTy::Coroutine(..) => 1,
+            DefiningTy::Closure(..)
+            | DefiningTy::CoroutineClosure(..)
+            | DefiningTy::Coroutine(..) => 1,
             DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => 0,
         }
     }
@@ -147,6 +157,7 @@ impl<'tcx> DefiningTy<'tcx> {
     pub fn def_id(&self) -> DefId {
         match *self {
             DefiningTy::Closure(def_id, ..)
+            | DefiningTy::CoroutineClosure(def_id, ..)
             | DefiningTy::Coroutine(def_id, ..)
             | DefiningTy::FnDef(def_id, ..)
             | DefiningTy::Const(def_id, ..)
@@ -355,6 +366,9 @@ impl<'tcx> UniversalRegions<'tcx> {
                     err.note(format!("late-bound region is {:?}", self.to_region_vid(r)));
                 });
             }
+            DefiningTy::CoroutineClosure(..) => {
+                todo!()
+            }
             DefiningTy::Coroutine(def_id, args) => {
                 let v = with_no_trimmed_paths!(
                     args[tcx.generics_of(def_id).parent_count..]
@@ -568,6 +582,9 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
                 match *defining_ty.kind() {
                     ty::Closure(def_id, args) => DefiningTy::Closure(def_id, args),
                     ty::Coroutine(def_id, args) => DefiningTy::Coroutine(def_id, args),
+                    ty::CoroutineClosure(def_id, args) => {
+                        DefiningTy::CoroutineClosure(def_id, args)
+                    }
                     ty::FnDef(def_id, args) => DefiningTy::FnDef(def_id, args),
                     _ => span_bug!(
                         tcx.def_span(self.mir_def),
@@ -623,6 +640,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id);
         let fr_args = match defining_ty {
             DefiningTy::Closure(_, args)
+            | DefiningTy::CoroutineClosure(_, args)
             | DefiningTy::Coroutine(_, args)
             | DefiningTy::InlineConst(_, args) => {
                 // In the case of closures, we rely on the fact that
@@ -702,6 +720,55 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
                 ty::Binder::dummy(inputs_and_output)
             }
 
+            // Construct the signature of the CoroutineClosure for the purposes of borrowck.
+            // This is pretty straightforward -- we:
+            // 1. first grab the `coroutine_closure_sig`,
+            // 2. compute the self type (`&`/`&mut`/no borrow),
+            // 3. flatten the tupled_input_tys,
+            // 4. construct the correct generator type to return with
+            //    `CoroutineClosureSignature::to_coroutine_given_kind_and_upvars`.
+            // Then we wrap it all up into a list of inputs and output.
+            DefiningTy::CoroutineClosure(def_id, args) => {
+                assert_eq!(self.mir_def.to_def_id(), def_id);
+                let closure_sig = args.as_coroutine_closure().coroutine_closure_sig();
+                let bound_vars = tcx.mk_bound_variable_kinds_from_iter(
+                    closure_sig
+                        .bound_vars()
+                        .iter()
+                        .chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))),
+                );
+                let br = ty::BoundRegion {
+                    var: ty::BoundVar::from_usize(bound_vars.len() - 1),
+                    kind: ty::BrEnv,
+                };
+                let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br);
+                let closure_kind = args.as_coroutine_closure().kind();
+
+                let closure_ty = tcx.closure_env_ty(
+                    Ty::new_coroutine_closure(tcx, def_id, args),
+                    closure_kind,
+                    env_region,
+                );
+
+                let inputs = closure_sig.skip_binder().tupled_inputs_ty.tuple_fields();
+                let output = closure_sig.skip_binder().to_coroutine_given_kind_and_upvars(
+                    tcx,
+                    args.as_coroutine_closure().parent_args(),
+                    tcx.coroutine_for_closure(def_id),
+                    closure_kind,
+                    env_region,
+                    args.as_coroutine_closure().tupled_upvars_ty(),
+                    args.as_coroutine_closure().coroutine_captures_by_ref_ty(),
+                );
+
+                ty::Binder::bind_with_vars(
+                    tcx.mk_type_list_from_iter(
+                        iter::once(closure_ty).chain(inputs).chain(iter::once(output)),
+                    ),
+                    bound_vars,
+                )
+            }
+
             DefiningTy::FnDef(def_id, _) => {
                 let sig = tcx.fn_sig(def_id).instantiate_identity();
                 let sig = indices.fold_to_region_vids(tcx, sig);
diff --git a/compiler/rustc_codegen_gcc/src/attributes.rs b/compiler/rustc_codegen_gcc/src/attributes.rs
index 9f361d36886..142f86b003d 100644
--- a/compiler/rustc_codegen_gcc/src/attributes.rs
+++ b/compiler/rustc_codegen_gcc/src/attributes.rs
@@ -62,9 +62,6 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
         if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
             func.add_attribute(FnAttribute::Cold);
         }
-        if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_RETURNS_TWICE) {
-            func.add_attribute(FnAttribute::ReturnsTwice);
-        }
         if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_PURE) {
             func.add_attribute(FnAttribute::Pure);
         }
diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs
index e5c0b2de4ca..25149b80201 100644
--- a/compiler/rustc_codegen_gcc/src/type_of.rs
+++ b/compiler/rustc_codegen_gcc/src/type_of.rs
@@ -87,7 +87,7 @@ fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout
         // FIXME(eddyb) producing readable type names for trait objects can result
         // in problematically distinct types due to HRTB and subtyping (see #47638).
         // ty::Dynamic(..) |
-        ty::Adt(..) | ty::Closure(..) | ty::Foreign(..) | ty::Coroutine(..) | ty::Str
+        ty::Adt(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Foreign(..) | ty::Coroutine(..) | ty::Str
             if !cx.sess().fewer_names() =>
         {
             let mut name = with_no_trimmed_paths!(layout.ty.to_string());
diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl
index d5bc04f594d..d14fe0299e6 100644
--- a/compiler/rustc_codegen_llvm/messages.ftl
+++ b/compiler/rustc_codegen_llvm/messages.ftl
@@ -28,6 +28,8 @@ codegen_llvm_invalid_minimum_alignment_not_power_of_two =
 codegen_llvm_invalid_minimum_alignment_too_large =
     invalid minimum global alignment: {$align} is too large
 
+codegen_llvm_invalid_target_feature_prefix = target feature `{$feature}` must begin with a `+` or `-`"
+
 codegen_llvm_load_bitcode = failed to load bitcode of module "{$name}"
 codegen_llvm_load_bitcode_with_llvm_err = failed to load bitcode of module "{$name}": {$llvm_err}
 
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 0a7ea599431..07c83f1aa08 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -356,9 +356,6 @@ pub fn from_fn_attrs<'ll, 'tcx>(
     if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
         to_add.push(AttributeKind::Cold.create_attr(cx.llcx));
     }
-    if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_RETURNS_TWICE) {
-        to_add.push(AttributeKind::ReturnsTwice.create_attr(cx.llcx));
-    }
     if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_PURE) {
         to_add.push(MemoryEffects::ReadOnly.create_attr(cx.llcx));
     }
diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs
index e839d278bea..587c5e9e8d2 100644
--- a/compiler/rustc_codegen_llvm/src/errors.rs
+++ b/compiler/rustc_codegen_llvm/src/errors.rs
@@ -253,3 +253,9 @@ pub struct MismatchedDataLayout<'a> {
     pub llvm_target: &'a str,
     pub llvm_layout: &'a str,
 }
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_invalid_target_feature_prefix)]
+pub(crate) struct InvalidTargetFeaturePrefix<'a> {
+    pub feature: &'a str,
+}
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 4ad44a42738..d0044086c61 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -184,7 +184,6 @@ pub enum AttributeKind {
     SanitizeMemory = 22,
     NonLazyBind = 23,
     OptimizeNone = 24,
-    ReturnsTwice = 25,
     ReadNone = 26,
     SanitizeHWAddress = 28,
     WillReturn = 29,
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 99f4488ac0f..4bb400b1879 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -1,7 +1,7 @@
 use crate::back::write::create_informational_target_machine;
 use crate::errors::{
-    PossibleFeature, TargetFeatureDisableOrEnable, UnknownCTargetFeature,
-    UnknownCTargetFeaturePrefix, UnstableCTargetFeature,
+    InvalidTargetFeaturePrefix, PossibleFeature, TargetFeatureDisableOrEnable,
+    UnknownCTargetFeature, UnknownCTargetFeaturePrefix, UnstableCTargetFeature,
 };
 use crate::llvm;
 use libc::c_int;
@@ -511,7 +511,7 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
         sess.target
             .features
             .split(',')
-            .filter(|v| !v.is_empty() && backend_feature_name(v).is_some())
+            .filter(|v| !v.is_empty() && backend_feature_name(sess, v).is_some())
             .map(String::from),
     );
 
@@ -535,7 +535,7 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
                 }
             };
 
-            let feature = backend_feature_name(s)?;
+            let feature = backend_feature_name(sess, s)?;
             // Warn against use of LLVM specific feature names and unstable features on the CLI.
             if diagnostics {
                 let feature_state = supported_features.iter().find(|&&(v, _)| v == feature);
@@ -611,11 +611,11 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
 /// Returns a feature name for the given `+feature` or `-feature` string.
 ///
 /// Only allows features that are backend specific (i.e. not [`RUSTC_SPECIFIC_FEATURES`].)
-fn backend_feature_name(s: &str) -> Option<&str> {
+fn backend_feature_name<'a>(sess: &Session, s: &'a str) -> Option<&'a str> {
     // features must start with a `+` or `-`.
-    let feature = s.strip_prefix(&['+', '-'][..]).unwrap_or_else(|| {
-        bug!("target feature `{}` must begin with a `+` or `-`", s);
-    });
+    let feature = s
+        .strip_prefix(&['+', '-'][..])
+        .unwrap_or_else(|| sess.dcx().emit_fatal(InvalidTargetFeaturePrefix { feature: s }));
     // Rustc-specific feature requests like `+crt-static` or `-crt-static`
     // are not passed down to LLVM.
     if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs
index f796ce0990f..f7630719368 100644
--- a/compiler/rustc_codegen_llvm/src/mono_item.rs
+++ b/compiler/rustc_codegen_llvm/src/mono_item.rs
@@ -123,6 +123,17 @@ impl CodegenCx<'_, '_> {
             return false;
         }
 
+        // Match clang by only supporting COFF and ELF for now.
+        if self.tcx.sess.target.is_like_osx {
+            return false;
+        }
+
+        // With pie relocation model calls of functions defined in the translation
+        // unit can use copy relocations.
+        if self.tcx.sess.relocation_model() == RelocModel::Pie && !is_declaration {
+            return true;
+        }
+
         // Thread-local variables generally don't support copy relocations.
         let is_thread_local_var = llvm::LLVMIsAGlobalVariable(llval)
             .is_some_and(|v| llvm::LLVMIsThreadLocal(v) == llvm::True);
@@ -130,18 +141,12 @@ impl CodegenCx<'_, '_> {
             return false;
         }
 
-        // Match clang by only supporting COFF and ELF for now.
-        if self.tcx.sess.target.is_like_osx {
-            return false;
+        // Respect the direct-access-external-data to override default behavior if present.
+        if let Some(direct) = self.tcx.sess.direct_access_external_data() {
+            return direct;
         }
 
         // Static relocation model should force copy relocations everywhere.
-        if self.tcx.sess.relocation_model() == RelocModel::Static {
-            return true;
-        }
-
-        // With pie relocation model calls of functions defined in the translation
-        // unit can use copy relocations.
-        self.tcx.sess.relocation_model() == RelocModel::Pie && !is_declaration
+        self.tcx.sess.relocation_model() == RelocModel::Static
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs
index e88f4217c9d..219c7025311 100644
--- a/compiler/rustc_codegen_llvm/src/type_of.rs
+++ b/compiler/rustc_codegen_llvm/src/type_of.rs
@@ -33,7 +33,7 @@ fn uncached_llvm_type<'a, 'tcx>(
         // FIXME(eddyb) producing readable type names for trait objects can result
         // in problematically distinct types due to HRTB and subtyping (see #47638).
         // ty::Dynamic(..) |
-        ty::Adt(..) | ty::Closure(..) | ty::Foreign(..) | ty::Coroutine(..) | ty::Str
+        ty::Adt(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Foreign(..) | ty::Coroutine(..) | ty::Str
             // For performance reasons we use names only when emitting LLVM IR.
             if !cx.sess().fewer_names() =>
         {
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 4211f875dd0..9b24339d255 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -1810,7 +1810,7 @@ impl Translate for SharedEmitter {
 }
 
 impl Emitter for SharedEmitter {
-    fn emit_diagnostic(&mut self, diag: &rustc_errors::Diagnostic) {
+    fn emit_diagnostic(&mut self, diag: rustc_errors::Diagnostic) {
         let args: FxHashMap<DiagnosticArgName, DiagnosticArgValue> =
             diag.args().map(|(name, arg)| (name.clone(), arg.clone())).collect();
         drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index 47b1b080119..b387d0b2258 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -103,9 +103,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
         match name {
             sym::cold => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD,
             sym::rustc_allocator => codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR,
-            sym::ffi_returns_twice => {
-                codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE
-            }
             sym::ffi_pure => codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE,
             sym::ffi_const => codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST,
             sym::rustc_nounwind => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND,
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 4f9f70648bd..5bd7442822a 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -398,7 +398,9 @@ fn push_debuginfo_type_name<'tcx>(
             // processing
             visited.remove(&t);
         }
-        ty::Closure(def_id, args) | ty::Coroutine(def_id, args, ..) => {
+        ty::Closure(def_id, args)
+        | ty::CoroutineClosure(def_id, args)
+        | ty::Coroutine(def_id, args, ..) => {
             // Name will be "{closure_env#0}<T1, T2, ...>", "{coroutine_env#0}<T1, T2, ...>", or
             // "{async_fn_env#0}<T1, T2, ...>", etc.
             // In the case of cpp-like debuginfo, the name additionally gets wrapped inside of
@@ -768,6 +770,8 @@ fn push_closure_or_coroutine_name<'tcx>(
 
     // Truncate the args to the length of the above generics. This will cut off
     // anything closure- or coroutine-specific.
+    // FIXME(async_closures): This is probably not going to be correct w.r.t.
+    // multiple coroutine flavors. Maybe truncate to (parent + 1)?
     let args = args.truncate_to(tcx, generics);
     push_generic_params_internal(tcx, args, enclosing_fn_def_id, output, visited);
 }
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 6a92ed9717d..a2d0f1c5583 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -1,5 +1,3 @@
-use std::mem;
-
 use either::{Left, Right};
 
 use rustc_hir::def::DefKind;
@@ -24,12 +22,13 @@ use crate::interpret::{
 };
 
 // Returns a pointer to where the result lives
+#[instrument(level = "trace", skip(ecx, body), ret)]
 fn eval_body_using_ecx<'mir, 'tcx>(
     ecx: &mut CompileTimeEvalContext<'mir, 'tcx>,
     cid: GlobalId<'tcx>,
     body: &'mir mir::Body<'tcx>,
 ) -> InterpResult<'tcx, MPlaceTy<'tcx>> {
-    debug!("eval_body_using_ecx: {:?}, {:?}", cid, ecx.param_env);
+    trace!(?ecx.param_env);
     let tcx = *ecx.tcx;
     assert!(
         cid.promoted.is_some()
@@ -75,11 +74,8 @@ fn eval_body_using_ecx<'mir, 'tcx>(
             None => InternKind::Constant,
         }
     };
-    let check_alignment = mem::replace(&mut ecx.machine.check_alignment, CheckAlignment::No); // interning doesn't need to respect alignment
     intern_const_alloc_recursive(ecx, intern_kind, &ret)?;
-    ecx.machine.check_alignment = check_alignment;
 
-    debug!("eval_body_using_ecx done: {:?}", ret);
     Ok(ret)
 }
 
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index 12544f5b029..5c2bf4626c4 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -172,6 +172,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
         | ty::Infer(_)
         // FIXME(oli-obk): we can probably encode closures just like structs
         | ty::Closure(..)
+        | ty::CoroutineClosure(..)
         | ty::Coroutine(..)
         | ty::CoroutineWitness(..) => Err(ValTreeCreationError::NonSupportedType),
     }
@@ -301,6 +302,7 @@ pub fn valtree_to_const_value<'tcx>(
         | ty::Placeholder(..)
         | ty::Infer(_)
         | ty::Closure(..)
+        | ty::CoroutineClosure(..)
         | ty::Coroutine(..)
         | ty::CoroutineWitness(..)
         | ty::FnPtr(_)
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index c14bd142efa..dd989ab80fd 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -1007,6 +1007,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 | ty::CoroutineWitness(..)
                 | ty::Array(..)
                 | ty::Closure(..)
+                | ty::CoroutineClosure(..)
                 | ty::Never
                 | ty::Error(_) => true,
 
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index 751fbfacaad..38e7843761b 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -41,13 +41,12 @@ pub trait CompileTimeMachine<'mir, 'tcx: 'mir, T> = Machine<
 /// allocation is interned immutably; if it is `Mutability::Mut`, then the allocation *must be*
 /// already mutable (as a sanity check).
 ///
-/// `recursive_alloc` is called for all recursively encountered allocations.
+/// Returns an iterator over all relocations referred to by this allocation.
 fn intern_shallow<'rt, 'mir, 'tcx, T, M: CompileTimeMachine<'mir, 'tcx, T>>(
     ecx: &'rt mut InterpCx<'mir, 'tcx, M>,
     alloc_id: AllocId,
     mutability: Mutability,
-    mut recursive_alloc: impl FnMut(&InterpCx<'mir, 'tcx, M>, CtfeProvenance),
-) -> Result<(), ()> {
+) -> Result<impl Iterator<Item = CtfeProvenance> + 'tcx, ()> {
     trace!("intern_shallow {:?}", alloc_id);
     // remove allocation
     let Some((_kind, mut alloc)) = ecx.memory.alloc_map.remove(&alloc_id) else {
@@ -65,14 +64,10 @@ fn intern_shallow<'rt, 'mir, 'tcx, T, M: CompileTimeMachine<'mir, 'tcx, T>>(
             assert_eq!(alloc.mutability, Mutability::Mut);
         }
     }
-    // record child allocations
-    for &(_, prov) in alloc.provenance().ptrs().iter() {
-        recursive_alloc(ecx, prov);
-    }
     // link the alloc id to the actual allocation
     let alloc = ecx.tcx.mk_const_alloc(alloc);
     ecx.tcx.set_alloc_id_memory(alloc_id, alloc);
-    Ok(())
+    Ok(alloc.0.0.provenance().ptrs().iter().map(|&(_, prov)| prov))
 }
 
 /// How a constant value should be interned.
@@ -128,12 +123,16 @@ pub fn intern_const_alloc_recursive<
         }
     };
 
-    // Initialize recursive interning.
+    // Intern the base allocation, and initialize todo list for recursive interning.
     let base_alloc_id = ret.ptr().provenance.unwrap().alloc_id();
-    let mut todo = vec![(base_alloc_id, base_mutability)];
+    // First we intern the base allocation, as it requires a different mutability.
+    // This gives us the initial set of nested allocations, which will then all be processed
+    // recursively in the loop below.
+    let mut todo: Vec<_> =
+        intern_shallow(ecx, base_alloc_id, base_mutability).unwrap().map(|prov| prov).collect();
     // We need to distinguish "has just been interned" from "was already in `tcx`",
     // so we track this in a separate set.
-    let mut just_interned = FxHashSet::default();
+    let mut just_interned: FxHashSet<_> = std::iter::once(base_alloc_id).collect();
     // Whether we encountered a bad mutable pointer.
     // We want to first report "dangling" and then "mutable", so we need to delay reporting these
     // errors.
@@ -147,52 +146,56 @@ pub fn intern_const_alloc_recursive<
     // raw pointers, so we cannot rely on validation to catch them -- and since interning runs
     // before validation, and interning doesn't know the type of anything, this means we can't show
     // better errors. Maybe we should consider doing validation before interning in the future.
-    while let Some((alloc_id, mutability)) = todo.pop() {
+    while let Some(prov) = todo.pop() {
+        let alloc_id = prov.alloc_id();
+        // Crucially, we check this *before* checking whether the `alloc_id`
+        // has already been interned. The point of this check is to ensure that when
+        // there are multiple pointers to the same allocation, they are *all* immutable.
+        // Therefore it would be bad if we only checked the first pointer to any given
+        // allocation.
+        // (It is likely not possible to actually have multiple pointers to the same allocation,
+        // so alternatively we could also check that and ICE if there are multiple such pointers.)
+        if intern_kind != InternKind::Promoted
+            && inner_mutability == Mutability::Not
+            && !prov.immutable()
+        {
+            if ecx.tcx.try_get_global_alloc(alloc_id).is_some()
+                && !just_interned.contains(&alloc_id)
+            {
+                // This is a pointer to some memory from another constant. We encounter mutable
+                // pointers to such memory since we do not always track immutability through
+                // these "global" pointers. Allowing them is harmless; the point of these checks
+                // during interning is to justify why we intern the *new* allocations immutably,
+                // so we can completely ignore existing allocations. We also don't need to add
+                // this to the todo list, since after all it is already interned.
+                continue;
+            }
+            // Found a mutable pointer inside a const where inner allocations should be
+            // immutable. We exclude promoteds from this, since things like `&mut []` and
+            // `&None::<Cell<i32>>` lead to promotion that can produce mutable pointers. We rely
+            // on the promotion analysis not screwing up to ensure that it is sound to intern
+            // promoteds as immutable.
+            found_bad_mutable_pointer = true;
+        }
         if ecx.tcx.try_get_global_alloc(alloc_id).is_some() {
             // Already interned.
             debug_assert!(!ecx.memory.alloc_map.contains_key(&alloc_id));
             continue;
         }
         just_interned.insert(alloc_id);
-        intern_shallow(ecx, alloc_id, mutability, |ecx, prov| {
-            let alloc_id = prov.alloc_id();
-            if intern_kind != InternKind::Promoted
-                && inner_mutability == Mutability::Not
-                && !prov.immutable()
-            {
-                if ecx.tcx.try_get_global_alloc(alloc_id).is_some()
-                    && !just_interned.contains(&alloc_id)
-                {
-                    // This is a pointer to some memory from another constant. We encounter mutable
-                    // pointers to such memory since we do not always track immutability through
-                    // these "global" pointers. Allowing them is harmless; the point of these checks
-                    // during interning is to justify why we intern the *new* allocations immutably,
-                    // so we can completely ignore existing allocations. We also don't need to add
-                    // this to the todo list, since after all it is already interned.
-                    return;
-                }
-                // Found a mutable pointer inside a const where inner allocations should be
-                // immutable. We exclude promoteds from this, since things like `&mut []` and
-                // `&None::<Cell<i32>>` lead to promotion that can produce mutable pointers. We rely
-                // on the promotion analysis not screwing up to ensure that it is sound to intern
-                // promoteds as immutable.
-                found_bad_mutable_pointer = true;
-            }
-            // We always intern with `inner_mutability`, and furthermore we ensured above that if
-            // that is "immutable", then there are *no* mutable pointers anywhere in the newly
-            // interned memory -- justifying that we can indeed intern immutably. However this also
-            // means we can *not* easily intern immutably here if `prov.immutable()` is true and
-            // `inner_mutability` is `Mut`: there might be other pointers to that allocation, and
-            // we'd have to somehow check that they are *all* immutable before deciding that this
-            // allocation can be made immutable. In the future we could consider analyzing all
-            // pointers before deciding which allocations can be made immutable; but for now we are
-            // okay with losing some potential for immutability here. This can anyway only affect
-            // `static mut`.
-            todo.push((alloc_id, inner_mutability));
-        })
-        .map_err(|()| {
+        // We always intern with `inner_mutability`, and furthermore we ensured above that if
+        // that is "immutable", then there are *no* mutable pointers anywhere in the newly
+        // interned memory -- justifying that we can indeed intern immutably. However this also
+        // means we can *not* easily intern immutably here if `prov.immutable()` is true and
+        // `inner_mutability` is `Mut`: there might be other pointers to that allocation, and
+        // we'd have to somehow check that they are *all* immutable before deciding that this
+        // allocation can be made immutable. In the future we could consider analyzing all
+        // pointers before deciding which allocations can be made immutable; but for now we are
+        // okay with losing some potential for immutability here. This can anyway only affect
+        // `static mut`.
+        todo.extend(intern_shallow(ecx, alloc_id, inner_mutability).map_err(|()| {
             ecx.tcx.dcx().emit_err(DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind })
-        })?;
+        })?);
     }
     if found_bad_mutable_pointer {
         return Err(ecx
@@ -220,13 +223,13 @@ pub fn intern_const_alloc_for_constprop<
         return Ok(());
     }
     // Move allocation to `tcx`.
-    intern_shallow(ecx, alloc_id, Mutability::Not, |_ecx, _| {
+    for _ in intern_shallow(ecx, alloc_id, Mutability::Not).map_err(|()| err_ub!(DeadLocal))? {
         // We are not doing recursive interning, so we don't currently support provenance.
         // (If this assertion ever triggers, we should just implement a
         // proper recursive interning loop -- or just call `intern_const_alloc_recursive`.
         panic!("`intern_const_alloc_for_constprop` called on allocation with nested provenance")
-    })
-    .map_err(|()| err_ub!(DeadLocal).into())
+    }
+    Ok(())
 }
 
 impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>>
@@ -247,15 +250,14 @@ impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>>
         let dest = self.allocate(layout, MemoryKind::Stack)?;
         f(self, &dest.clone().into())?;
         let alloc_id = dest.ptr().provenance.unwrap().alloc_id(); // this was just allocated, it must have provenance
-        intern_shallow(self, alloc_id, Mutability::Not, |ecx, prov| {
+        for prov in intern_shallow(self, alloc_id, Mutability::Not).unwrap() {
             // We are not doing recursive interning, so we don't currently support provenance.
             // (If this assertion ever triggers, we should just implement a
             // proper recursive interning loop -- or just call `intern_const_alloc_recursive`.
-            if !ecx.tcx.try_get_global_alloc(prov.alloc_id()).is_some() {
+            if !self.tcx.try_get_global_alloc(prov.alloc_id()).is_some() {
                 panic!("`intern_with_temp_alloc` with nested allocations");
             }
-        })
-        .unwrap();
+        }
         Ok(alloc_id)
     }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 1e9e7d94596..7991f90b815 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -85,6 +85,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
             | ty::FnPtr(_)
             | ty::Dynamic(_, _, _)
             | ty::Closure(_, _)
+            | ty::CoroutineClosure(_, _)
             | ty::Coroutine(_, _)
             | ty::CoroutineWitness(..)
             | ty::Never
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index b7ffb4a16fc..85a2e4778d2 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -545,6 +545,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             ty::InstanceDef::VTableShim(..)
             | ty::InstanceDef::ReifyShim(..)
             | ty::InstanceDef::ClosureOnceShim { .. }
+            | ty::InstanceDef::ConstructCoroutineInClosureShim { .. }
+            | ty::InstanceDef::CoroutineKindShim { .. }
             | ty::InstanceDef::FnPtrShim(..)
             | ty::InstanceDef::DropGlue(..)
             | ty::InstanceDef::CloneShim(..)
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index b5cd3259520..90cde81c018 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -644,6 +644,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
             | ty::Str
             | ty::Dynamic(..)
             | ty::Closure(..)
+            | ty::CoroutineClosure(..)
             | ty::Coroutine(..) => Ok(false),
             // Some types only occur during typechecking, they have no layout.
             // We should not see them here and we could not check them anyway.
@@ -992,10 +993,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             // Complain about any other kind of error -- those are bad because we'd like to
             // report them in a way that shows *where* in the value the issue lies.
             Err(err) => {
-                bug!(
-                    "Unexpected Undefined Behavior error during validation: {}",
-                    self.format_error(err)
-                );
+                bug!("Unexpected error during validation: {}", self.format_error(err));
             }
         }
     }
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 89c65d92325..5ff81615552 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -20,7 +20,7 @@ use std::mem;
 use std::ops::{ControlFlow, Deref};
 
 use super::ops::{self, NonConstOp, Status};
-use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop, NeedsNonConstDrop};
+use super::qualifs::{self, HasMutInterior, NeedsDrop, NeedsNonConstDrop};
 use super::resolver::FlowSensitiveAnalysis;
 use super::{ConstCx, Qualif};
 use crate::const_eval::is_unstable_const_fn;
@@ -149,37 +149,10 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
 
         let return_loc = ccx.body.terminator_loc(return_block);
 
-        let custom_eq = match ccx.const_kind() {
-            // We don't care whether a `const fn` returns a value that is not structurally
-            // matchable. Functions calls are opaque and always use type-based qualification, so
-            // this value should never be used.
-            hir::ConstContext::ConstFn => true,
-
-            // If we know that all values of the return type are structurally matchable, there's no
-            // need to run dataflow.
-            // Opaque types do not participate in const generics or pattern matching, so we can safely count them out.
-            _ if ccx.body.return_ty().has_opaque_types()
-                || !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) =>
-            {
-                false
-            }
-
-            hir::ConstContext::Const { .. } | hir::ConstContext::Static(_) => {
-                let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx)
-                    .into_engine(ccx.tcx, ccx.body)
-                    .iterate_to_fixpoint()
-                    .into_results_cursor(ccx.body);
-
-                cursor.seek_after_primary_effect(return_loc);
-                cursor.get().contains(RETURN_PLACE)
-            }
-        };
-
         ConstQualifs {
             needs_drop: self.needs_drop(ccx, RETURN_PLACE, return_loc),
             needs_non_const_drop: self.needs_non_const_drop(ccx, RETURN_PLACE, return_loc),
             has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc),
-            custom_eq,
             tainted_by_errors,
         }
     }
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
index 1efa52df581..67fef208079 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -10,7 +10,7 @@ use rustc_middle::mir::*;
 use rustc_middle::traits::BuiltinImplSource;
 use rustc_middle::ty::{self, AdtDef, GenericArgsRef, Ty};
 use rustc_trait_selection::traits::{
-    self, ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext,
+    ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext,
 };
 
 use super::ConstCx;
@@ -24,7 +24,6 @@ pub fn in_any_value_of_ty<'tcx>(
         has_mut_interior: HasMutInterior::in_any_value_of_ty(cx, ty),
         needs_drop: NeedsDrop::in_any_value_of_ty(cx, ty),
         needs_non_const_drop: NeedsNonConstDrop::in_any_value_of_ty(cx, ty),
-        custom_eq: CustomEq::in_any_value_of_ty(cx, ty),
         tainted_by_errors,
     }
 }
@@ -213,35 +212,6 @@ impl Qualif for NeedsNonConstDrop {
     }
 }
 
-/// A constant that cannot be used as part of a pattern in a `match` expression.
-pub struct CustomEq;
-
-impl Qualif for CustomEq {
-    const ANALYSIS_NAME: &'static str = "flow_custom_eq";
-
-    fn in_qualifs(qualifs: &ConstQualifs) -> bool {
-        qualifs.custom_eq
-    }
-
-    fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
-        // If *any* component of a composite data type does not implement `Structural{Partial,}Eq`,
-        // we know that at least some values of that type are not structural-match. I say "some"
-        // because that component may be part of an enum variant (e.g.,
-        // `Option::<NonStructuralMatchTy>::Some`), in which case some values of this type may be
-        // structural-match (`Option::None`).
-        traits::search_for_structural_match_violation(cx.body.span, cx.tcx, ty).is_some()
-    }
-
-    fn in_adt_inherently<'tcx>(
-        cx: &ConstCx<'_, 'tcx>,
-        def: AdtDef<'tcx>,
-        args: GenericArgsRef<'tcx>,
-    ) -> bool {
-        let ty = Ty::new_adt(cx.tcx, def, args);
-        !ty.is_structural_eq_shallow(cx.tcx)
-    }
-}
-
 // FIXME: Use `mir::visit::Visitor` for the `in_*` functions if/when it supports early return.
 
 /// Returns `true` if this `Rvalue` contains qualif `Q`.
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 21bdb66a276..c4542aaa7b2 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -58,6 +58,7 @@ impl<'tcx> MirPass<'tcx> for Validator {
             let body_abi = match body_ty.kind() {
                 ty::FnDef(..) => body_ty.fn_sig(tcx).abi(),
                 ty::Closure(..) => Abi::RustCall,
+                ty::CoroutineClosure(..) => Abi::RustCall,
                 ty::Coroutine(..) => Abi::Rust,
                 _ => {
                     span_bug!(body.span, "unexpected body ty: {:?} phase {:?}", body_ty, mir_phase)
@@ -665,6 +666,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                         };
                         check_equal(self, location, f_ty);
                     }
+                    ty::CoroutineClosure(_, args) => {
+                        let args = args.as_coroutine_closure();
+                        let Some(&f_ty) = args.upvar_tys().get(f.as_usize()) else {
+                            fail_out_of_bounds(self, location);
+                            return;
+                        };
+                        check_equal(self, location, f_ty);
+                    }
                     &ty::Coroutine(def_id, args) => {
                         let f_ty = if let Some(var) = parent_ty.variant_index {
                             let gen_body = if def_id == self.body.source.def_id() {
@@ -861,6 +870,20 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                         }
                     }
                 }
+                AggregateKind::CoroutineClosure(_, args) => {
+                    let upvars = args.as_coroutine_closure().upvar_tys();
+                    if upvars.len() != fields.len() {
+                        self.fail(
+                            location,
+                            "coroutine-closure has the wrong number of initialized fields",
+                        );
+                    }
+                    for (src, dest) in std::iter::zip(fields, upvars) {
+                        if !self.mir_assign_valid_types(src.ty(self.body, self.tcx), dest) {
+                            self.fail(location, "coroutine-closure field has the wrong type");
+                        }
+                    }
+                }
             },
             Rvalue::Ref(_, BorrowKind::Fake, _) => {
                 if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs
index 976e42ad768..2b80623ab45 100644
--- a/compiler/rustc_const_eval/src/util/type_name.rs
+++ b/compiler/rustc_const_eval/src/util/type_name.rs
@@ -51,6 +51,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
             | ty::FnDef(def_id, args)
             | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. })
             | ty::Closure(def_id, args)
+            | ty::CoroutineClosure(def_id, args)
             | ty::Coroutine(def_id, args) => self.print_def_path(def_id, args),
             ty::Foreign(def_id) => self.print_def_path(def_id, &[]),
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0724.md b/compiler/rustc_error_codes/src/error_codes/E0724.md
index 70578acbe0d..bcefd0a7479 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0724.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0724.md
@@ -1,9 +1,12 @@
+#### Note: this error code is no longer emitted by the compiler.
+
+
 `#[ffi_returns_twice]` was used on something other than a foreign function
 declaration.
 
 Erroneous code example:
 
-```compile_fail,E0724
+```compile_fail
 #![feature(ffi_returns_twice)]
 #![crate_type = "lib"]
 
@@ -15,7 +18,7 @@ pub fn foo() {}
 For example, we might correct the previous example by declaring
 the function inside of an `extern` block.
 
-```
+```compile_fail
 #![feature(ffi_returns_twice)]
 
 extern "C" {
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 8fd7c576479..d212e18b4cd 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -378,7 +378,7 @@ impl From<Cow<'static, str>> for DiagnosticMessage {
     }
 }
 
-/// A workaround for "good path" ICEs when formatting types in disabled lints.
+/// A workaround for good_path_delayed_bug ICEs when formatting types in disabled lints.
 ///
 /// Delays formatting until `.into(): DiagnosticMessage` is used.
 pub struct DelayDm<F>(pub F);
diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
index 949f52ef6b5..37f568f12a7 100644
--- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
+++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
@@ -44,15 +44,15 @@ impl Translate for AnnotateSnippetEmitter {
 
 impl Emitter for AnnotateSnippetEmitter {
     /// The entry point for the diagnostics generation
-    fn emit_diagnostic(&mut self, diag: &Diagnostic) {
+    fn emit_diagnostic(&mut self, mut diag: Diagnostic) {
         let fluent_args = to_fluent_args(diag.args());
 
-        let mut children = diag.children.clone();
-        let (mut primary_span, suggestions) = self.primary_span_formatted(diag, &fluent_args);
+        let mut suggestions = diag.suggestions.unwrap_or(vec![]);
+        self.primary_span_formatted(&mut diag.span, &mut suggestions, &fluent_args);
 
         self.fix_multispans_in_extern_macros_and_render_macro_backtrace(
-            &mut primary_span,
-            &mut children,
+            &mut diag.span,
+            &mut diag.children,
             &diag.level,
             self.macro_backtrace,
         );
@@ -62,9 +62,9 @@ impl Emitter for AnnotateSnippetEmitter {
             &diag.messages,
             &fluent_args,
             &diag.code,
-            &primary_span,
-            &children,
-            suggestions,
+            &diag.span,
+            &diag.children,
+            &suggestions,
         );
     }
 
@@ -85,7 +85,11 @@ fn source_string(file: Lrc<SourceFile>, line: &Line) -> String {
 /// Maps `Diagnostic::Level` to `snippet::AnnotationType`
 fn annotation_type_for_level(level: Level) -> AnnotationType {
     match level {
-        Level::Bug | Level::DelayedBug(_) | Level::Fatal | Level::Error => AnnotationType::Error,
+        Level::Bug
+        | Level::Fatal
+        | Level::Error
+        | Level::DelayedBug
+        | Level::GoodPathDelayedBug => AnnotationType::Error,
         Level::ForceWarning(_) | Level::Warning => AnnotationType::Warning,
         Level::Note | Level::OnceNote => AnnotationType::Note,
         Level::Help | Level::OnceHelp => AnnotationType::Help,
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 8ad4925cff2..1763c355069 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -1,8 +1,7 @@
 use crate::snippet::Style;
 use crate::{
-    CodeSuggestion, DelayedBugKind, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee,
-    ErrCode, Level, MultiSpan, SubdiagnosticMessage, Substitution, SubstitutionPart,
-    SuggestionStyle,
+    CodeSuggestion, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, ErrCode, Level,
+    MultiSpan, SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle,
 };
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_error_messages::fluent_value_from_str_list_sep_by_and;
@@ -235,19 +234,16 @@ impl Diagnostic {
 
     pub fn is_error(&self) -> bool {
         match self.level {
-            Level::Bug
-            | Level::DelayedBug(DelayedBugKind::Normal)
-            | Level::Fatal
-            | Level::Error
-            | Level::FailureNote => true,
+            Level::Bug | Level::Fatal | Level::Error | Level::DelayedBug => true,
 
-            Level::ForceWarning(_)
+            Level::GoodPathDelayedBug
+            | Level::ForceWarning(_)
             | Level::Warning
-            | Level::DelayedBug(DelayedBugKind::GoodPath)
             | Level::Note
             | Level::OnceNote
             | Level::Help
             | Level::OnceHelp
+            | Level::FailureNote
             | Level::Allow
             | Level::Expect(_) => false,
         }
@@ -306,11 +302,11 @@ impl Diagnostic {
     #[track_caller]
     pub fn downgrade_to_delayed_bug(&mut self) {
         assert!(
-            self.is_error(),
+            matches!(self.level, Level::Error | Level::DelayedBug),
             "downgrade_to_delayed_bug: cannot downgrade {:?} to DelayedBug: not an error",
             self.level
         );
-        self.level = Level::DelayedBug(DelayedBugKind::Normal);
+        self.level = Level::DelayedBug;
     }
 
     /// Appends a labeled span to the diagnostic.
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 4be5ed923e5..b9e92dbb31c 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -193,7 +193,7 @@ pub type DynEmitter = dyn Emitter + DynSend;
 /// Emitter trait for emitting errors.
 pub trait Emitter: Translate {
     /// Emit a structured diagnostic.
-    fn emit_diagnostic(&mut self, diag: &Diagnostic);
+    fn emit_diagnostic(&mut self, diag: Diagnostic);
 
     /// Emit a notification that an artifact has been output.
     /// Currently only supported for the JSON format.
@@ -230,17 +230,17 @@ pub trait Emitter: Translate {
     ///
     /// * If the current `Diagnostic` has only one visible `CodeSuggestion`,
     ///   we format the `help` suggestion depending on the content of the
-    ///   substitutions. In that case, we return the modified span only.
+    ///   substitutions. In that case, we modify the span and clear the
+    ///   suggestions.
     ///
     /// * If the current `Diagnostic` has multiple suggestions,
-    ///   we return the original `primary_span` and the original suggestions.
-    fn primary_span_formatted<'a>(
+    ///   we leave `primary_span` and the suggestions untouched.
+    fn primary_span_formatted(
         &mut self,
-        diag: &'a Diagnostic,
+        primary_span: &mut MultiSpan,
+        suggestions: &mut Vec<CodeSuggestion>,
         fluent_args: &FluentArgs<'_>,
-    ) -> (MultiSpan, &'a [CodeSuggestion]) {
-        let mut primary_span = diag.span.clone();
-        let suggestions = diag.suggestions.as_deref().unwrap_or(&[]);
+    ) {
         if let Some((sugg, rest)) = suggestions.split_first() {
             let msg = self.translate_message(&sugg.msg, fluent_args).map_err(Report::new).unwrap();
             if rest.is_empty() &&
@@ -287,16 +287,15 @@ pub trait Emitter: Translate {
                 primary_span.push_span_label(sugg.substitutions[0].parts[0].span, msg);
 
                 // We return only the modified primary_span
-                (primary_span, &[])
+                suggestions.clear();
             } else {
                 // if there are multiple suggestions, print them all in full
                 // to be consistent. We could try to figure out if we can
                 // make one (or the first one) inline, but that would give
                 // undue importance to a semi-random suggestion
-                (primary_span, suggestions)
             }
         } else {
-            (primary_span, suggestions)
+            // do nothing
         }
     }
 
@@ -518,16 +517,15 @@ impl Emitter for HumanEmitter {
         self.sm.as_ref()
     }
 
-    fn emit_diagnostic(&mut self, diag: &Diagnostic) {
+    fn emit_diagnostic(&mut self, mut diag: Diagnostic) {
         let fluent_args = to_fluent_args(diag.args());
 
-        let mut children = diag.children.clone();
-        let (mut primary_span, suggestions) = self.primary_span_formatted(diag, &fluent_args);
-        debug!("emit_diagnostic: suggestions={:?}", suggestions);
+        let mut suggestions = diag.suggestions.unwrap_or(vec![]);
+        self.primary_span_formatted(&mut diag.span, &mut suggestions, &fluent_args);
 
         self.fix_multispans_in_extern_macros_and_render_macro_backtrace(
-            &mut primary_span,
-            &mut children,
+            &mut diag.span,
+            &mut diag.children,
             &diag.level,
             self.macro_backtrace,
         );
@@ -537,9 +535,9 @@ impl Emitter for HumanEmitter {
             &diag.messages,
             &fluent_args,
             &diag.code,
-            &primary_span,
-            &children,
-            suggestions,
+            &diag.span,
+            &diag.children,
+            &suggestions,
             self.track_diagnostics.then_some(&diag.emitted_at),
         );
     }
@@ -576,9 +574,8 @@ impl Emitter for SilentEmitter {
         None
     }
 
-    fn emit_diagnostic(&mut self, diag: &Diagnostic) {
+    fn emit_diagnostic(&mut self, mut diag: Diagnostic) {
         if diag.level == Level::Fatal {
-            let mut diag = diag.clone();
             diag.note(self.fatal_note.clone());
             self.fatal_dcx.emit_diagnostic(diag);
         }
@@ -2116,6 +2113,7 @@ impl HumanEmitter {
                 }
                 if !self.short_message {
                     for child in children {
+                        assert!(child.level.can_be_top_or_sub().1);
                         let span = &child.span;
                         if let Err(err) = self.emit_messages_default_inner(
                             span,
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index 6f922998279..470e3d52452 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -176,7 +176,7 @@ impl Translate for JsonEmitter {
 }
 
 impl Emitter for JsonEmitter {
-    fn emit_diagnostic(&mut self, diag: &crate::Diagnostic) {
+    fn emit_diagnostic(&mut self, diag: crate::Diagnostic) {
         let data = Diagnostic::from_errors_diagnostic(diag, self);
         let result = self.emit(EmitTyped::Diagnostic(data));
         if let Err(e) = result {
@@ -201,7 +201,7 @@ impl Emitter for JsonEmitter {
                 }
                 FutureBreakageItem {
                     diagnostic: EmitTyped::Diagnostic(Diagnostic::from_errors_diagnostic(
-                        &diag, self,
+                        diag, self,
                     )),
                 }
             })
@@ -340,7 +340,7 @@ struct UnusedExterns<'a, 'b, 'c> {
 }
 
 impl Diagnostic {
-    fn from_errors_diagnostic(diag: &crate::Diagnostic, je: &JsonEmitter) -> Diagnostic {
+    fn from_errors_diagnostic(diag: crate::Diagnostic, je: &JsonEmitter) -> Diagnostic {
         let args = to_fluent_args(diag.args());
         let sugg = diag.suggestions.iter().flatten().map(|sugg| {
             let translated_message =
@@ -382,6 +382,28 @@ impl Diagnostic {
                 Ok(())
             }
         }
+
+        let translated_message = je.translate_messages(&diag.messages, &args);
+
+        let code = if let Some(code) = diag.code {
+            Some(DiagnosticCode {
+                code: code.to_string(),
+                explanation: je.registry.as_ref().unwrap().try_find_description(code).ok(),
+            })
+        } else if let Some(IsLint { name, .. }) = &diag.is_lint {
+            Some(DiagnosticCode { code: name.to_string(), explanation: None })
+        } else {
+            None
+        };
+        let level = diag.level.to_str();
+        let spans = DiagnosticSpan::from_multispan(&diag.span, &args, je);
+        let children = diag
+            .children
+            .iter()
+            .map(|c| Diagnostic::from_sub_diagnostic(c, &args, je))
+            .chain(sugg)
+            .collect();
+
         let buf = BufWriter::default();
         let output = buf.clone();
         je.json_rendered
@@ -398,30 +420,12 @@ impl Diagnostic {
         let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap();
         let output = String::from_utf8(output).unwrap();
 
-        let translated_message = je.translate_messages(&diag.messages, &args);
-
-        let code = if let Some(code) = diag.code {
-            Some(DiagnosticCode {
-                code: code.to_string(),
-                explanation: je.registry.as_ref().unwrap().try_find_description(code).ok(),
-            })
-        } else if let Some(IsLint { name, .. }) = &diag.is_lint {
-            Some(DiagnosticCode { code: name.to_string(), explanation: None })
-        } else {
-            None
-        };
-
         Diagnostic {
             message: translated_message.to_string(),
             code,
-            level: diag.level.to_str(),
-            spans: DiagnosticSpan::from_multispan(&diag.span, &args, je),
-            children: diag
-                .children
-                .iter()
-                .map(|c| Diagnostic::from_sub_diagnostic(c, &args, je))
-                .chain(sugg)
-                .collect(),
+            level,
+            spans,
+            children,
             rendered: Some(output),
         }
     }
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 9ec636dcc9c..a4112d717d0 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -439,7 +439,7 @@ struct DiagCtxtInner {
     has_printed: bool,
 
     emitter: Box<DynEmitter>,
-    span_delayed_bugs: Vec<DelayedDiagnostic>,
+    delayed_bugs: Vec<DelayedDiagnostic>,
     good_path_delayed_bugs: Vec<DelayedDiagnostic>,
     /// This flag indicates that an expected diagnostic was emitted and suppressed.
     /// This is used for the `good_path_delayed_bugs` check.
@@ -523,8 +523,7 @@ fn default_track_diagnostic(diag: Diagnostic, f: &mut dyn FnMut(Diagnostic)) {
 pub static TRACK_DIAGNOSTIC: AtomicRef<fn(Diagnostic, &mut dyn FnMut(Diagnostic))> =
     AtomicRef::new(&(default_track_diagnostic as _));
 
-#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug, Encodable, Decodable)]
-pub enum DelayedBugKind {
+enum DelayedBugKind {
     Normal,
     GoodPath,
 }
@@ -557,11 +556,6 @@ impl Drop for DiagCtxtInner {
             self.flush_delayed(DelayedBugKind::Normal)
         }
 
-        // FIXME(eddyb) this explains what `good_path_delayed_bugs` are!
-        // They're `span_delayed_bugs` but for "require some diagnostic happened"
-        // instead of "require some error happened". Sadly that isn't ideal, as
-        // lints can be `#[allow]`'d, potentially leading to this triggering.
-        // Also, "good path" should be replaced with a better naming.
         if !self.has_printed && !self.suppressed_expected_diag && !std::thread::panicking() {
             self.flush_delayed(DelayedBugKind::GoodPath);
         }
@@ -608,7 +602,7 @@ impl DiagCtxt {
                 deduplicated_warn_count: 0,
                 has_printed: false,
                 emitter,
-                span_delayed_bugs: Vec::new(),
+                delayed_bugs: Vec::new(),
                 good_path_delayed_bugs: Vec::new(),
                 suppressed_expected_diag: false,
                 taught_diagnostics: Default::default(),
@@ -665,7 +659,7 @@ impl DiagCtxt {
         inner.has_printed = false;
 
         // actually free the underlying memory (which `clear` would not do)
-        inner.span_delayed_bugs = Default::default();
+        inner.delayed_bugs = Default::default();
         inner.good_path_delayed_bugs = Default::default();
         inner.taught_diagnostics = Default::default();
         inner.emitted_diagnostic_codes = Default::default();
@@ -866,8 +860,7 @@ impl DiagCtxt {
     /// directly).
     #[track_caller]
     pub fn delayed_bug(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
-        DiagnosticBuilder::<ErrorGuaranteed>::new(self, DelayedBug(DelayedBugKind::Normal), msg)
-            .emit()
+        DiagnosticBuilder::<ErrorGuaranteed>::new(self, DelayedBug, msg).emit()
     }
 
     /// Like `delayed_bug`, but takes an additional span.
@@ -880,15 +873,12 @@ impl DiagCtxt {
         sp: impl Into<MultiSpan>,
         msg: impl Into<DiagnosticMessage>,
     ) -> ErrorGuaranteed {
-        DiagnosticBuilder::<ErrorGuaranteed>::new(self, DelayedBug(DelayedBugKind::Normal), msg)
-            .with_span(sp)
-            .emit()
+        DiagnosticBuilder::<ErrorGuaranteed>::new(self, DelayedBug, msg).with_span(sp).emit()
     }
 
-    // FIXME(eddyb) note the comment inside `impl Drop for DiagCtxtInner`, that's
-    // where the explanation of what "good path" is (also, it should be renamed).
+    /// Ensures that a diagnostic is printed. See `Level::GoodPathDelayedBug`.
     pub fn good_path_delayed_bug(&self, msg: impl Into<DiagnosticMessage>) {
-        DiagnosticBuilder::<()>::new(self, DelayedBug(DelayedBugKind::GoodPath), msg).emit()
+        DiagnosticBuilder::<()>::new(self, GoodPathDelayedBug, msg).emit()
     }
 
     #[track_caller]
@@ -962,7 +952,7 @@ impl DiagCtxt {
     pub fn has_errors_or_lint_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
         let inner = self.inner.borrow();
         let result =
-            inner.has_errors() || inner.lint_err_count > 0 || !inner.span_delayed_bugs.is_empty();
+            inner.has_errors() || inner.lint_err_count > 0 || !inner.delayed_bugs.is_empty();
         result.then(|| {
             #[allow(deprecated)]
             ErrorGuaranteed::unchecked_claim_error_was_emitted()
@@ -991,9 +981,13 @@ impl DiagCtxt {
 
         match (errors.len(), warnings.len()) {
             (0, 0) => return,
-            (0, _) => inner
-                .emitter
-                .emit_diagnostic(&Diagnostic::new(Warning, DiagnosticMessage::Str(warnings))),
+            (0, _) => {
+                // Use `inner.emitter` directly, otherwise the warning might not be emitted, e.g.
+                // with a configuration like `--cap-lints allow --force-warn bare_trait_objects`.
+                inner
+                    .emitter
+                    .emit_diagnostic(Diagnostic::new(Warning, DiagnosticMessage::Str(warnings)));
+            }
             (_, 0) => {
                 inner.emit_diagnostic(Diagnostic::new(Fatal, errors));
             }
@@ -1057,7 +1051,7 @@ impl DiagCtxt {
     }
 
     pub fn force_print_diagnostic(&self, db: Diagnostic) {
-        self.inner.borrow_mut().emitter.emit_diagnostic(&db);
+        self.inner.borrow_mut().emitter.emit_diagnostic(db);
     }
 
     pub fn emit_diagnostic(&self, diagnostic: Diagnostic) -> Option<ErrorGuaranteed> {
@@ -1248,43 +1242,19 @@ impl DiagCtxtInner {
     }
 
     fn emit_diagnostic(&mut self, mut diagnostic: Diagnostic) -> Option<ErrorGuaranteed> {
-        // The `LintExpectationId` can be stable or unstable depending on when it was created.
-        // Diagnostics created before the definition of `HirId`s are unstable and can not yet
-        // be stored. Instead, they are buffered until the `LintExpectationId` is replaced by
-        // a stable one by the `LintLevelsBuilder`.
-        if let Some(LintExpectationId::Unstable { .. }) = diagnostic.level.get_expectation_id() {
-            self.unstable_expect_diagnostics.push(diagnostic);
-            return None;
-        }
+        assert!(diagnostic.level.can_be_top_or_sub().0);
 
-        // FIXME(eddyb) this should check for `has_errors` and stop pushing
-        // once *any* errors were emitted (and truncate `span_delayed_bugs`
-        // when an error is first emitted, also), but maybe there's a case
-        // in which that's not sound? otherwise this is really inefficient.
-        match diagnostic.level {
-            DelayedBug(_) if self.flags.eagerly_emit_delayed_bugs => {
-                diagnostic.level = Error;
-            }
-            DelayedBug(DelayedBugKind::Normal) => {
-                let backtrace = std::backtrace::Backtrace::capture();
-                self.span_delayed_bugs
-                    .push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
-                #[allow(deprecated)]
-                return Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
-            }
-            DelayedBug(DelayedBugKind::GoodPath) => {
-                let backtrace = std::backtrace::Backtrace::capture();
-                self.good_path_delayed_bugs
-                    .push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
+        if let Some(expectation_id) = diagnostic.level.get_expectation_id() {
+            // The `LintExpectationId` can be stable or unstable depending on when it was created.
+            // Diagnostics created before the definition of `HirId`s are unstable and can not yet
+            // be stored. Instead, they are buffered until the `LintExpectationId` is replaced by
+            // a stable one by the `LintLevelsBuilder`.
+            if let LintExpectationId::Unstable { .. } = expectation_id {
+                self.unstable_expect_diagnostics.push(diagnostic);
                 return None;
             }
-            _ => {}
-        }
-
-        // This must come after the possible promotion of `DelayedBug` to
-        // `Error` above.
-        if matches!(diagnostic.level, Error | Fatal) && self.treat_next_err_as_bug() {
-            diagnostic.level = Bug;
+            self.suppressed_expected_diag = true;
+            self.fulfilled_expectations.insert(expectation_id.normalize());
         }
 
         if diagnostic.has_future_breakage() {
@@ -1295,21 +1265,45 @@ impl DiagCtxtInner {
             self.future_breakage_diagnostics.push(diagnostic.clone());
         }
 
-        if let Some(expectation_id) = diagnostic.level.get_expectation_id() {
-            self.suppressed_expected_diag = true;
-            self.fulfilled_expectations.insert(expectation_id.normalize());
+        if matches!(diagnostic.level, DelayedBug | GoodPathDelayedBug)
+            && self.flags.eagerly_emit_delayed_bugs
+        {
+            diagnostic.level = Error;
         }
 
-        if diagnostic.level == Warning && !self.flags.can_emit_warnings {
-            if diagnostic.has_future_breakage() {
+        match diagnostic.level {
+            // This must come after the possible promotion of `DelayedBug`/`GoodPathDelayedBug` to
+            // `Error` above.
+            Fatal | Error if self.treat_next_err_as_bug() => {
+                diagnostic.level = Bug;
+            }
+            DelayedBug => {
+                // FIXME(eddyb) this should check for `has_errors` and stop pushing
+                // once *any* errors were emitted (and truncate `delayed_bugs`
+                // when an error is first emitted, also), but maybe there's a case
+                // in which that's not sound? otherwise this is really inefficient.
+                let backtrace = std::backtrace::Backtrace::capture();
+                self.delayed_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
+                #[allow(deprecated)]
+                return Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
+            }
+            GoodPathDelayedBug => {
+                let backtrace = std::backtrace::Backtrace::capture();
+                self.good_path_delayed_bugs
+                    .push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
+                return None;
+            }
+            Warning if !self.flags.can_emit_warnings => {
+                if diagnostic.has_future_breakage() {
+                    (*TRACK_DIAGNOSTIC)(diagnostic, &mut |_| {});
+                }
+                return None;
+            }
+            Allow | Expect(_) => {
                 (*TRACK_DIAGNOSTIC)(diagnostic, &mut |_| {});
+                return None;
             }
-            return None;
-        }
-
-        if matches!(diagnostic.level, Expect(_) | Allow) {
-            (*TRACK_DIAGNOSTIC)(diagnostic, &mut |_| {});
-            return None;
+            _ => {}
         }
 
         let mut guaranteed = None;
@@ -1325,11 +1319,15 @@ impl DiagCtxtInner {
                 !self.emitted_diagnostics.insert(diagnostic_hash)
             };
 
+            let is_error = diagnostic.is_error();
+            let is_lint = diagnostic.is_lint.is_some();
+
             // Only emit the diagnostic if we've been asked to deduplicate or
             // haven't already emitted an equivalent diagnostic.
             if !(self.flags.deduplicate_diagnostics && already_emitted) {
                 debug!(?diagnostic);
                 debug!(?self.emitted_diagnostics);
+
                 let already_emitted_sub = |sub: &mut SubDiagnostic| {
                     debug!(?sub);
                     if sub.level != OnceNote && sub.level != OnceHelp {
@@ -1341,7 +1339,6 @@ impl DiagCtxtInner {
                     debug!(?diagnostic_hash);
                     !self.emitted_diagnostics.insert(diagnostic_hash)
                 };
-
                 diagnostic.children.extract_if(already_emitted_sub).for_each(|_| {});
                 if already_emitted {
                     diagnostic.note(
@@ -1349,16 +1346,17 @@ impl DiagCtxtInner {
                     );
                 }
 
-                self.emitter.emit_diagnostic(&diagnostic);
-                if diagnostic.is_error() {
+                if is_error {
                     self.deduplicated_err_count += 1;
                 } else if matches!(diagnostic.level, ForceWarning(_) | Warning) {
                     self.deduplicated_warn_count += 1;
                 }
                 self.has_printed = true;
+
+                self.emitter.emit_diagnostic(diagnostic);
             }
-            if diagnostic.is_error() {
-                if diagnostic.is_lint.is_some() {
+            if is_error {
+                if is_lint {
                     self.lint_err_count += 1;
                 } else {
                     self.err_count += 1;
@@ -1397,12 +1395,12 @@ impl DiagCtxtInner {
     fn flush_delayed(&mut self, kind: DelayedBugKind) {
         let (bugs, note1) = match kind {
             DelayedBugKind::Normal => (
-                std::mem::take(&mut self.span_delayed_bugs),
-                "no errors encountered even though `span_delayed_bug` issued",
+                std::mem::take(&mut self.delayed_bugs),
+                "no errors encountered even though delayed bugs were created",
             ),
             DelayedBugKind::GoodPath => (
                 std::mem::take(&mut self.good_path_delayed_bugs),
-                "no warnings or errors encountered even though `good_path_delayed_bugs` issued",
+                "no warnings or errors encountered even though good path delayed bugs were created",
             ),
         };
         let note2 = "those delayed bugs will now be shown as internal compiler errors";
@@ -1441,8 +1439,8 @@ impl DiagCtxtInner {
             let mut bug =
                 if backtrace || self.ice_file.is_none() { bug.decorate() } else { bug.inner };
 
-            // "Undelay" the `DelayedBug`s (into plain `Bug`s).
-            if !matches!(bug.level, DelayedBug(_)) {
+            // "Undelay" the delayed bugs (into plain `Bug`s).
+            if !matches!(bug.level, DelayedBug | GoodPathDelayedBug) {
                 // NOTE(eddyb) not panicking here because we're already producing
                 // an ICE, and the more information the merrier.
                 bug.subdiagnostic(InvalidFlushedDelayedDiagnosticLevel {
@@ -1508,35 +1506,59 @@ impl DelayedDiagnostic {
     }
 }
 
+/// Level              is_error  EmissionGuarantee         Top-level  Sub   Used in lints?
+/// -----              --------  -----------------         ---------  ---   --------------
+/// Bug                yes       BugAbort                  yes        -     -
+/// Fatal              yes       FatalAbort/FatalError(*)  yes        -     -
+/// Error              yes       ErrorGuaranteed           yes        -     yes
+/// DelayedBug         yes       ErrorGuaranteed           yes        -     -
+/// GoodPathDelayedBug -         ()                        yes        -     -
+/// ForceWarning       -         ()                        yes        -     lint-only
+/// Warning            -         ()                        yes        yes   yes
+/// Note               -         ()                        rare       yes   -
+/// OnceNote           -         ()                        -          yes   lint-only
+/// Help               -         ()                        rare       yes   -
+/// OnceHelp           -         ()                        -          yes   lint-only
+/// FailureNote        -         ()                        rare       -     -
+/// Allow              -         ()                        yes        -     lint-only
+/// Expect             -         ()                        yes        -     lint-only
+///
+/// (*) `FatalAbort` normally, `FatalError` in the non-aborting "almost fatal" case that is
+///     occasionally used.
+///
 #[derive(Copy, PartialEq, Eq, Clone, Hash, Debug, Encodable, Decodable)]
 pub enum Level {
     /// For bugs in the compiler. Manifests as an ICE (internal compiler error) panic.
-    ///
-    /// Its `EmissionGuarantee` is `BugAbort`.
     Bug,
 
-    /// This is a strange one: lets you register an error without emitting it. If compilation ends
-    /// without any other errors occurring, this will be emitted as a bug. Otherwise, it will be
-    /// silently dropped. I.e. "expect other errors are emitted" semantics. Useful on code paths
-    /// that should only be reached when compiling erroneous code.
-    ///
-    /// Its `EmissionGuarantee` is `ErrorGuaranteed` for `Normal` delayed bugs, and `()` for
-    /// `GoodPath` delayed bugs.
-    DelayedBug(DelayedBugKind),
-
     /// An error that causes an immediate abort. Used for things like configuration errors,
     /// internal overflows, some file operation errors.
-    ///
-    /// Its `EmissionGuarantee` is `FatalAbort`, except in the non-aborting "almost fatal" case
-    /// that is occasionally used, where it is `FatalError`.
     Fatal,
 
     /// An error in the code being compiled, which prevents compilation from finishing. This is the
     /// most common case.
-    ///
-    /// Its `EmissionGuarantee` is `ErrorGuaranteed`.
     Error,
 
+    /// This is a strange one: lets you register an error without emitting it. If compilation ends
+    /// without any other errors occurring, this will be emitted as a bug. Otherwise, it will be
+    /// silently dropped. I.e. "expect other errors are emitted" semantics. Useful on code paths
+    /// that should only be reached when compiling erroneous code.
+    DelayedBug,
+
+    /// Like `DelayedBug`, but weaker: lets you register an error without emitting it. If
+    /// compilation ends without any other diagnostics being emitted (and without an expected lint
+    /// being suppressed), this will be emitted as a bug. Otherwise, it will be silently dropped.
+    /// I.e. "expect other diagnostics are emitted (or suppressed)" semantics. Useful on code paths
+    /// that should only be reached when emitting diagnostics, e.g. for expensive one-time
+    /// diagnostic formatting operations.
+    ///
+    /// FIXME(nnethercote) good path delayed bugs are semantically strange: if printed they produce
+    /// an ICE, but they don't satisfy `is_error` and they don't guarantee an error is emitted.
+    /// Plus there's the extra complication with expected (suppressed) lints. They have limited
+    /// use, and are used in very few places, and "good path" isn't a good name. It would be good
+    /// to remove them.
+    GoodPathDelayedBug,
+
     /// A `force-warn` lint warning about the code being compiled. Does not prevent compilation
     /// from finishing.
     ///
@@ -1545,45 +1567,28 @@ pub enum Level {
     ForceWarning(Option<LintExpectationId>),
 
     /// A warning about the code being compiled. Does not prevent compilation from finishing.
-    ///
-    /// Its `EmissionGuarantee` is `()`.
     Warning,
 
-    /// A message giving additional context. Rare, because notes are more commonly attached to other
-    /// diagnostics such as errors.
-    ///
-    /// Its `EmissionGuarantee` is `()`.
+    /// A message giving additional context.
     Note,
 
-    /// A note that is only emitted once. Rare, mostly used in circumstances relating to lints.
-    ///
-    /// Its `EmissionGuarantee` is `()`.
+    /// A note that is only emitted once.
     OnceNote,
 
-    /// A message suggesting how to fix something. Rare, because help messages are more commonly
-    /// attached to other diagnostics such as errors.
-    ///
-    /// Its `EmissionGuarantee` is `()`.
+    /// A message suggesting how to fix something.
     Help,
 
-    /// A help that is only emitted once. Rare.
-    ///
-    /// Its `EmissionGuarantee` is `()`.
+    /// A help that is only emitted once.
     OnceHelp,
 
-    /// Similar to `Note`, but used in cases where compilation has failed. Rare.
-    ///
-    /// Its `EmissionGuarantee` is `()`.
+    /// Similar to `Note`, but used in cases where compilation has failed. When printed for human
+    /// consumption, it doesn't have any kind of `note:` label.
     FailureNote,
 
     /// Only used for lints.
-    ///
-    /// Its `EmissionGuarantee` is `()`.
     Allow,
 
     /// Only used for lints.
-    ///
-    /// Its `EmissionGuarantee` is `()`.
     Expect(LintExpectationId),
 }
 
@@ -1597,7 +1602,7 @@ impl Level {
     fn color(self) -> ColorSpec {
         let mut spec = ColorSpec::new();
         match self {
-            Bug | DelayedBug(_) | Fatal | Error => {
+            Bug | Fatal | Error | DelayedBug | GoodPathDelayedBug => {
                 spec.set_fg(Some(Color::Red)).set_intense(true);
             }
             ForceWarning(_) | Warning => {
@@ -1617,7 +1622,7 @@ impl Level {
 
     pub fn to_str(self) -> &'static str {
         match self {
-            Bug | DelayedBug(_) => "error: internal compiler error",
+            Bug | DelayedBug | GoodPathDelayedBug => "error: internal compiler error",
             Fatal | Error => "error",
             ForceWarning(_) | Warning => "warning",
             Note | OnceNote => "note",
@@ -1637,6 +1642,19 @@ impl Level {
             _ => None,
         }
     }
+
+    // Can this level be used in a top-level diagnostic message and/or a
+    // subdiagnostic message?
+    fn can_be_top_or_sub(&self) -> (bool, bool) {
+        match self {
+            Bug | DelayedBug | Fatal | Error | GoodPathDelayedBug | ForceWarning(_)
+            | FailureNote | Allow | Expect(_) => (true, false),
+
+            Warning | Note | Help => (true, true),
+
+            OnceNote | OnceHelp => (false, true),
+        }
+    }
 }
 
 // FIXME(eddyb) this doesn't belong here AFAICT, should be moved to callsite.
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 68b6f69854d..019cc1c847e 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -440,9 +440,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         experimental!(optimize),
     ),
 
-    gated!(
-        ffi_returns_twice, Normal, template!(Word), WarnFollowing, experimental!(ffi_returns_twice)
-    ),
     gated!(ffi_pure, Normal, template!(Word), WarnFollowing, experimental!(ffi_pure)),
     gated!(ffi_const, Normal, template!(Word), WarnFollowing, experimental!(ffi_const)),
     gated!(
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index 85fcf6a9994..040892df4c3 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -97,6 +97,9 @@ declare_features! (
     /// Allows `#[doc(include = "some-file")]`.
     (removed, external_doc, "1.54.0", Some(44732),
      Some("use #[doc = include_str!(\"filename\")] instead, which handles macro invocations")),
+    /// Allows using `#[ffi_returns_twice]` on foreign functions.
+    (removed, ffi_returns_twice, "CURRENT_RUSTC_VERSION", Some(58314),
+     Some("being investigated by the ffi-unwind project group")),
     /// Allows generators to be cloned.
     (removed, generator_clone, "1.65.0", Some(95360), Some("renamed to `coroutine_clone`")),
     /// Allows defining generators.
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index d00621d8254..1fb91ff8bbc 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -465,8 +465,6 @@ declare_features! (
     (unstable, ffi_const, "1.45.0", Some(58328)),
     /// Allows the use of `#[ffi_pure]` on foreign functions.
     (unstable, ffi_pure, "1.45.0", Some(58329)),
-    /// Allows using `#[ffi_returns_twice]` on foreign functions.
-    (unstable, ffi_returns_twice, "1.34.0", Some(58314)),
     /// Allows using `#[repr(align(...))]` on function items
     (unstable, fn_align, "1.53.0", Some(82232)),
     /// Support delegating implementation of functions to other already implemented functions.
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index de1b28acb12..ff50086ff8f 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -952,6 +952,11 @@ pub enum ClosureKind {
     ///  usage (e.g. `let x = || { yield (); }`) or from a desugared expression
     /// (e.g. `async` and `gen` blocks).
     Coroutine(CoroutineKind),
+    /// This is a coroutine-closure, which is a special sugared closure that
+    /// returns one of the sugared coroutine (`async`/`gen`/`async gen`). It
+    /// additionally allows capturing the coroutine's upvars by ref, and therefore
+    /// needs to be specially treated during analysis and borrowck.
+    CoroutineClosure(CoroutineDesugaring),
 }
 
 /// A block of statements `{ .. }`, which may have a label (in this case the
@@ -3698,6 +3703,7 @@ impl<'hir> Node<'hir> {
         expect_generic_param, &'hir GenericParam<'hir>, Node::GenericParam(n), n;
         expect_crate,         &'hir Mod<'hir>,          Node::Crate(n),        n;
         expect_infer,         &'hir InferArg,           Node::Infer(n),        n;
+        expect_closure,       &'hir Closure<'hir>, Node::Expr(Expr { kind: ExprKind::Closure(n), .. }), n;
     }
 }
 
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 8e327c029df..9c9e72d6e65 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -209,6 +209,7 @@ language_item_table! {
     AsyncFn,                 sym::async_fn,            async_fn_trait,             Target::Trait,          GenericRequirement::Exact(1);
     AsyncFnMut,              sym::async_fn_mut,        async_fn_mut_trait,         Target::Trait,          GenericRequirement::Exact(1);
     AsyncFnOnce,             sym::async_fn_once,       async_fn_once_trait,        Target::Trait,          GenericRequirement::Exact(1);
+    AsyncFnKindHelper,       sym::async_fn_kind_helper,async_fn_kind_helper,       Target::Trait,          GenericRequirement::Exact(1);
 
     FnOnceOutput,            sym::fn_once_output,      fn_once_output,             Target::AssocTy,        GenericRequirement::None;
 
diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs
index e67a44d96ad..3c64b102bae 100644
--- a/compiler/rustc_hir_analysis/src/astconv/errors.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs
@@ -14,6 +14,7 @@ use rustc_errors::{
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_infer::traits::FulfillmentError;
+use rustc_middle::query::Key;
 use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TyCtxt, TypeVisitableExt};
 use rustc_session::parse::feature_err;
 use rustc_span::edit_distance::find_best_match_for_name;
@@ -859,6 +860,56 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
         self.set_tainted_by_errors(err.emit());
     }
+
+    /// On ambiguous associated type, look for an associated function whose name matches the
+    /// extended path and, if found, emit an E0223 error with a structured suggestion.
+    /// e.g. for `String::from::utf8`, suggest `String::from_utf8` (#109195)
+    pub(crate) fn maybe_report_similar_assoc_fn(
+        &self,
+        span: Span,
+        qself_ty: Ty<'tcx>,
+        qself: &hir::Ty<'_>,
+    ) -> Result<(), ErrorGuaranteed> {
+        let tcx = self.tcx();
+        if let Some((_, node)) = tcx.hir().parent_iter(qself.hir_id).skip(1).next()
+            && let hir::Node::Expr(hir::Expr {
+                kind:
+                    hir::ExprKind::Path(hir::QPath::TypeRelative(
+                        hir::Ty {
+                            kind:
+                                hir::TyKind::Path(hir::QPath::TypeRelative(
+                                    _,
+                                    hir::PathSegment { ident: ident2, .. },
+                                )),
+                            ..
+                        },
+                        hir::PathSegment { ident: ident3, .. },
+                    )),
+                ..
+            }) = node
+            && let Some(ty_def_id) = qself_ty.ty_def_id()
+            && let Ok([inherent_impl]) = tcx.inherent_impls(ty_def_id)
+            && let name = format!("{ident2}_{ident3}")
+            && let Some(ty::AssocItem { kind: ty::AssocKind::Fn, .. }) = tcx
+                .associated_items(inherent_impl)
+                .filter_by_name_unhygienic(Symbol::intern(&name))
+                .next()
+        {
+            let reported =
+                struct_span_code_err!(tcx.dcx(), span, E0223, "ambiguous associated type")
+                    .with_span_suggestion_verbose(
+                        ident2.span.to(ident3.span),
+                        format!("there is an associated function with a similar name: `{name}`"),
+                        name,
+                        Applicability::MaybeIncorrect,
+                    )
+                    .emit();
+            self.set_tainted_by_errors(reported);
+            Err(reported)
+        } else {
+            Ok(())
+        }
+    }
 }
 
 /// Emits an error regarding forbidden type binding associations
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 89f39897ea8..cfd38fb48f4 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -1373,6 +1373,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     )
                     .emit() // Already reported in an earlier stage.
                 } else {
+                    self.maybe_report_similar_assoc_fn(span, qself_ty, qself)?;
+
                     let traits: Vec<_> =
                         self.probe_traits_that_match_assoc_ty(qself_ty, assoc_ident);
 
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index abef365c3ca..0df5a57bc2c 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -171,6 +171,7 @@ impl<'tcx> InherentCollect<'tcx> {
             }
             ty::FnDef(..)
             | ty::Closure(..)
+            | ty::CoroutineClosure(..)
             | ty::Coroutine(..)
             | ty::CoroutineWitness(..)
             | ty::Bound(..)
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 1736de760d5..45641be52d2 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -244,6 +244,7 @@ fn do_orphan_check_impl<'tcx>(
             | ty::Tuple(..) => (LocalImpl::Allow, NonlocalImpl::DisallowOther),
 
             ty::Closure(..)
+            | ty::CoroutineClosure(..)
             | ty::Coroutine(..)
             | ty::CoroutineWitness(..)
             | ty::Bound(..)
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 8d862d5eb71..fbcebb7c87c 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -81,6 +81,7 @@ pub fn provide(providers: &mut Providers) {
         impl_trait_ref,
         impl_polarity,
         coroutine_kind,
+        coroutine_for_closure,
         collect_mod_item_types,
         is_type_alias_impl_trait,
         ..*providers
@@ -1531,6 +1532,29 @@ fn coroutine_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<hir::CoroutineK
     }
 }
 
+fn coroutine_for_closure(tcx: TyCtxt<'_>, def_id: LocalDefId) -> DefId {
+    let &rustc_hir::Closure { kind: hir::ClosureKind::CoroutineClosure(_), body, .. } =
+        tcx.hir_node_by_def_id(def_id).expect_closure()
+    else {
+        bug!()
+    };
+
+    let &hir::Expr {
+        kind:
+            hir::ExprKind::Closure(&rustc_hir::Closure {
+                def_id,
+                kind: hir::ClosureKind::Coroutine(_),
+                ..
+            }),
+        ..
+    } = tcx.hir().body(body).value
+    else {
+        bug!()
+    };
+
+    def_id.to_def_id()
+}
+
 fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
     match tcx.hir_node_by_def_id(def_id) {
         Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(opaque), .. }) => {
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index c29d4131843..1dabb6feb5e 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -349,6 +349,13 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
             ClosureKind::Coroutine(_) => {
                 &["<resume_ty>", "<yield_ty>", "<return_ty>", "<witness>", "<upvars>"][..]
             }
+            ClosureKind::CoroutineClosure(_) => &[
+                "<closure_kind>",
+                "<closure_signature_parts>",
+                "<upvars>",
+                "<bound_captures_by_ref>",
+                "<witness>",
+            ][..],
         };
 
         params.extend(dummy_args.iter().map(|&arg| ty::GenericParamDef {
diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs
index f09594cbbc6..580cdb4a3a2 100644
--- a/compiler/rustc_hir_analysis/src/variance/constraints.rs
+++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs
@@ -235,8 +235,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 // leaf type -- noop
             }
 
-            ty::FnDef(..) | ty::Coroutine(..) | ty::Closure(..) => {
-                bug!("Unexpected closure type in variance computation");
+            ty::FnDef(..) | ty::Coroutine(..) | ty::Closure(..) | ty::CoroutineClosure(..) => {
+                bug!("Unexpected coroutine/closure type in variance computation");
             }
 
             ty::Ref(region, ty, mutbl) => {
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index cf1f232229d..7ea0469dedd 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -1,7 +1,11 @@
 use crate::coercion::{AsCoercionSite, CoerceMany};
 use crate::{Diverges, Expectation, FnCtxt, Needs};
-use rustc_errors::Diagnostic;
-use rustc_hir::{self as hir, ExprKind};
+use rustc_errors::{Applicability, Diagnostic};
+use rustc_hir::{
+    self as hir,
+    def::{CtorOf, DefKind, Res},
+    ExprKind, PatKind,
+};
 use rustc_hir_pretty::ty_to_string;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::traits::Obligation;
@@ -273,7 +277,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Returns `true` if there was an error forcing the coercion to the `()` type.
     pub(super) fn if_fallback_coercion<T>(
         &self,
-        span: Span,
+        if_span: Span,
+        cond_expr: &'tcx hir::Expr<'tcx>,
         then_expr: &'tcx hir::Expr<'tcx>,
         coercion: &mut CoerceMany<'tcx, '_, T>,
     ) -> bool
@@ -283,29 +288,106 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // If this `if` expr is the parent's function return expr,
         // the cause of the type coercion is the return type, point at it. (#25228)
         let hir_id = self.tcx.hir().parent_id(self.tcx.hir().parent_id(then_expr.hir_id));
-        let ret_reason = self.maybe_get_coercion_reason(hir_id, span);
-        let cause = self.cause(span, ObligationCauseCode::IfExpressionWithNoElse);
+        let ret_reason = self.maybe_get_coercion_reason(hir_id, if_span);
+        let cause = self.cause(if_span, ObligationCauseCode::IfExpressionWithNoElse);
         let mut error = false;
         coercion.coerce_forced_unit(
             self,
             &cause,
-            |err| {
-                if let Some((span, msg)) = &ret_reason {
-                    err.span_label(*span, msg.clone());
-                } else if let ExprKind::Block(block, _) = &then_expr.kind
-                    && let Some(expr) = &block.expr
-                {
-                    err.span_label(expr.span, "found here");
-                }
-                err.note("`if` expressions without `else` evaluate to `()`");
-                err.help("consider adding an `else` block that evaluates to the expected type");
-                error = true;
-            },
+            |err| self.explain_if_expr(err, ret_reason, if_span, cond_expr, then_expr, &mut error),
             false,
         );
         error
     }
 
+    /// Explain why `if` expressions without `else` evaluate to `()` and detect likely irrefutable
+    /// `if let PAT = EXPR {}` expressions that could be turned into `let PAT = EXPR;`.
+    fn explain_if_expr(
+        &self,
+        err: &mut Diagnostic,
+        ret_reason: Option<(Span, String)>,
+        if_span: Span,
+        cond_expr: &'tcx hir::Expr<'tcx>,
+        then_expr: &'tcx hir::Expr<'tcx>,
+        error: &mut bool,
+    ) {
+        if let Some((if_span, msg)) = ret_reason {
+            err.span_label(if_span, msg.clone());
+        } else if let ExprKind::Block(block, _) = then_expr.kind
+            && let Some(expr) = block.expr
+        {
+            err.span_label(expr.span, "found here");
+        }
+        err.note("`if` expressions without `else` evaluate to `()`");
+        err.help("consider adding an `else` block that evaluates to the expected type");
+        *error = true;
+        if let ExprKind::Let(hir::Let { span, pat, init, .. }) = cond_expr.kind
+            && let ExprKind::Block(block, _) = then_expr.kind
+            // Refutability checks occur on the MIR, so we approximate it here by checking
+            // if we have an enum with a single variant or a struct in the pattern.
+            && let PatKind::TupleStruct(qpath, ..) | PatKind::Struct(qpath, ..) = pat.kind
+            && let hir::QPath::Resolved(_, path) = qpath
+        {
+            match path.res {
+                Res::Def(DefKind::Ctor(CtorOf::Struct, _), _) => {
+                    // Structs are always irrefutable. Their fields might not be, but we
+                    // don't check for that here, it's only an approximation.
+                }
+                Res::Def(DefKind::Ctor(CtorOf::Variant, _), def_id)
+                    if self
+                        .tcx
+                        .adt_def(self.tcx.parent(self.tcx.parent(def_id)))
+                        .variants()
+                        .len()
+                        == 1 =>
+                {
+                    // There's only a single variant in the `enum`, so we can suggest the
+                    // irrefutable `let` instead of `if let`.
+                }
+                _ => return,
+            }
+
+            let mut sugg = vec![
+                // Remove the `if`
+                (if_span.until(*span), String::new()),
+            ];
+            match (block.stmts, block.expr) {
+                ([first, ..], Some(expr)) => {
+                    let padding = self
+                        .tcx
+                        .sess
+                        .source_map()
+                        .indentation_before(first.span)
+                        .unwrap_or_else(|| String::new());
+                    sugg.extend([
+                        (init.span.between(first.span), format!(";\n{padding}")),
+                        (expr.span.shrink_to_hi().with_hi(block.span.hi()), String::new()),
+                    ]);
+                }
+                ([], Some(expr)) => {
+                    let padding = self
+                        .tcx
+                        .sess
+                        .source_map()
+                        .indentation_before(expr.span)
+                        .unwrap_or_else(|| String::new());
+                    sugg.extend([
+                        (init.span.between(expr.span), format!(";\n{padding}")),
+                        (expr.span.shrink_to_hi().with_hi(block.span.hi()), String::new()),
+                    ]);
+                }
+                // If there's no value in the body, then the `if` expression would already
+                // be of type `()`, so checking for those cases is unnecessary.
+                (_, None) => return,
+            }
+            err.multipart_suggestion(
+                "consider using an irrefutable `let` binding instead",
+                sugg,
+                Applicability::MaybeIncorrect,
+            );
+        }
+    }
+
     pub fn maybe_get_coercion_reason(
         &self,
         hir_id: hir::HirId,
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index b263c985534..fbe6f454dbc 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -141,33 +141,77 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 return Some(CallStep::Builtin(adjusted_ty));
             }
 
-            ty::Closure(def_id, args) => {
+            // Check whether this is a call to a closure where we
+            // haven't yet decided on whether the closure is fn vs
+            // fnmut vs fnonce. If so, we have to defer further processing.
+            ty::Closure(def_id, args) if self.closure_kind(adjusted_ty).is_none() => {
                 let def_id = def_id.expect_local();
+                let closure_sig = args.as_closure().sig();
+                let closure_sig = self.instantiate_binder_with_fresh_vars(
+                    call_expr.span,
+                    infer::FnCall,
+                    closure_sig,
+                );
+                let adjustments = self.adjust_steps(autoderef);
+                self.record_deferred_call_resolution(
+                    def_id,
+                    DeferredCallResolution {
+                        call_expr,
+                        callee_expr,
+                        closure_ty: adjusted_ty,
+                        adjustments,
+                        fn_sig: closure_sig,
+                    },
+                );
+                return Some(CallStep::DeferredClosure(def_id, closure_sig));
+            }
 
-                // Check whether this is a call to a closure where we
-                // haven't yet decided on whether the closure is fn vs
-                // fnmut vs fnonce. If so, we have to defer further processing.
-                if self.closure_kind(args).is_none() {
-                    let closure_sig = args.as_closure().sig();
-                    let closure_sig = self.instantiate_binder_with_fresh_vars(
-                        call_expr.span,
-                        infer::FnCall,
-                        closure_sig,
-                    );
-                    let adjustments = self.adjust_steps(autoderef);
-                    self.record_deferred_call_resolution(
-                        def_id,
-                        DeferredCallResolution {
-                            call_expr,
-                            callee_expr,
-                            adjusted_ty,
-                            adjustments,
-                            fn_sig: closure_sig,
-                            closure_args: args,
-                        },
-                    );
-                    return Some(CallStep::DeferredClosure(def_id, closure_sig));
-                }
+            // When calling a `CoroutineClosure` that is local to the body, we will
+            // not know what its `closure_kind` is yet. Instead, just fill in the
+            // signature with an infer var for the `tupled_upvars_ty` of the coroutine,
+            // and record a deferred call resolution which will constrain that var
+            // as part of `AsyncFn*` trait confirmation.
+            ty::CoroutineClosure(def_id, args) if self.closure_kind(adjusted_ty).is_none() => {
+                let def_id = def_id.expect_local();
+                let closure_args = args.as_coroutine_closure();
+                let coroutine_closure_sig = self.instantiate_binder_with_fresh_vars(
+                    call_expr.span,
+                    infer::FnCall,
+                    closure_args.coroutine_closure_sig(),
+                );
+                let tupled_upvars_ty = self.next_ty_var(TypeVariableOrigin {
+                    kind: TypeVariableOriginKind::TypeInference,
+                    span: callee_expr.span,
+                });
+                let call_sig = self.tcx.mk_fn_sig(
+                    [coroutine_closure_sig.tupled_inputs_ty],
+                    coroutine_closure_sig.to_coroutine(
+                        self.tcx,
+                        closure_args.parent_args(),
+                        // Inherit the kind ty of the closure, since we're calling this
+                        // coroutine with the most relaxed `AsyncFn*` trait that we can.
+                        // We don't necessarily need to do this here, but it saves us
+                        // computing one more infer var that will get constrained later.
+                        closure_args.kind_ty(),
+                        self.tcx.coroutine_for_closure(def_id),
+                        tupled_upvars_ty,
+                    ),
+                    coroutine_closure_sig.c_variadic,
+                    coroutine_closure_sig.unsafety,
+                    coroutine_closure_sig.abi,
+                );
+                let adjustments = self.adjust_steps(autoderef);
+                self.record_deferred_call_resolution(
+                    def_id,
+                    DeferredCallResolution {
+                        call_expr,
+                        callee_expr,
+                        closure_ty: adjusted_ty,
+                        adjustments,
+                        fn_sig: call_sig,
+                    },
+                );
+                return Some(CallStep::DeferredClosure(def_id, call_sig));
             }
 
             // Hack: we know that there are traits implementing Fn for &F
@@ -886,10 +930,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 pub struct DeferredCallResolution<'tcx> {
     call_expr: &'tcx hir::Expr<'tcx>,
     callee_expr: &'tcx hir::Expr<'tcx>,
-    adjusted_ty: Ty<'tcx>,
+    closure_ty: Ty<'tcx>,
     adjustments: Vec<Adjustment<'tcx>>,
     fn_sig: ty::FnSig<'tcx>,
-    closure_args: GenericArgsRef<'tcx>,
 }
 
 impl<'a, 'tcx> DeferredCallResolution<'tcx> {
@@ -898,10 +941,10 @@ impl<'a, 'tcx> DeferredCallResolution<'tcx> {
 
         // we should not be invoked until the closure kind has been
         // determined by upvar inference
-        assert!(fcx.closure_kind(self.closure_args).is_some());
+        assert!(fcx.closure_kind(self.closure_ty).is_some());
 
         // We may now know enough to figure out fn vs fnmut etc.
-        match fcx.try_overloaded_call_traits(self.call_expr, self.adjusted_ty, None) {
+        match fcx.try_overloaded_call_traits(self.call_expr, self.closure_ty, None) {
             Some((autoref, method_callee)) => {
                 // One problem is that when we get here, we are going
                 // to have a newly instantiated function signature
@@ -937,7 +980,7 @@ impl<'a, 'tcx> DeferredCallResolution<'tcx> {
                 span_bug!(
                     self.call_expr.span,
                     "Expected to find a suitable `Fn`/`FnMut`/`FnOnce` implementation for `{}`",
-                    self.adjusted_ty
+                    self.closure_ty
                 )
             }
         }
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index a0ac839f3dd..58823ea30ce 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -133,6 +133,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             | ty::FnDef(..)
             | ty::FnPtr(..)
             | ty::Closure(..)
+            | ty::CoroutineClosure(..)
             | ty::Coroutine(..)
             | ty::Adt(..)
             | ty::Never
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index f51cc97b45d..a985fa201d0 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -63,7 +63,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             None => (None, None),
         };
 
-        let ClosureSignatures { bound_sig, liberated_sig } =
+        let ClosureSignatures { bound_sig, mut liberated_sig } =
             self.sig_of_closure(expr_def_id, closure.fn_decl, closure.kind, expected_sig);
 
         debug!(?bound_sig, ?liberated_sig);
@@ -125,7 +125,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)
                     | hir::CoroutineKind::Coroutine(_) => {
                         let yield_ty = self.next_ty_var(TypeVariableOrigin {
-                            kind: TypeVariableOriginKind::TypeInference,
+                            kind: TypeVariableOriginKind::ClosureSynthetic,
                             span: expr_span,
                         });
                         self.require_type_is_sized(yield_ty, expr_span, traits::SizedYieldType);
@@ -137,7 +137,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // not a problem.
                     hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _) => {
                         let yield_ty = self.next_ty_var(TypeVariableOrigin {
-                            kind: TypeVariableOriginKind::TypeInference,
+                            kind: TypeVariableOriginKind::ClosureSynthetic,
                             span: expr_span,
                         });
                         self.require_type_is_sized(yield_ty, expr_span, traits::SizedYieldType);
@@ -166,8 +166,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let resume_ty = liberated_sig.inputs().get(0).copied().unwrap_or(tcx.types.unit);
 
                 let interior = self.next_ty_var(TypeVariableOrigin {
-                    kind: TypeVariableOriginKind::MiscVariable,
-                    span: body.value.span,
+                    kind: TypeVariableOriginKind::ClosureSynthetic,
+                    span: expr_span,
                 });
                 self.deferred_coroutine_interiors.borrow_mut().push((
                     expr_def_id,
@@ -175,10 +175,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     interior,
                 ));
 
+                // Coroutines that come from coroutine closures have not yet determined
+                // their kind ty, so make a fresh infer var which will be constrained
+                // later during upvar analysis. Regular coroutines always have the kind
+                // ty of `().`
+                let kind_ty = match kind {
+                    hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Closure) => self
+                        .next_ty_var(TypeVariableOrigin {
+                            kind: TypeVariableOriginKind::ClosureSynthetic,
+                            span: expr_span,
+                        }),
+                    _ => tcx.types.unit,
+                };
+
                 let coroutine_args = ty::CoroutineArgs::new(
                     tcx,
                     ty::CoroutineArgsParts {
                         parent_args,
+                        kind_ty,
                         resume_ty,
                         yield_ty,
                         return_ty: liberated_sig.output(),
@@ -192,6 +206,94 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     Some(CoroutineTypes { resume_ty, yield_ty }),
                 )
             }
+            hir::ClosureKind::CoroutineClosure(kind) => {
+                // async closures always return the type ascribed after the `->` (if present),
+                // and yield `()`.
+                let (bound_return_ty, bound_yield_ty) = match kind {
+                    hir::CoroutineDesugaring::Async => {
+                        (bound_sig.skip_binder().output(), tcx.types.unit)
+                    }
+                    hir::CoroutineDesugaring::Gen | hir::CoroutineDesugaring::AsyncGen => {
+                        todo!("`gen` and `async gen` closures not supported yet")
+                    }
+                };
+                // Compute all of the variables that will be used to populate the coroutine.
+                let resume_ty = self.next_ty_var(TypeVariableOrigin {
+                    kind: TypeVariableOriginKind::ClosureSynthetic,
+                    span: expr_span,
+                });
+                let interior = self.next_ty_var(TypeVariableOrigin {
+                    kind: TypeVariableOriginKind::ClosureSynthetic,
+                    span: expr_span,
+                });
+                let closure_kind_ty = self.next_ty_var(TypeVariableOrigin {
+                    // FIXME(eddyb) distinguish closure kind inference variables from the rest.
+                    kind: TypeVariableOriginKind::ClosureSynthetic,
+                    span: expr_span,
+                });
+                let coroutine_captures_by_ref_ty = self.next_ty_var(TypeVariableOrigin {
+                    kind: TypeVariableOriginKind::ClosureSynthetic,
+                    span: expr_span,
+                });
+                let closure_args = ty::CoroutineClosureArgs::new(
+                    tcx,
+                    ty::CoroutineClosureArgsParts {
+                        parent_args,
+                        closure_kind_ty,
+                        signature_parts_ty: Ty::new_fn_ptr(
+                            tcx,
+                            bound_sig.map_bound(|sig| {
+                                tcx.mk_fn_sig(
+                                    [
+                                        resume_ty,
+                                        Ty::new_tup_from_iter(tcx, sig.inputs().iter().copied()),
+                                    ],
+                                    Ty::new_tup(tcx, &[bound_yield_ty, bound_return_ty]),
+                                    sig.c_variadic,
+                                    sig.unsafety,
+                                    sig.abi,
+                                )
+                            }),
+                        ),
+                        tupled_upvars_ty,
+                        coroutine_captures_by_ref_ty,
+                        coroutine_witness_ty: interior,
+                    },
+                );
+
+                let coroutine_upvars_ty = self.next_ty_var(TypeVariableOrigin {
+                    kind: TypeVariableOriginKind::ClosureSynthetic,
+                    span: expr_span,
+                });
+
+                // We need to turn the liberated signature that we got from HIR, which
+                // looks something like `|Args...| -> T`, into a signature that is suitable
+                // for type checking the inner body of the closure, which always returns a
+                // coroutine. To do so, we use the `CoroutineClosureSignature` to compute
+                // the coroutine type, filling in the tupled_upvars_ty and kind_ty with infer
+                // vars which will get constrained during upvar analysis.
+                let coroutine_output_ty = tcx.liberate_late_bound_regions(
+                    expr_def_id.to_def_id(),
+                    closure_args.coroutine_closure_sig().map_bound(|sig| {
+                        sig.to_coroutine(
+                            tcx,
+                            parent_args,
+                            closure_kind_ty,
+                            tcx.coroutine_for_closure(expr_def_id),
+                            coroutine_upvars_ty,
+                        )
+                    }),
+                );
+                liberated_sig = tcx.mk_fn_sig(
+                    liberated_sig.inputs().iter().copied(),
+                    coroutine_output_ty,
+                    liberated_sig.c_variadic,
+                    liberated_sig.unsafety,
+                    liberated_sig.abi,
+                );
+
+                (Ty::new_coroutine_closure(tcx, expr_def_id.to_def_id(), closure_args.args), None)
+            }
         };
 
         check_fn(
@@ -690,7 +792,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     _,
                 ))
                 | hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(_))
-                | hir::ClosureKind::Closure => astconv.ty_infer(None, decl.output.span()),
+                | hir::ClosureKind::Closure
+                | hir::ClosureKind::CoroutineClosure(_) => {
+                    astconv.ty_infer(None, decl.output.span())
+                }
             },
         };
 
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 1adde8c21b8..54664f38b19 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -1118,7 +1118,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // We won't diverge unless both branches do (or the condition does).
             self.diverges.set(cond_diverges | then_diverges & else_diverges);
         } else {
-            self.if_fallback_coercion(sp, then_expr, &mut coerce);
+            self.if_fallback_coercion(sp, cond_expr, then_expr, &mut coerce);
 
             // If the condition is false we can't diverge.
             self.diverges.set(cond_diverges);
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 904961d9eba..007df203f71 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -57,6 +57,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         match ty.kind() {
             // Not all of these (e.g., unsafe fns) implement `FnOnce`,
             // so we look for these beforehand.
+            // FIXME(async_closures): These don't impl `FnOnce` by default.
             ty::Closure(..) | ty::FnDef(..) | ty::FnPtr(_) => true,
             // If it's not a simple function, look for things which implement `FnOnce`.
             _ => {
@@ -540,6 +541,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let mut bound_spans: SortedMap<Span, Vec<String>> = Default::default();
         let mut restrict_type_params = false;
+        let mut suggested_derive = false;
         let mut unsatisfied_bounds = false;
         if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) {
             let msg = "consider using `len` instead";
@@ -554,6 +556,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     "`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement"
                 ));
             }
+        } else if !unsatisfied_predicates.is_empty() && matches!(rcvr_ty.kind(), ty::Param(_)) {
+            // We special case the situation where we are looking for `_` in
+            // `<TypeParam as _>::method` because otherwise the machinery will look for blanket
+            // implementations that have unsatisfied trait bounds to suggest, leading us to claim
+            // things like "we're looking for a trait with method `cmp`, both `Iterator` and `Ord`
+            // have one, in order to implement `Ord` you need to restrict `TypeParam: FnPtr` so
+            // that `impl<T: FnPtr> Ord for T` can apply", which is not what we want. We have a type
+            // parameter, we want to directly say "`Ord::cmp` and `Iterator::cmp` exist, restrict
+            // `TypeParam: Ord` or `TypeParam: Iterator`"". That is done further down when calling
+            // `self.suggest_traits_to_import`, so we ignore the `unsatisfied_predicates`
+            // suggestions.
         } else if !unsatisfied_predicates.is_empty() {
             let mut type_params = FxIndexMap::default();
 
@@ -916,20 +929,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .enumerate()
                 .collect::<Vec<(usize, String)>>();
 
-            for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
-                restrict_type_params = true;
-                // #74886: Sort here so that the output is always the same.
-                let obligations = obligations.into_sorted_stable_ord();
-                err.span_suggestion_verbose(
-                    span,
-                    format!(
-                        "consider restricting the type parameter{s} to satisfy the \
-                         trait bound{s}",
-                        s = pluralize!(obligations.len())
-                    ),
-                    format!("{} {}", add_where_or_comma, obligations.join(", ")),
-                    Applicability::MaybeIncorrect,
-                );
+            if !matches!(rcvr_ty.peel_refs().kind(), ty::Param(_)) {
+                for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
+                    restrict_type_params = true;
+                    // #74886: Sort here so that the output is always the same.
+                    let obligations = obligations.into_sorted_stable_ord();
+                    err.span_suggestion_verbose(
+                        span,
+                        format!(
+                            "consider restricting the type parameter{s} to satisfy the trait \
+                             bound{s}",
+                            s = pluralize!(obligations.len())
+                        ),
+                        format!("{} {}", add_where_or_comma, obligations.join(", ")),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
             }
 
             bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically.
@@ -977,7 +992,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         "the following trait bounds were not satisfied:\n{bound_list}"
                     ));
                 }
-                self.suggest_derive(&mut err, unsatisfied_predicates);
+                suggested_derive = self.suggest_derive(&mut err, unsatisfied_predicates);
 
                 unsatisfied_bounds = true;
             }
@@ -1200,7 +1215,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             );
         }
 
-        if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params {
+        if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params || suggested_derive {
         } else {
             self.suggest_traits_to_import(
                 &mut err,
@@ -1210,7 +1225,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 args.map(|args| args.len() + 1),
                 source,
                 no_match_data.out_of_scope_traits.clone(),
-                unsatisfied_predicates,
                 static_candidates,
                 unsatisfied_bounds,
                 expected.only_has_type(self),
@@ -1325,7 +1339,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         }
         self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected);
-        return Some(err);
+        Some(err)
     }
 
     fn note_candidates_on_method_error(
@@ -2470,7 +2484,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             Option<ty::Predicate<'tcx>>,
             Option<ObligationCause<'tcx>>,
         )],
-    ) {
+    ) -> bool {
         let mut derives = self.note_predicate_source_and_get_derives(err, unsatisfied_predicates);
         derives.sort();
         derives.dedup();
@@ -2495,6 +2509,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 Applicability::MaybeIncorrect,
             );
         }
+        !derives_grouped.is_empty()
     }
 
     fn note_derefed_ty_has_method(
@@ -2697,11 +2712,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         inputs_len: Option<usize>,
         source: SelfSource<'tcx>,
         valid_out_of_scope_traits: Vec<DefId>,
-        unsatisfied_predicates: &[(
-            ty::Predicate<'tcx>,
-            Option<ty::Predicate<'tcx>>,
-            Option<ObligationCause<'tcx>>,
-        )],
         static_candidates: &[CandidateSource],
         unsatisfied_bounds: bool,
         return_type: Option<Ty<'tcx>>,
@@ -2918,19 +2928,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // this isn't perfect (that is, there are cases when
                 // implementing a trait would be legal but is rejected
                 // here).
-                unsatisfied_predicates.iter().all(|(p, _, _)| {
-                    match p.kind().skip_binder() {
-                        // Hide traits if they are present in predicates as they can be fixed without
-                        // having to implement them.
-                        ty::PredicateKind::Clause(ty::ClauseKind::Trait(t)) => {
-                            t.def_id() == info.def_id
-                        }
-                        ty::PredicateKind::Clause(ty::ClauseKind::Projection(p)) => {
-                            p.projection_ty.def_id == info.def_id
-                        }
-                        _ => false,
-                    }
-                }) && (type_is_local || info.def_id.is_local())
+                (type_is_local || info.def_id.is_local())
                     && !self.tcx.trait_is_auto(info.def_id)
                     && self
                         .associated_value(info.def_id, item_name)
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 82c5e566f16..c4773a88521 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -170,9 +170,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) {
         // Extract the type of the closure.
         let ty = self.node_ty(closure_hir_id);
-        let (closure_def_id, args) = match *ty.kind() {
-            ty::Closure(def_id, args) => (def_id, UpvarArgs::Closure(args)),
-            ty::Coroutine(def_id, args) => (def_id, UpvarArgs::Coroutine(args)),
+        let (closure_def_id, args, infer_kind) = match *ty.kind() {
+            ty::Closure(def_id, args) => {
+                (def_id, UpvarArgs::Closure(args), self.closure_kind(ty).is_none())
+            }
+            ty::CoroutineClosure(def_id, args) => {
+                (def_id, UpvarArgs::CoroutineClosure(args), self.closure_kind(ty).is_none())
+            }
+            ty::Coroutine(def_id, args) => (def_id, UpvarArgs::Coroutine(args), false),
             ty::Error(_) => {
                 // #51714: skip analysis when we have already encountered type errors
                 return;
@@ -188,18 +193,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
         let closure_def_id = closure_def_id.expect_local();
 
-        let infer_kind = if let UpvarArgs::Closure(closure_args) = args {
-            self.closure_kind(closure_args).is_none().then_some(closure_args)
-        } else {
-            None
-        };
-
         assert_eq!(self.tcx.hir().body_owner_def_id(body.id()), closure_def_id);
         let mut delegate = InferBorrowKind {
             closure_def_id,
             capture_information: Default::default(),
             fake_reads: Default::default(),
         };
+
+        // As noted in `lower_coroutine_body_with_moved_arguments`, we default the capture mode
+        // to `ByRef` for the `async {}` block internal to async fns/closure. This means
+        // that we would *not* be moving all of the parameters into the async block by default.
+        //
+        // We force all of these arguments to be captured by move before we do expr use analysis.
+        //
+        // FIXME(async_closures): This could be cleaned up. It's a bit janky that we're just
+        // moving all of the `LocalSource::AsyncFn` locals here.
+        if let Some(hir::CoroutineKind::Desugared(
+            _,
+            hir::CoroutineSource::Fn | hir::CoroutineSource::Closure,
+        )) = self.tcx.coroutine_kind(closure_def_id)
+        {
+            let hir::ExprKind::Block(block, _) = body.value.kind else {
+                bug!();
+            };
+            for stmt in block.stmts {
+                let hir::StmtKind::Local(hir::Local {
+                    init: Some(init),
+                    source: hir::LocalSource::AsyncFn,
+                    pat,
+                    ..
+                }) = stmt.kind
+                else {
+                    bug!();
+                };
+                let hir::PatKind::Binding(hir::BindingAnnotation(hir::ByRef::No, _), _, _, _) =
+                    pat.kind
+                else {
+                    // Complex pattern, skip the non-upvar local.
+                    continue;
+                };
+                let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = init.kind else {
+                    bug!();
+                };
+                let hir::def::Res::Local(local_id) = path.res else {
+                    bug!();
+                };
+                let place = self.place_for_root_variable(closure_def_id, local_id);
+                delegate.capture_information.push((
+                    place,
+                    ty::CaptureInfo {
+                        capture_kind_expr_id: Some(init.hir_id),
+                        path_expr_id: Some(init.hir_id),
+                        capture_kind: UpvarCapture::ByValue,
+                    },
+                ));
+            }
+        }
+
         euv::ExprUseVisitor::new(
             &mut delegate,
             &self.infcx,
@@ -257,10 +307,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let before_feature_tys = self.final_upvar_tys(closure_def_id);
 
-        if let Some(closure_args) = infer_kind {
+        if infer_kind {
             // Unify the (as yet unbound) type variable in the closure
             // args with the kind we inferred.
-            let closure_kind_ty = closure_args.as_closure().kind_ty();
+            let closure_kind_ty = match args {
+                UpvarArgs::Closure(args) => args.as_closure().kind_ty(),
+                UpvarArgs::CoroutineClosure(args) => args.as_coroutine_closure().kind_ty(),
+                UpvarArgs::Coroutine(_) => unreachable!("coroutines don't have an inferred kind"),
+            };
             self.demand_eqtype(
                 span,
                 Ty::from_closure_kind(self.tcx, closure_kind),
@@ -282,6 +336,84 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         }
 
+        // For coroutine-closures, we additionally must compute the
+        // `coroutine_captures_by_ref_ty` type, which is used to generate the by-ref
+        // version of the coroutine-closure's output coroutine.
+        if let UpvarArgs::CoroutineClosure(args) = args {
+            let closure_env_region: ty::Region<'_> = ty::Region::new_bound(
+                self.tcx,
+                ty::INNERMOST,
+                ty::BoundRegion {
+                    var: ty::BoundVar::from_usize(0),
+                    kind: ty::BoundRegionKind::BrEnv,
+                },
+            );
+            let tupled_upvars_ty_for_borrow = Ty::new_tup_from_iter(
+                self.tcx,
+                self.typeck_results
+                    .borrow()
+                    .closure_min_captures_flattened(
+                        self.tcx.coroutine_for_closure(closure_def_id).expect_local(),
+                    )
+                    // Skip the captures that are just moving the closure's args
+                    // into the coroutine. These are always by move, and we append
+                    // those later in the `CoroutineClosureSignature` helper functions.
+                    .skip(
+                        args.as_coroutine_closure()
+                            .coroutine_closure_sig()
+                            .skip_binder()
+                            .tupled_inputs_ty
+                            .tuple_fields()
+                            .len(),
+                    )
+                    .map(|captured_place| {
+                        let upvar_ty = captured_place.place.ty();
+                        let capture = captured_place.info.capture_kind;
+                        // Not all upvars are captured by ref, so use
+                        // `apply_capture_kind_on_capture_ty` to ensure that we
+                        // compute the right captured type.
+                        apply_capture_kind_on_capture_ty(
+                            self.tcx,
+                            upvar_ty,
+                            capture,
+                            Some(closure_env_region),
+                        )
+                    }),
+            );
+            let coroutine_captures_by_ref_ty = Ty::new_fn_ptr(
+                self.tcx,
+                ty::Binder::bind_with_vars(
+                    self.tcx.mk_fn_sig(
+                        [],
+                        tupled_upvars_ty_for_borrow,
+                        false,
+                        hir::Unsafety::Normal,
+                        rustc_target::spec::abi::Abi::Rust,
+                    ),
+                    self.tcx.mk_bound_variable_kinds(&[ty::BoundVariableKind::Region(
+                        ty::BoundRegionKind::BrEnv,
+                    )]),
+                ),
+            );
+            self.demand_eqtype(
+                span,
+                args.as_coroutine_closure().coroutine_captures_by_ref_ty(),
+                coroutine_captures_by_ref_ty,
+            );
+
+            // Additionally, we can now constrain the coroutine's kind type.
+            let ty::Coroutine(_, coroutine_args) =
+                *self.typeck_results.borrow().expr_ty(body.value).kind()
+            else {
+                bug!();
+            };
+            self.demand_eqtype(
+                span,
+                coroutine_args.as_coroutine().kind_ty(),
+                Ty::from_closure_kind(self.tcx, closure_kind),
+            );
+        }
+
         self.log_closure_min_capture_info(closure_def_id, span);
 
         // Now that we've analyzed the closure, we know how each
@@ -551,7 +683,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             };
 
             // Go through each entry in the current list of min_captures
-            // - if ancestor is found, update it's capture kind to account for current place's
+            // - if ancestor is found, update its capture kind to account for current place's
             // capture information.
             //
             // - if descendant is found, remove it from the list, and update the current place's
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index e4b37f05b77..156a4f71017 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -414,6 +414,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
             }
 
             ty::Closure(..)
+            | ty::CoroutineClosure(..)
             | ty::Coroutine(..)
             | ty::CoroutineWitness(..)
             | ty::Bool
@@ -480,7 +481,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
             }
             ty::ConstKind::Infer(InferConst::EffectVar(vid)) => {
                 match self.infcx.unwrap().probe_effect_var(vid) {
-                    Some(value) => return self.fold_const(value.as_const(self.tcx)),
+                    Some(value) => return self.fold_const(value),
                     None => {
                         return self.canonicalize_const_var(
                             CanonicalVarInfo { kind: CanonicalVarKind::Effect },
diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs
index 386fdb09ba5..1f68a5a9c61 100644
--- a/compiler/rustc_infer/src/infer/canonical/mod.rs
+++ b/compiler/rustc_infer/src/infer/canonical/mod.rs
@@ -24,6 +24,7 @@
 use crate::infer::{ConstVariableOrigin, ConstVariableOriginKind};
 use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_index::IndexVec;
+use rustc_middle::infer::unify_key::EffectVarValue;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::GenericArg;
 use rustc_middle::ty::{self, List, Ty, TyCtxt};
@@ -152,7 +153,12 @@ impl<'tcx> InferCtxt<'tcx> {
                 )
                 .into(),
             CanonicalVarKind::Effect => {
-                let vid = self.inner.borrow_mut().effect_unification_table().new_key(None).vid;
+                let vid = self
+                    .inner
+                    .borrow_mut()
+                    .effect_unification_table()
+                    .new_key(EffectVarValue::Unknown)
+                    .vid;
                 ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(vid), self.tcx.types.bool)
                     .into()
             }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index b8344310d5d..59bed38ec2a 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -71,6 +71,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_middle::dep_graph::DepContext;
 use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError};
 use rustc_middle::ty::relate::{self, RelateResult, TypeRelation};
+use rustc_middle::ty::ToPredicate;
 use rustc_middle::ty::{
     self, error::TypeError, IsSuggestable, List, Region, Ty, TyCtxt, TypeFoldable,
     TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
@@ -519,10 +520,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit();
                     }
 
-                    RegionResolutionError::CannotNormalize(ty, origin) => {
+                    RegionResolutionError::CannotNormalize(clause, origin) => {
+                        let clause: ty::Clause<'tcx> =
+                            clause.map_bound(ty::ClauseKind::TypeOutlives).to_predicate(self.tcx);
                         self.tcx
                             .dcx()
-                            .struct_span_err(origin.span(), format!("cannot normalize `{ty}`"))
+                            .struct_span_err(origin.span(), format!("cannot normalize `{clause}`"))
                             .emit();
                     }
                 }
@@ -2839,7 +2842,11 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
             // say, also take a look at the error code, maybe we can
             // tailor to that.
             _ => match terr {
-                TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_coroutine() => Error0644,
+                TypeError::CyclicTy(ty)
+                    if ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure() =>
+                {
+                    Error0644
+                }
                 TypeError::IntrinsicCast => Error0308,
                 _ => Error0308,
             },
@@ -2886,7 +2893,9 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
             // say, also take a look at the error code, maybe we can
             // tailor to that.
             _ => match terr {
-                TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_coroutine() => {
+                TypeError::CyclicTy(ty)
+                    if ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure() =>
+                {
                     ObligationCauseFailureCode::ClosureSelfref { span }
                 }
                 TypeError::IntrinsicCast => {
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 7287fc26053..c637ab31cd2 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
@@ -883,7 +883,10 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
                 GenericArgKind::Type(ty) => {
                     if matches!(
                         ty.kind(),
-                        ty::Alias(ty::Opaque, ..) | ty::Closure(..) | ty::Coroutine(..)
+                        ty::Alias(ty::Opaque, ..)
+                            | ty::Closure(..)
+                            | ty::CoroutineClosure(..)
+                            | ty::Coroutine(..)
                     ) {
                         // Opaque types can't be named by the user right now.
                         //
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
index 0452d4fe6c8..f884ca83073 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
@@ -228,7 +228,10 @@ impl<T> Trait<T> for X {
                              #traits-as-parameters",
                         );
                     }
-                    (ty::Param(p), ty::Closure(..) | ty::Coroutine(..)) => {
+                    (
+                        ty::Param(p),
+                        ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..),
+                    ) => {
                         let generics = tcx.generics_of(body_owner_def_id);
                         if let Some(param) = generics.opt_type_param(p, tcx) {
                             let p_span = tcx.def_span(param.def_id);
@@ -497,7 +500,7 @@ impl<T> Trait<T> for X {
             }
             CyclicTy(ty) => {
                 // Watch out for various cases of cyclic types and try to explain.
-                if ty.is_closure() || ty.is_coroutine() {
+                if ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure() {
                     diag.note(
                         "closures cannot capture themselves or take themselves as argument;\n\
                          this error may be the result of a recent compiler bug-fix,\n\
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index d256994d8d1..2d5fa1b5c70 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -151,13 +151,8 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
                 self.freshen_const(opt_ct, ty::InferConst::Var(v), ty::InferConst::Fresh, ct.ty())
             }
             ty::ConstKind::Infer(ty::InferConst::EffectVar(v)) => {
-                let opt_ct = self
-                    .infcx
-                    .inner
-                    .borrow_mut()
-                    .effect_unification_table()
-                    .probe_value(v)
-                    .map(|effect| effect.as_const(self.infcx.tcx));
+                let opt_ct =
+                    self.infcx.inner.borrow_mut().effect_unification_table().probe_value(v).known();
                 self.freshen_const(
                     opt_ct,
                     ty::InferConst::EffectVar(v),
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index 4a1169e68e0..6137506d4a9 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -99,7 +99,7 @@ pub enum RegionResolutionError<'tcx> {
         Region<'tcx>,          // the placeholder `'b`
     ),
 
-    CannotNormalize(Ty<'tcx>, SubregionOrigin<'tcx>),
+    CannotNormalize(ty::PolyTypeOutlivesPredicate<'tcx>, SubregionOrigin<'tcx>),
 }
 
 impl<'tcx> RegionResolutionError<'tcx> {
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 0a39fe007fd..2d8b47a9cc0 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -8,6 +8,7 @@ pub use self::ValuePairs::*;
 pub use relate::combine::ObligationEmittingRelation;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::undo_log::UndoLogs;
+use rustc_middle::infer::unify_key::EffectVarValue;
 use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey};
 
 use self::opaque_types::OpaqueTypeStorage;
@@ -25,8 +26,8 @@ use rustc_data_structures::unify as ut;
 use rustc_errors::{DiagCtxt, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
+use rustc_middle::infer::unify_key::ConstVariableValue;
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
-use rustc_middle::infer::unify_key::{ConstVariableValue, EffectVarValue};
 use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::traits::{select, DefiningAnchor};
@@ -818,7 +819,7 @@ impl<'tcx> InferCtxt<'tcx> {
 
         (0..table.len())
             .map(|i| ty::EffectVid::from_usize(i))
-            .filter(|&vid| table.probe_value(vid).is_none())
+            .filter(|&vid| table.probe_value(vid).is_unknown())
             .map(|v| {
                 ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(v), self.tcx.types.bool)
             })
@@ -1236,7 +1237,8 @@ impl<'tcx> InferCtxt<'tcx> {
     }
 
     pub fn var_for_effect(&self, param: &ty::GenericParamDef) -> GenericArg<'tcx> {
-        let effect_vid = self.inner.borrow_mut().effect_unification_table().new_key(None).vid;
+        let effect_vid =
+            self.inner.borrow_mut().effect_unification_table().new_key(EffectVarValue::Unknown).vid;
         let ty = self
             .tcx
             .type_of(param.def_id)
@@ -1416,8 +1418,8 @@ impl<'tcx> InferCtxt<'tcx> {
         }
     }
 
-    pub fn probe_effect_var(&self, vid: EffectVid) -> Option<EffectVarValue<'tcx>> {
-        self.inner.borrow_mut().effect_unification_table().probe_value(vid)
+    pub fn probe_effect_var(&self, vid: EffectVid) -> Option<ty::Const<'tcx>> {
+        self.inner.borrow_mut().effect_unification_table().probe_value(vid).known()
     }
 
     /// Attempts to resolve all type/region/const variables in
@@ -1538,9 +1540,13 @@ impl<'tcx> InferCtxt<'tcx> {
     /// Obtains the latest type of the given closure; this may be a
     /// closure in the current function, in which case its
     /// `ClosureKind` may not yet be known.
-    pub fn closure_kind(&self, closure_args: GenericArgsRef<'tcx>) -> Option<ty::ClosureKind> {
-        let closure_kind_ty = closure_args.as_closure().kind_ty();
-        let closure_kind_ty = self.shallow_resolve(closure_kind_ty);
+    pub fn closure_kind(&self, closure_ty: Ty<'tcx>) -> Option<ty::ClosureKind> {
+        let unresolved_kind_ty = match *closure_ty.kind() {
+            ty::Closure(_, args) => args.as_closure().kind_ty(),
+            ty::CoroutineClosure(_, args) => args.as_coroutine_closure().kind_ty(),
+            _ => bug!("unexpected type {closure_ty}"),
+        };
+        let closure_kind_ty = self.shallow_resolve(unresolved_kind_ty);
         closure_kind_ty.to_opt_closure_kind()
     }
 
@@ -1893,7 +1899,8 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ShallowResolver<'a, 'tcx> {
                 .borrow_mut()
                 .effect_unification_table()
                 .probe_value(vid)
-                .map_or(ct, |val| val.as_const(self.infcx.tcx)),
+                .known()
+                .unwrap_or(ct),
             _ => ct,
         }
     }
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index db46b39ce25..5ee0a606a5f 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -456,6 +456,17 @@ where
                 args.as_closure().sig_as_fn_ptr_ty().visit_with(self);
             }
 
+            ty::CoroutineClosure(_, args) => {
+                // Skip lifetime parameters of the enclosing item(s)
+
+                for upvar in args.as_coroutine_closure().upvar_tys() {
+                    upvar.visit_with(self);
+                }
+
+                // FIXME(async_closures): Is this the right signature to visit here?
+                args.as_coroutine_closure().signature_parts_ty().visit_with(self);
+            }
+
             ty::Coroutine(_, args) => {
                 // Skip lifetime parameters of the enclosing item(s)
                 // Also skip the witness type, because that has no free regions.
diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs
index fc3d8375873..7dd1ec32542 100644
--- a/compiler/rustc_infer/src/infer/outlives/components.rs
+++ b/compiler/rustc_infer/src/infer/outlives/components.rs
@@ -103,6 +103,11 @@ fn compute_components<'tcx>(
                 compute_components(tcx, tupled_ty, out, visited);
             }
 
+            ty::CoroutineClosure(_, args) => {
+                let tupled_ty = args.as_coroutine_closure().tupled_upvars_ty();
+                compute_components(tcx, tupled_ty, out, visited);
+            }
+
             ty::Coroutine(_, args) => {
                 // Same as the closure case
                 let tupled_ty = args.as_coroutine().tupled_upvars_ty();
diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs
index 926e198b219..a4f9316b502 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -4,8 +4,8 @@ use super::region_constraints::RegionConstraintData;
 use super::{InferCtxt, RegionResolutionError, SubregionOrigin};
 use crate::infer::free_regions::RegionRelations;
 use crate::infer::lexical_region_resolve;
-use rustc_middle::traits::query::OutlivesBound;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::traits::query::{NoSolution, OutlivesBound};
+use rustc_middle::ty;
 
 pub mod components;
 pub mod env;
@@ -49,12 +49,15 @@ impl<'tcx> InferCtxt<'tcx> {
     pub fn resolve_regions_with_normalize(
         &self,
         outlives_env: &OutlivesEnvironment<'tcx>,
-        deeply_normalize_ty: impl Fn(Ty<'tcx>, SubregionOrigin<'tcx>) -> Result<Ty<'tcx>, Ty<'tcx>>,
+        deeply_normalize_ty: impl Fn(
+            ty::PolyTypeOutlivesPredicate<'tcx>,
+            SubregionOrigin<'tcx>,
+        ) -> Result<ty::PolyTypeOutlivesPredicate<'tcx>, NoSolution>,
     ) -> Vec<RegionResolutionError<'tcx>> {
         match self.process_registered_region_obligations(outlives_env, deeply_normalize_ty) {
             Ok(()) => {}
-            Err((ty, origin)) => {
-                return vec![RegionResolutionError::CannotNormalize(ty, origin)];
+            Err((clause, origin)) => {
+                return vec![RegionResolutionError::CannotNormalize(clause, origin)];
             }
         };
 
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index b10bf98e8b5..7208f17fb34 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -68,8 +68,9 @@ use crate::infer::{
 use crate::traits::{ObligationCause, ObligationCauseCode};
 use rustc_data_structures::undo_log::UndoLogs;
 use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::ty::GenericArgKind;
+use rustc_middle::traits::query::NoSolution;
 use rustc_middle::ty::{self, GenericArgsRef, Region, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{GenericArgKind, PolyTypeOutlivesPredicate};
 use rustc_span::DUMMY_SP;
 use smallvec::smallvec;
 
@@ -125,11 +126,15 @@ impl<'tcx> InferCtxt<'tcx> {
     /// invoked after all type-inference variables have been bound --
     /// right before lexical region resolution.
     #[instrument(level = "debug", skip(self, outlives_env, deeply_normalize_ty))]
-    pub fn process_registered_region_obligations<E>(
+    pub fn process_registered_region_obligations(
         &self,
         outlives_env: &OutlivesEnvironment<'tcx>,
-        mut deeply_normalize_ty: impl FnMut(Ty<'tcx>, SubregionOrigin<'tcx>) -> Result<Ty<'tcx>, E>,
-    ) -> Result<(), (E, SubregionOrigin<'tcx>)> {
+        mut deeply_normalize_ty: impl FnMut(
+            PolyTypeOutlivesPredicate<'tcx>,
+            SubregionOrigin<'tcx>,
+        )
+            -> Result<PolyTypeOutlivesPredicate<'tcx>, NoSolution>,
+    ) -> Result<(), (PolyTypeOutlivesPredicate<'tcx>, SubregionOrigin<'tcx>)> {
         assert!(!self.in_snapshot(), "cannot process registered region obligations in a snapshot");
 
         let normalized_caller_bounds: Vec<_> = outlives_env
@@ -137,38 +142,53 @@ impl<'tcx> InferCtxt<'tcx> {
             .caller_bounds()
             .iter()
             .filter_map(|clause| {
-                let bound_clause = clause.kind();
-                let ty::ClauseKind::TypeOutlives(outlives) = bound_clause.skip_binder() else {
-                    return None;
-                };
+                let outlives = clause.as_type_outlives_clause()?;
                 Some(
                     deeply_normalize_ty(
-                        outlives.0,
+                        outlives,
                         SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP),
                     )
-                    .map(|ty| bound_clause.rebind(ty::OutlivesPredicate(ty, outlives.1))),
+                    // FIXME(-Znext-solver): How do we accurately report an error span here :(
+                    .map_err(|NoSolution| {
+                        (outlives, SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP))
+                    }),
                 )
             })
-            // FIXME(-Znext-solver): How do we accurately report an error here :(
-            .try_collect()
-            .map_err(|e| (e, SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP)))?;
-
-        let my_region_obligations = self.take_registered_region_obligations();
-
-        for RegionObligation { sup_type, sub_region, origin } in my_region_obligations {
-            let sup_type =
-                deeply_normalize_ty(sup_type, origin.clone()).map_err(|e| (e, origin.clone()))?;
-            debug!(?sup_type, ?sub_region, ?origin);
-
-            let outlives = &mut TypeOutlives::new(
-                self,
-                self.tcx,
-                outlives_env.region_bound_pairs(),
-                None,
-                &normalized_caller_bounds,
-            );
-            let category = origin.to_constraint_category();
-            outlives.type_must_outlive(origin, sup_type, sub_region, category);
+            .try_collect()?;
+
+        // Must loop since the process of normalizing may itself register region obligations.
+        for iteration in 0.. {
+            let my_region_obligations = self.take_registered_region_obligations();
+            if my_region_obligations.is_empty() {
+                break;
+            }
+
+            if !self.tcx.recursion_limit().value_within_limit(iteration) {
+                bug!(
+                    "FIXME(-Znext-solver): Overflowed when processing region obligations: {my_region_obligations:#?}"
+                );
+            }
+
+            for RegionObligation { sup_type, sub_region, origin } in my_region_obligations {
+                let outlives = ty::Binder::dummy(ty::OutlivesPredicate(sup_type, sub_region));
+                let ty::OutlivesPredicate(sup_type, sub_region) =
+                    deeply_normalize_ty(outlives, origin.clone())
+                        .map_err(|NoSolution| (outlives, origin.clone()))?
+                        .no_bound_vars()
+                        .expect("started with no bound vars, should end with no bound vars");
+
+                debug!(?sup_type, ?sub_region, ?origin);
+
+                let outlives = &mut TypeOutlives::new(
+                    self,
+                    self.tcx,
+                    outlives_env.region_bound_pairs(),
+                    None,
+                    &normalized_caller_bounds,
+                );
+                let category = origin.to_constraint_category();
+                outlives.type_must_outlive(origin, sup_type, sub_region, category);
+            }
         }
 
         Ok(())
diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs
index 1c120646f1f..13c17ee1cd2 100644
--- a/compiler/rustc_infer/src/infer/relate/combine.rs
+++ b/compiler/rustc_infer/src/infer/relate/combine.rs
@@ -202,11 +202,7 @@ impl<'tcx> InferCtxt<'tcx> {
                 ty::ConstKind::Infer(InferConst::EffectVar(a_vid)),
                 ty::ConstKind::Infer(InferConst::EffectVar(b_vid)),
             ) => {
-                self.inner
-                    .borrow_mut()
-                    .effect_unification_table()
-                    .unify_var_var(a_vid, b_vid)
-                    .map_err(|a| effect_unification_error(self.tcx, relation.a_is_expected(), a))?;
+                self.inner.borrow_mut().effect_unification_table().union(a_vid, b_vid);
                 return Ok(a);
             }
 
@@ -233,19 +229,11 @@ impl<'tcx> InferCtxt<'tcx> {
             }
 
             (ty::ConstKind::Infer(InferConst::EffectVar(vid)), _) => {
-                return self.unify_effect_variable(
-                    relation.a_is_expected(),
-                    vid,
-                    EffectVarValue::Const(b),
-                );
+                return Ok(self.unify_effect_variable(vid, b));
             }
 
             (_, ty::ConstKind::Infer(InferConst::EffectVar(vid))) => {
-                return self.unify_effect_variable(
-                    !relation.a_is_expected(),
-                    vid,
-                    EffectVarValue::Const(a),
-                );
+                return Ok(self.unify_effect_variable(vid, a));
             }
 
             (ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..))
@@ -366,18 +354,12 @@ impl<'tcx> InferCtxt<'tcx> {
         Ok(Ty::new_float(self.tcx, val))
     }
 
-    fn unify_effect_variable(
-        &self,
-        vid_is_expected: bool,
-        vid: ty::EffectVid,
-        val: EffectVarValue<'tcx>,
-    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
+    fn unify_effect_variable(&self, vid: ty::EffectVid, val: ty::Const<'tcx>) -> ty::Const<'tcx> {
         self.inner
             .borrow_mut()
             .effect_unification_table()
-            .unify_var_value(vid, Some(val))
-            .map_err(|e| effect_unification_error(self.tcx, vid_is_expected, e))?;
-        Ok(val.as_const(self.tcx))
+            .union_value(vid, EffectVarValue::Known(val));
+        val
     }
 }
 
@@ -579,11 +561,3 @@ fn float_unification_error<'tcx>(
     let (ty::FloatVarValue(a), ty::FloatVarValue(b)) = v;
     TypeError::FloatMismatch(ExpectedFound::new(a_is_expected, a, b))
 }
-
-fn effect_unification_error<'tcx>(
-    _tcx: TyCtxt<'tcx>,
-    _a_is_expected: bool,
-    (_a, _b): (EffectVarValue<'tcx>, EffectVarValue<'tcx>),
-) -> TypeError<'tcx> {
-    bug!("unexpected effect unification error")
-}
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index 959b0903127..d5999331dfa 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -237,14 +237,13 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EagerResolver<'_, 'tcx> {
             }
             ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)) => {
                 debug_assert_eq!(c.ty(), self.infcx.tcx.types.bool);
-                match self.infcx.probe_effect_var(vid) {
-                    Some(c) => c.as_const(self.infcx.tcx),
-                    None => ty::Const::new_infer(
+                self.infcx.probe_effect_var(vid).unwrap_or_else(|| {
+                    ty::Const::new_infer(
                         self.infcx.tcx,
                         ty::InferConst::EffectVar(self.infcx.root_effect_var(vid)),
                         self.infcx.tcx.types.bool,
-                    ),
-                }
+                    )
+                })
             }
             _ => {
                 if c.has_infer() {
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 2d4963a8b90..bfc4fc07d4c 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -749,6 +749,7 @@ fn test_unstable_options_tracking_hash() {
     tracked!(debug_macros, true);
     tracked!(default_hidden_visibility, Some(true));
     tracked!(dep_info_omit_d_target, true);
+    tracked!(direct_access_external_data, Some(true));
     tracked!(dual_proc_macros, true);
     tracked!(dwarf_version, Some(5));
     tracked!(emit_thin_lto, false);
diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs
index eb42730f69a..0fa61c5d87e 100644
--- a/compiler/rustc_lint/src/context/diagnostics.rs
+++ b/compiler/rustc_lint/src/context/diagnostics.rs
@@ -188,6 +188,23 @@ pub(super) fn builtin(
             #[allow(rustc::potential_query_instability)]
             let possibilities: Vec<Symbol> =
                 sess.parse_sess.check_config.expecteds.keys().copied().collect();
+
+            let mut names_possibilities: Vec<_> = if value.is_none() {
+                // We later sort and display all the possibilities, so the order here does not matter.
+                #[allow(rustc::potential_query_instability)]
+                sess.parse_sess
+                    .check_config
+                    .expecteds
+                    .iter()
+                    .filter_map(|(k, v)| match v {
+                        ExpectedValues::Some(v) if v.contains(&Some(name)) => Some(k),
+                        _ => None,
+                    })
+                    .collect()
+            } else {
+                Vec::new()
+            };
+
             let is_from_cargo = std::env::var_os("CARGO").is_some();
             let mut is_feature_cfg = name == sym::feature;
 
@@ -262,17 +279,30 @@ pub(super) fn builtin(
                 }
 
                 is_feature_cfg |= best_match == sym::feature;
-            } else if !possibilities.is_empty() {
-                let mut possibilities =
-                    possibilities.iter().map(Symbol::as_str).collect::<Vec<_>>();
-                possibilities.sort();
-                let possibilities = possibilities.join("`, `");
+            } else {
+                if !names_possibilities.is_empty() && names_possibilities.len() <= 3 {
+                    names_possibilities.sort();
+                    for cfg_name in names_possibilities.iter() {
+                        db.span_suggestion(
+                            name_span,
+                            "found config with similar value",
+                            format!("{cfg_name} = \"{name}\""),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                }
+                if !possibilities.is_empty() {
+                    let mut possibilities =
+                        possibilities.iter().map(Symbol::as_str).collect::<Vec<_>>();
+                    possibilities.sort();
+                    let possibilities = possibilities.join("`, `");
 
-                // The list of expected names can be long (even by default) and
-                // so the diagnostic produced can take a lot of space. To avoid
-                // cloging the user output we only want to print that diagnostic
-                // once.
-                db.help_once(format!("expected names are: `{possibilities}`"));
+                    // The list of expected names can be long (even by default) and
+                    // so the diagnostic produced can take a lot of space. To avoid
+                    // cloging the user output we only want to print that diagnostic
+                    // once.
+                    db.help_once(format!("expected names are: `{possibilities}`"));
+                }
             }
 
             let inst = if let Some((value, _value_span)) = value {
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 0a15671e686..1c03de410ee 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -520,6 +520,11 @@ fn register_builtins(store: &mut LintStore) {
         "illegal_floating_point_literal_pattern",
         "no longer a warning, float patterns behave the same as `==`",
     );
+    store.register_removed(
+        "nontrivial_structural_match",
+        "no longer needed, see RFC #3535 \
+         <https://rust-lang.github.io/rfcs/3535-constants-in-patterns.html> for more information",
+    );
 }
 
 fn register_internals(store: &mut LintStore) {
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index e3d3150b36e..1205395b890 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1435,6 +1435,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             | ty::Bound(..)
             | ty::Error(_)
             | ty::Closure(..)
+            | ty::CoroutineClosure(..)
             | ty::Coroutine(..)
             | ty::CoroutineWitness(..)
             | ty::Placeholder(..)
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index ea3747dfac4..9f670893b27 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -355,7 +355,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
                     Some(len) => is_ty_must_use(cx, ty, expr, span)
                         .map(|inner| MustUsePath::Array(Box::new(inner), len)),
                 },
-                ty::Closure(..) => Some(MustUsePath::Closure(span)),
+                ty::Closure(..) | ty::CoroutineClosure(..) => Some(MustUsePath::Closure(span)),
                 ty::Coroutine(def_id, ..) => {
                     // async fn should be treated as "implementor of `Future`"
                     let must_use = if cx.tcx.coroutine_is_async(def_id) {
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 07c0e75a71c..6a2a2c1e48e 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -3,6 +3,9 @@
 //! These are the built-in lints that are emitted direct in the main
 //! compiler code, rather than using their own custom pass. Those
 //! lints are all available in `rustc_lint::builtin`.
+//!
+//! When removing a lint, make sure to also add a call to `register_removed` in
+//! compiler/rustc_lint/src/lib.rs.
 
 use crate::{declare_lint, declare_lint_pass, FutureIncompatibilityReason};
 use rustc_span::edition::Edition;
@@ -66,7 +69,6 @@ declare_lint_pass! {
         MUST_NOT_SUSPEND,
         NAMED_ARGUMENTS_USED_POSITIONALLY,
         NON_EXHAUSTIVE_OMITTED_PATTERNS,
-        NONTRIVIAL_STRUCTURAL_MATCH,
         ORDER_DEPENDENT_TRAIT_OBJECTS,
         OVERLAPPING_RANGE_ENDPOINTS,
         PATTERNS_IN_FNS_WITHOUT_BODY,
@@ -2280,8 +2282,8 @@ declare_lint! {
     Warn,
     "constant used in pattern contains value of non-structural-match type in a field or a variant",
     @future_incompatible = FutureIncompatibleInfo {
-        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
-        reference: "issue #62411 <https://github.com/rust-lang/rust/issues/62411>",
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
+        reference: "issue #120362 <https://github.com/rust-lang/rust/issues/120362>",
     };
 }
 
@@ -2336,47 +2338,8 @@ declare_lint! {
     Warn,
     "pointers are not structural-match",
     @future_incompatible = FutureIncompatibleInfo {
-        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
-        reference: "issue #62411 <https://github.com/rust-lang/rust/issues/70861>",
-    };
-}
-
-declare_lint! {
-    /// The `nontrivial_structural_match` lint detects constants that are used in patterns,
-    /// whose type is not structural-match and whose initializer body actually uses values
-    /// that are not structural-match. So `Option<NotStructuralMatch>` is ok if the constant
-    /// is just `None`.
-    ///
-    /// ### Example
-    ///
-    /// ```rust,compile_fail
-    /// #![deny(nontrivial_structural_match)]
-    ///
-    /// #[derive(Copy, Clone, Debug)]
-    /// struct NoDerive(u32);
-    /// impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
-    /// impl Eq for NoDerive { }
-    /// fn main() {
-    ///     const INDEX: Option<NoDerive> = [None, Some(NoDerive(10))][0];
-    ///     match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), };
-    /// }
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// Previous versions of Rust accepted constants in patterns, even if those constants' types
-    /// did not have `PartialEq` derived. Thus the compiler falls back to runtime execution of
-    /// `PartialEq`, which can report that two constants are not equal even if they are
-    /// bit-equivalent.
-    pub NONTRIVIAL_STRUCTURAL_MATCH,
-    Warn,
-    "constant used in pattern of non-structural-match type and the constant's initializer \
-    expression contains values of non-structural-match types",
-    @future_incompatible = FutureIncompatibleInfo {
-        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
-        reference: "issue #73448 <https://github.com/rust-lang/rust/issues/73448>",
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
+        reference: "issue #120362 <https://github.com/rust-lang/rust/issues/120362>",
     };
 }
 
diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
index 5bfffc5d911..6d578c97f3f 100644
--- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
+++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
@@ -76,7 +76,6 @@ enum LLVMRustAttribute {
   SanitizeMemory = 22,
   NonLazyBind = 23,
   OptimizeNone = 24,
-  ReturnsTwice = 25,
   ReadNone = 26,
   SanitizeHWAddress = 28,
   WillReturn = 29,
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 6114f7c8678..3b6bf03686b 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -934,10 +934,8 @@ LLVMRustOptimize(
     } else {
       for (const auto &C : PipelineStartEPCallbacks)
         PB.registerPipelineStartEPCallback(C);
-      if (OptStage != LLVMRustOptStage::PreLinkThinLTO) {
-        for (const auto &C : OptimizerLastEPCallbacks)
-          PB.registerOptimizerLastEPCallback(C);
-      }
+      for (const auto &C : OptimizerLastEPCallbacks)
+        PB.registerOptimizerLastEPCallback(C);
 
       switch (OptStage) {
       case LLVMRustOptStage::PreLinkNoLTO:
@@ -945,14 +943,7 @@ LLVMRustOptimize(
         break;
       case LLVMRustOptStage::PreLinkThinLTO:
         MPM = PB.buildThinLTOPreLinkDefaultPipeline(OptLevel);
-        // The ThinLTOPreLink pipeline already includes ThinLTOBuffer passes. However, callback
-        // passes may still run afterwards. This means we need to run the buffer passes again.
-        // FIXME: In LLVM 13, the ThinLTOPreLink pipeline also runs OptimizerLastEPCallbacks
-        // before the RequiredLTOPreLinkPasses, in which case we can remove these hacks.
-        if (OptimizerLastEPCallbacks.empty())
-          NeedThinLTOBufferPasses = false;
-        for (const auto &C : OptimizerLastEPCallbacks)
-          C(MPM, OptLevel);
+        NeedThinLTOBufferPasses = false;
         break;
       case LLVMRustOptStage::PreLinkFatLTO:
         MPM = PB.buildLTOPreLinkDefaultPipeline(OptLevel);
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 0df7b7eed11..a2dfebec594 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -250,8 +250,6 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
     return Attribute::NonLazyBind;
   case OptimizeNone:
     return Attribute::OptimizeNone;
-  case ReturnsTwice:
-    return Attribute::ReturnsTwice;
   case ReadNone:
     return Attribute::ReadNone;
   case SanitizeHWAddress:
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 542caf86223..85631bd8edb 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -386,7 +386,7 @@ impl<'a, 'tcx> TyEncoder for EncodeContext<'a, 'tcx> {
     }
 }
 
-// Shorthand for `$self.$tables.$table.set_some($def_id.index, $self.lazy_value($value))`, which would
+// Shorthand for `$self.$tables.$table.set_some($def_id.index, $self.lazy($value))`, which would
 // normally need extra variables to avoid errors about multiple mutable borrows.
 macro_rules! record {
     ($self:ident.$tables:ident.$table:ident[$def_id:expr] <- $value:expr) => {{
@@ -398,7 +398,7 @@ macro_rules! record {
     }};
 }
 
-// Shorthand for `$self.$tables.$table.set_some($def_id.index, $self.lazy_value($value))`, which would
+// Shorthand for `$self.$tables.$table.set_some($def_id.index, $self.lazy_array($value))`, which would
 // normally need extra variables to avoid errors about multiple mutable borrows.
 macro_rules! record_array {
     ($self:ident.$tables:ident.$table:ident[$def_id:expr] <- $value:expr) => {{
diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs
index c35799ef47f..63c0ebd5f6b 100644
--- a/compiler/rustc_middle/src/infer/unify_key.rs
+++ b/compiler/rustc_middle/src/infer/unify_key.rs
@@ -194,33 +194,37 @@ impl<'tcx> UnifyValue for ConstVariableValue<'tcx> {
 /// values for the effect inference variable
 #[derive(Clone, Copy, Debug)]
 pub enum EffectVarValue<'tcx> {
-    /// The host effect is on, enabling access to syscalls, filesystem access, etc.
-    Host,
-    /// The host effect is off. Execution is restricted to const operations only.
-    NoHost,
-    Const(ty::Const<'tcx>),
+    Unknown,
+    Known(ty::Const<'tcx>),
 }
 
 impl<'tcx> EffectVarValue<'tcx> {
-    pub fn as_const(self, tcx: TyCtxt<'tcx>) -> ty::Const<'tcx> {
+    pub fn known(self) -> Option<ty::Const<'tcx>> {
         match self {
-            EffectVarValue::Host => tcx.consts.true_,
-            EffectVarValue::NoHost => tcx.consts.false_,
-            EffectVarValue::Const(c) => c,
+            EffectVarValue::Unknown => None,
+            EffectVarValue::Known(value) => Some(value),
+        }
+    }
+
+    pub fn is_unknown(self) -> bool {
+        match self {
+            EffectVarValue::Unknown => true,
+            EffectVarValue::Known(_) => false,
         }
     }
 }
 
 impl<'tcx> UnifyValue for EffectVarValue<'tcx> {
-    type Error = (EffectVarValue<'tcx>, EffectVarValue<'tcx>);
+    type Error = NoError;
     fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
-        match (value1, value2) {
-            (EffectVarValue::Host, EffectVarValue::Host) => Ok(EffectVarValue::Host),
-            (EffectVarValue::NoHost, EffectVarValue::NoHost) => Ok(EffectVarValue::NoHost),
-            (EffectVarValue::NoHost | EffectVarValue::Host, _)
-            | (_, EffectVarValue::NoHost | EffectVarValue::Host) => Err((*value1, *value2)),
-            (EffectVarValue::Const(_), EffectVarValue::Const(_)) => {
-                bug!("equating two const variables, both of which have known values")
+        match (*value1, *value2) {
+            (EffectVarValue::Unknown, EffectVarValue::Unknown) => Ok(EffectVarValue::Unknown),
+            (EffectVarValue::Unknown, EffectVarValue::Known(val))
+            | (EffectVarValue::Known(val), EffectVarValue::Unknown) => {
+                Ok(EffectVarValue::Known(val))
+            }
+            (EffectVarValue::Known(_), EffectVarValue::Known(_)) => {
+                bug!("equating known inference variables: {value1:?} {value2:?}")
             }
         }
     }
@@ -229,7 +233,7 @@ impl<'tcx> UnifyValue for EffectVarValue<'tcx> {
 #[derive(PartialEq, Copy, Clone, Debug)]
 pub struct EffectVidKey<'tcx> {
     pub vid: ty::EffectVid,
-    pub phantom: PhantomData<EffectVarValue<'tcx>>,
+    pub phantom: PhantomData<ty::Const<'tcx>>,
 }
 
 impl<'tcx> From<ty::EffectVid> for EffectVidKey<'tcx> {
@@ -239,7 +243,7 @@ impl<'tcx> From<ty::EffectVid> for EffectVidKey<'tcx> {
 }
 
 impl<'tcx> UnifyKey for EffectVidKey<'tcx> {
-    type Value = Option<EffectVarValue<'tcx>>;
+    type Value = EffectVarValue<'tcx>;
     #[inline]
     fn index(&self) -> u32 {
         self.vid.as_u32()
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index e11c9371118..7d6d39a2a8a 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -74,35 +74,32 @@ bitflags! {
         /// `#[used]`: indicates that LLVM can't eliminate this function (but the
         /// linker can!).
         const USED                      = 1 << 9;
-        /// `#[ffi_returns_twice]`, indicates that an extern function can return
-        /// multiple times
-        const FFI_RETURNS_TWICE         = 1 << 10;
         /// `#[track_caller]`: allow access to the caller location
-        const TRACK_CALLER              = 1 << 11;
+        const TRACK_CALLER              = 1 << 10;
         /// #[ffi_pure]: applies clang's `pure` attribute to a foreign function
         /// declaration.
-        const FFI_PURE                  = 1 << 12;
+        const FFI_PURE                  = 1 << 11;
         /// #[ffi_const]: applies clang's `const` attribute to a foreign function
         /// declaration.
-        const FFI_CONST                 = 1 << 13;
+        const FFI_CONST                 = 1 << 12;
         /// #[cmse_nonsecure_entry]: with a TrustZone-M extension, declare a
         /// function as an entry function from Non-Secure code.
-        const CMSE_NONSECURE_ENTRY      = 1 << 14;
+        const CMSE_NONSECURE_ENTRY      = 1 << 13;
         /// `#[coverage(off)]`: indicates that the function should be ignored by
         /// the MIR `InstrumentCoverage` pass and not added to the coverage map
         /// during codegen.
-        const NO_COVERAGE               = 1 << 15;
+        const NO_COVERAGE               = 1 << 14;
         /// `#[used(linker)]`:
         /// indicates that neither LLVM nor the linker will eliminate this function.
-        const USED_LINKER               = 1 << 16;
+        const USED_LINKER               = 1 << 15;
         /// `#[rustc_deallocator]`: a hint to LLVM that the function only deallocates memory.
-        const DEALLOCATOR               = 1 << 17;
+        const DEALLOCATOR               = 1 << 16;
         /// `#[rustc_reallocator]`: a hint to LLVM that the function only reallocates memory.
-        const REALLOCATOR               = 1 << 18;
+        const REALLOCATOR               = 1 << 17;
         /// `#[rustc_allocator_zeroed]`: a hint to LLVM that the function only allocates zeroed memory.
-        const ALLOCATOR_ZEROED          = 1 << 19;
+        const ALLOCATOR_ZEROED          = 1 << 18;
         /// `#[no_builtins]`: indicates that disable implicit builtin knowledge of functions for the function.
-        const NO_BUILTINS               = 1 << 20;
+        const NO_BUILTINS               = 1 << 19;
     }
 }
 rustc_data_structures::external_bitflags_debug! { CodegenFnAttrFlags }
diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs
index f92c72c8a58..a4e193ba2c9 100644
--- a/compiler/rustc_middle/src/middle/lang_items.rs
+++ b/compiler/rustc_middle/src/middle/lang_items.rs
@@ -23,7 +23,7 @@ impl<'tcx> TyCtxt<'tcx> {
         })
     }
 
-    /// Given a [`DefId`] of a [`Fn`], [`FnMut`] or [`FnOnce`] traits,
+    /// Given a [`DefId`] of one of the [`Fn`], [`FnMut`] or [`FnOnce`] traits,
     /// returns a corresponding [`ty::ClosureKind`].
     /// For any other [`DefId`] return `None`.
     pub fn fn_trait_kind_from_def_id(self, id: DefId) -> Option<ty::ClosureKind> {
@@ -36,6 +36,19 @@ impl<'tcx> TyCtxt<'tcx> {
         }
     }
 
+    /// Given a [`DefId`] of one of the `AsyncFn`, `AsyncFnMut` or `AsyncFnOnce` traits,
+    /// returns a corresponding [`ty::ClosureKind`].
+    /// For any other [`DefId`] return `None`.
+    pub fn async_fn_trait_kind_from_def_id(self, id: DefId) -> Option<ty::ClosureKind> {
+        let items = self.lang_items();
+        match Some(id) {
+            x if x == items.async_fn_trait() => Some(ty::ClosureKind::Fn),
+            x if x == items.async_fn_mut_trait() => Some(ty::ClosureKind::FnMut),
+            x if x == items.async_fn_once_trait() => Some(ty::ClosureKind::FnOnce),
+            _ => None,
+        }
+    }
+
     /// Given a [`ty::ClosureKind`], get the [`DefId`] of its corresponding `Fn`-family
     /// trait, if it is defined.
     pub fn fn_trait_kind_to_def_id(self, kind: ty::ClosureKind) -> Option<DefId> {
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 4ba96464c0e..e22d5228628 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -266,6 +266,25 @@ pub struct CoroutineInfo<'tcx> {
     /// Coroutine drop glue. This field is populated after the state transform pass.
     pub coroutine_drop: Option<Body<'tcx>>,
 
+    /// The body of the coroutine, modified to take its upvars by move rather than by ref.
+    ///
+    /// This is used by coroutine-closures, which must return a different flavor of coroutine
+    /// when called using `AsyncFnOnce::call_once`. It is produced by the `ByMoveBody` pass which
+    /// is run right after building the initial MIR, and will only be populated for coroutines
+    /// which come out of the async closure desugaring.
+    ///
+    /// This body should be processed in lockstep with the containing body -- any optimization
+    /// passes, etc, should be applied to this body as well. This is done automatically if
+    /// using `run_passes`.
+    pub by_move_body: Option<Body<'tcx>>,
+
+    /// The body of the coroutine, modified to take its upvars by mutable ref rather than by
+    /// immutable ref.
+    ///
+    /// FIXME(async_closures): This is literally the same body as the parent body. Find a better
+    /// way to represent the by-mut signature (or cap the closure-kind of the coroutine).
+    pub by_mut_body: Option<Body<'tcx>>,
+
     /// The layout of a coroutine. This field is populated after the state transform pass.
     pub coroutine_layout: Option<CoroutineLayout<'tcx>>,
 
@@ -285,6 +304,8 @@ impl<'tcx> CoroutineInfo<'tcx> {
             coroutine_kind,
             yield_ty: Some(yield_ty),
             resume_ty: Some(resume_ty),
+            by_move_body: None,
+            by_mut_body: None,
             coroutine_drop: None,
             coroutine_layout: None,
         }
@@ -595,6 +616,14 @@ impl<'tcx> Body<'tcx> {
         self.coroutine.as_ref().and_then(|coroutine| coroutine.coroutine_drop.as_ref())
     }
 
+    pub fn coroutine_by_move_body(&self) -> Option<&Body<'tcx>> {
+        self.coroutine.as_ref()?.by_move_body.as_ref()
+    }
+
+    pub fn coroutine_by_mut_body(&self) -> Option<&Body<'tcx>> {
+        self.coroutine.as_ref()?.by_mut_body.as_ref()
+    }
+
     #[inline]
     pub fn coroutine_kind(&self) -> Option<CoroutineKind> {
         self.coroutine.as_ref().map(|coroutine| coroutine.coroutine_kind)
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 91fdf0b3129..6937df7bb18 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -402,6 +402,8 @@ impl<'tcx> CodegenUnit<'tcx> {
                             | InstanceDef::FnPtrShim(..)
                             | InstanceDef::Virtual(..)
                             | InstanceDef::ClosureOnceShim { .. }
+                            | InstanceDef::ConstructCoroutineInClosureShim { .. }
+                            | InstanceDef::CoroutineKindShim { .. }
                             | InstanceDef::DropGlue(..)
                             | InstanceDef::CloneShim(..)
                             | InstanceDef::ThreadLocalShim(..)
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 3b60eba2dfe..6f587fdd53c 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -990,7 +990,8 @@ impl<'tcx> Debug for Rvalue<'tcx> {
                         })
                     }
 
-                    AggregateKind::Closure(def_id, args) => ty::tls::with(|tcx| {
+                    AggregateKind::Closure(def_id, args)
+                    | AggregateKind::CoroutineClosure(def_id, args) => ty::tls::with(|tcx| {
                         let name = if tcx.sess.opts.unstable_opts.span_free_formats {
                             let args = tcx.lift(args).unwrap();
                             format!("{{closure@{}}}", tcx.def_path_str_with_args(def_id, args),)
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index 98642adc190..90b6df1dd1f 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -189,7 +189,7 @@ pub struct BorrowCheckResult<'tcx> {
 
 /// The result of the `mir_const_qualif` query.
 ///
-/// Each field (except `error_occurred`) corresponds to an implementer of the `Qualif` trait in
+/// Each field (except `tainted_by_errors`) corresponds to an implementer of the `Qualif` trait in
 /// `rustc_const_eval/src/transform/check_consts/qualifs.rs`. See that file for more information on each
 /// `Qualif`.
 #[derive(Clone, Copy, Debug, Default, TyEncodable, TyDecodable, HashStable)]
@@ -197,7 +197,6 @@ pub struct ConstQualifs {
     pub has_mut_interior: bool,
     pub needs_drop: bool,
     pub needs_non_const_drop: bool,
-    pub custom_eq: bool,
     pub tainted_by_errors: Option<ErrorGuaranteed>,
 }
 
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index a4b6c4f9c3f..ca56e1fd92c 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -1350,6 +1350,7 @@ pub enum AggregateKind<'tcx> {
 
     Closure(DefId, GenericArgsRef<'tcx>),
     Coroutine(DefId, GenericArgsRef<'tcx>),
+    CoroutineClosure(DefId, GenericArgsRef<'tcx>),
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index 5597609c7d7..4780042a510 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -202,6 +202,9 @@ impl<'tcx> Rvalue<'tcx> {
                 AggregateKind::Adt(did, _, args, _, _) => tcx.type_of(did).instantiate(tcx, args),
                 AggregateKind::Closure(did, args) => Ty::new_closure(tcx, did, args),
                 AggregateKind::Coroutine(did, args) => Ty::new_coroutine(tcx, did, args),
+                AggregateKind::CoroutineClosure(did, args) => {
+                    Ty::new_coroutine_closure(tcx, did, args)
+                }
             },
             Rvalue::ShallowInitBox(_, ty) => Ty::new_box(tcx, ty),
             Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty,
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 4696f54c897..2c5ca82a4cd 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -345,6 +345,8 @@ macro_rules! make_mir_visitor {
                         ty::InstanceDef::Virtual(_def_id, _) |
                         ty::InstanceDef::ThreadLocalShim(_def_id) |
                         ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } |
+                        ty::InstanceDef::ConstructCoroutineInClosureShim { coroutine_closure_def_id: _def_id, target_kind: _ } |
+                        ty::InstanceDef::CoroutineKindShim { coroutine_def_id: _def_id, target_kind: _ } |
                         ty::InstanceDef::DropGlue(_def_id, None) => {}
 
                         ty::InstanceDef::FnPtrShim(_def_id, ty) |
@@ -739,6 +741,12 @@ macro_rules! make_mir_visitor {
                             ) => {
                                 self.visit_args(coroutine_args, location);
                             }
+                            AggregateKind::CoroutineClosure(
+                                _,
+                                coroutine_closure_args,
+                            ) => {
+                                self.visit_args(coroutine_closure_args, location);
+                            }
                         }
 
                         for operand in operands {
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 2438f826441..938fba0ed09 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -755,6 +755,11 @@ rustc_queries! {
         separate_provide_extern
     }
 
+    query coroutine_for_closure(def_id: DefId) -> DefId {
+        desc { |_tcx| "Given a coroutine-closure def id, return the def id of the coroutine returned by it" }
+        separate_provide_extern
+    }
+
     /// Gets a map with the variance of every item; use `variances_of` instead.
     query crate_variances(_: ()) -> &'tcx ty::CrateVariancesMap<'tcx> {
         arena_cache
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index 64f4af08e12..28eba133c76 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -134,6 +134,15 @@ pub enum SelectionCandidate<'tcx> {
         is_const: bool,
     },
 
+    /// Implementation of an `AsyncFn`-family trait by one of the anonymous types
+    /// generated for an `async ||` expression.
+    AsyncClosureCandidate,
+
+    /// Implementation of the the `AsyncFnKindHelper` helper trait, which
+    /// is used internally to delay computation for async closures until after
+    /// upvar analysis is performed in HIR typeck.
+    AsyncFnKindHelperCandidate,
+
     /// Implementation of a `Coroutine` trait by one of the anonymous types
     /// generated for a coroutine.
     CoroutineCandidate,
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 0d53870a0ba..b747f0a4fb6 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1193,7 +1193,7 @@ impl<'tcx> TyCtxt<'tcx> {
         let (suitable_region_binding_scope, bound_region) = loop {
             let def_id = match region.kind() {
                 ty::ReLateParam(fr) => fr.bound_region.get_id()?.as_local()?,
-                ty::ReEarlyParam(ebr) => ebr.def_id.expect_local(),
+                ty::ReEarlyParam(ebr) => ebr.def_id.as_local()?,
                 _ => return None, // not a free region
             };
             let scope = self.local_parent(def_id);
@@ -1544,6 +1544,7 @@ impl<'tcx> TyCtxt<'tcx> {
                     CoroutineWitness,
                     Dynamic,
                     Closure,
+                    CoroutineClosure,
                     Tuple,
                     Bound,
                     Param,
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 0e44878524b..80b763d1469 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -299,7 +299,7 @@ impl<'tcx> Ty<'tcx> {
             },
             ty::FnPtr(_) => "fn pointer".into(),
             ty::Dynamic(..) => "trait object".into(),
-            ty::Closure(..) => "closure".into(),
+            ty::Closure(..) | ty::CoroutineClosure(..) => "closure".into(),
             ty::Coroutine(def_id, ..) => {
                 format!("{:#}", tcx.coroutine_kind(def_id).unwrap()).into()
             }
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index b71919adc58..adc153c4dfd 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -128,7 +128,9 @@ pub fn simplify_type<'tcx>(
             _ => Some(SimplifiedType::MarkerTraitObject),
         },
         ty::Ref(_, _, mutbl) => Some(SimplifiedType::Ref(mutbl)),
-        ty::FnDef(def_id, _) | ty::Closure(def_id, _) => Some(SimplifiedType::Closure(def_id)),
+        ty::FnDef(def_id, _) | ty::Closure(def_id, _) | ty::CoroutineClosure(def_id, _) => {
+            Some(SimplifiedType::Closure(def_id))
+        }
         ty::Coroutine(def_id, _) => Some(SimplifiedType::Coroutine(def_id)),
         ty::CoroutineWitness(def_id, _) => Some(SimplifiedType::CoroutineWitness(def_id)),
         ty::Never => Some(SimplifiedType::Never),
@@ -236,6 +238,7 @@ impl DeepRejectCtxt {
             | ty::Foreign(..) => debug_assert!(impl_ty.is_known_rigid()),
             ty::FnDef(..)
             | ty::Closure(..)
+            | ty::CoroutineClosure(..)
             | ty::Coroutine(..)
             | ty::CoroutineWitness(..)
             | ty::Placeholder(..)
@@ -312,7 +315,7 @@ impl DeepRejectCtxt {
             },
 
             // Impls cannot contain these types as these cannot be named directly.
-            ty::FnDef(..) | ty::Closure(..) | ty::Coroutine(..) => false,
+            ty::FnDef(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..) => false,
 
             // Placeholder types don't unify with anything on their own
             ty::Placeholder(..) | ty::Bound(..) => false,
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 0c1d1091414..0f4b5fe228c 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -136,6 +136,22 @@ impl FlagComputation {
                 self.add_ty(args.tupled_upvars_ty());
             }
 
+            &ty::CoroutineClosure(_, args) => {
+                let args = args.as_coroutine_closure();
+                let should_remove_further_specializable =
+                    !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
+                self.add_args(args.parent_args());
+                if should_remove_further_specializable {
+                    self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE;
+                }
+
+                self.add_ty(args.kind_ty());
+                self.add_ty(args.signature_parts_ty());
+                self.add_ty(args.tupled_upvars_ty());
+                self.add_ty(args.coroutine_captures_by_ref_ty());
+                self.add_ty(args.coroutine_witness_ty());
+            }
+
             &ty::Bound(debruijn, _) => {
                 self.add_bound_var(debruijn);
                 self.add_flags(TypeFlags::HAS_TY_BOUND);
diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs
index 69ad6810c6f..b9fff660a03 100644
--- a/compiler/rustc_middle/src/ty/generic_args.rs
+++ b/compiler/rustc_middle/src/ty/generic_args.rs
@@ -2,7 +2,7 @@
 
 use crate::ty::codec::{TyDecoder, TyEncoder};
 use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
-use crate::ty::sty::{ClosureArgs, CoroutineArgs, InlineConstArgs};
+use crate::ty::sty::{ClosureArgs, CoroutineArgs, CoroutineClosureArgs, InlineConstArgs};
 use crate::ty::visit::{TypeVisitable, TypeVisitableExt, TypeVisitor};
 use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
 
@@ -288,6 +288,14 @@ impl<'tcx> GenericArgs<'tcx> {
         ClosureArgs { args: self }
     }
 
+    /// Interpret these generic args as the args of a coroutine-closure type.
+    /// Coroutine-closure args have a particular structure controlled by the
+    /// compiler that encodes information like the signature and closure kind;
+    /// see `ty::CoroutineClosureArgs` struct for more comments.
+    pub fn as_coroutine_closure(&'tcx self) -> CoroutineClosureArgs<'tcx> {
+        CoroutineClosureArgs { args: self }
+    }
+
     /// Interpret these generic args as the args of a coroutine type.
     /// Coroutine args have a particular structure controlled by the
     /// compiler that encodes information like the signature and coroutine kind;
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 293fdb026b6..9c1f4b20d2c 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -82,11 +82,33 @@ pub enum InstanceDef<'tcx> {
     /// details on that).
     Virtual(DefId, usize),
 
-    /// `<[FnMut closure] as FnOnce>::call_once`.
+    /// `<[FnMut/Fn closure] as FnOnce>::call_once`.
     ///
     /// The `DefId` is the ID of the `call_once` method in `FnOnce`.
+    ///
+    /// This generates a body that will just borrow the (owned) self type,
+    /// and dispatch to the `FnMut::call_mut` instance for the closure.
     ClosureOnceShim { call_once: DefId, track_caller: bool },
 
+    /// `<[FnMut/Fn coroutine-closure] as FnOnce>::call_once` or
+    /// `<[Fn coroutine-closure] as FnMut>::call_mut`.
+    ///
+    /// The body generated here differs significantly from the `ClosureOnceShim`,
+    /// since we need to generate a distinct coroutine type that will move the
+    /// closure's upvars *out* of the closure.
+    ConstructCoroutineInClosureShim {
+        coroutine_closure_def_id: DefId,
+        target_kind: ty::ClosureKind,
+    },
+
+    /// `<[coroutine] as Future>::poll`, but for coroutines produced when `AsyncFnOnce`
+    /// is called on a coroutine-closure whose closure kind greater than `FnOnce`, or
+    /// similarly for `AsyncFnMut`.
+    ///
+    /// This will select the body that is produced by the `ByMoveBody` transform, and thus
+    /// take and use all of its upvars by-move rather than by-ref.
+    CoroutineKindShim { coroutine_def_id: DefId, target_kind: ty::ClosureKind },
+
     /// Compiler-generated accessor for thread locals which returns a reference to the thread local
     /// the `DefId` defines. This is used to export thread locals from dylibs on platforms lacking
     /// native support.
@@ -168,6 +190,11 @@ impl<'tcx> InstanceDef<'tcx> {
             | InstanceDef::Intrinsic(def_id)
             | InstanceDef::ThreadLocalShim(def_id)
             | InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ }
+            | ty::InstanceDef::ConstructCoroutineInClosureShim {
+                coroutine_closure_def_id: def_id,
+                target_kind: _,
+            }
+            | ty::InstanceDef::CoroutineKindShim { coroutine_def_id: def_id, target_kind: _ }
             | InstanceDef::DropGlue(def_id, _)
             | InstanceDef::CloneShim(def_id, _)
             | InstanceDef::FnPtrAddrShim(def_id, _) => def_id,
@@ -187,6 +214,8 @@ impl<'tcx> InstanceDef<'tcx> {
             | InstanceDef::Virtual(..)
             | InstanceDef::Intrinsic(..)
             | InstanceDef::ClosureOnceShim { .. }
+            | ty::InstanceDef::ConstructCoroutineInClosureShim { .. }
+            | ty::InstanceDef::CoroutineKindShim { .. }
             | InstanceDef::DropGlue(..)
             | InstanceDef::CloneShim(..)
             | InstanceDef::FnPtrAddrShim(..) => None,
@@ -282,6 +311,8 @@ impl<'tcx> InstanceDef<'tcx> {
             | InstanceDef::FnPtrShim(..)
             | InstanceDef::DropGlue(_, Some(_)) => false,
             InstanceDef::ClosureOnceShim { .. }
+            | InstanceDef::ConstructCoroutineInClosureShim { .. }
+            | InstanceDef::CoroutineKindShim { .. }
             | InstanceDef::DropGlue(..)
             | InstanceDef::Item(_)
             | InstanceDef::Intrinsic(..)
@@ -319,6 +350,8 @@ fn fmt_instance(
         InstanceDef::Virtual(_, num) => write!(f, " - virtual#{num}"),
         InstanceDef::FnPtrShim(_, ty) => write!(f, " - shim({ty})"),
         InstanceDef::ClosureOnceShim { .. } => write!(f, " - shim"),
+        InstanceDef::ConstructCoroutineInClosureShim { .. } => write!(f, " - shim"),
+        InstanceDef::CoroutineKindShim { .. } => write!(f, " - shim"),
         InstanceDef::DropGlue(_, None) => write!(f, " - shim(None)"),
         InstanceDef::DropGlue(_, Some(ty)) => write!(f, " - shim(Some({ty}))"),
         InstanceDef::CloneShim(_, ty) => write!(f, " - shim({ty})"),
@@ -610,7 +643,24 @@ impl<'tcx> Instance<'tcx> {
         };
 
         if tcx.lang_items().get(coroutine_callable_item) == Some(trait_item_id) {
-            Some(Instance { def: ty::InstanceDef::Item(coroutine_def_id), args: args })
+            let ty::Coroutine(_, id_args) = *tcx.type_of(coroutine_def_id).skip_binder().kind()
+            else {
+                bug!()
+            };
+
+            // If the closure's kind ty disagrees with the identity closure's kind ty,
+            // then this must be a coroutine generated by one of the `ConstructCoroutineInClosureShim`s.
+            if args.as_coroutine().kind_ty() == id_args.as_coroutine().kind_ty() {
+                Some(Instance { def: ty::InstanceDef::Item(coroutine_def_id), args })
+            } else {
+                Some(Instance {
+                    def: ty::InstanceDef::CoroutineKindShim {
+                        coroutine_def_id,
+                        target_kind: args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap(),
+                    },
+                    args,
+                })
+            }
         } else {
             // All other methods should be defaulted methods of the built-in trait.
             // This is important for `Iterator`'s combinators, but also useful for
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 73b0e324f13..8d8d06b7c0b 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -906,6 +906,12 @@ where
                     i,
                 ),
 
+                ty::CoroutineClosure(_, args) => field_ty_or_layout(
+                    TyAndLayout { ty: args.as_coroutine_closure().tupled_upvars_ty(), ..this },
+                    cx,
+                    i,
+                ),
+
                 ty::Coroutine(def_id, args) => match this.variants {
                     Variants::Single { index } => TyMaybeWithLayout::Ty(
                         args.as_coroutine()
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 8e51db82f95..c9137f374a2 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -105,9 +105,10 @@ pub use self::region::{
 pub use self::rvalue_scopes::RvalueScopes;
 pub use self::sty::{
     AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig,
-    ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, FnSig, GenSig,
-    InlineConstArgs, InlineConstArgsParts, ParamConst, ParamTy, PolyFnSig, TyKind, TypeAndMut,
-    UpvarArgs, VarianceDiagInfo,
+    ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, CoroutineClosureArgs,
+    CoroutineClosureArgsParts, CoroutineClosureSignature, FnSig, GenSig, InlineConstArgs,
+    InlineConstArgsParts, ParamConst, ParamTy, PolyFnSig, TyKind, TypeAndMut, UpvarArgs,
+    VarianceDiagInfo,
 };
 pub use self::trait_def::TraitDef;
 pub use self::typeck_results::{
@@ -1679,6 +1680,8 @@ impl<'tcx> TyCtxt<'tcx> {
             | ty::InstanceDef::FnPtrShim(..)
             | ty::InstanceDef::Virtual(..)
             | ty::InstanceDef::ClosureOnceShim { .. }
+            | ty::InstanceDef::ConstructCoroutineInClosureShim { .. }
+            | ty::InstanceDef::CoroutineKindShim { .. }
             | ty::InstanceDef::DropGlue(..)
             | ty::InstanceDef::CloneShim(..)
             | ty::InstanceDef::ThreadLocalShim(..)
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index f32b7b0852a..19f8ba124f1 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -3,6 +3,7 @@ use crate::ty::{self, Ty, TyCtxt};
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sso::SsoHashSet;
+use rustc_hir as hir;
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
 use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
 
@@ -130,8 +131,24 @@ pub trait Printer<'tcx>: Sized {
                     parent_args = &args[..generics.parent_count.min(args.len())];
 
                     match key.disambiguated_data.data {
-                        // Closures' own generics are only captures, don't print them.
-                        DefPathData::Closure => {}
+                        DefPathData::Closure => {
+                            // FIXME(async_closures): This is somewhat ugly.
+                            // We need to additionally print the `kind` field of a closure if
+                            // it is desugared from a coroutine-closure.
+                            if let Some(hir::CoroutineKind::Desugared(
+                                _,
+                                hir::CoroutineSource::Closure,
+                            )) = self.tcx().coroutine_kind(def_id)
+                                && args.len() >= parent_args.len() + 1
+                            {
+                                return self.path_generic_args(
+                                    |cx| cx.print_def_path(def_id, parent_args),
+                                    &args[..parent_args.len() + 1][..1],
+                                );
+                            } else {
+                                // Closures' own generics are only captures, don't print them.
+                            }
+                        }
                         // This covers both `DefKind::AnonConst` and `DefKind::InlineConst`.
                         // Anon consts doesn't have their own generics, and inline consts' own
                         // generics are their inferred types, so don't print them.
@@ -259,6 +276,7 @@ fn characteristic_def_id_of_type_cached<'a>(
 
         ty::FnDef(def_id, _)
         | ty::Closure(def_id, _)
+        | ty::CoroutineClosure(def_id, _)
         | ty::Coroutine(def_id, _)
         | ty::CoroutineWitness(def_id, _)
         | ty::Foreign(def_id) => Some(def_id),
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index bac5068a69b..c0bfd2380ad 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -874,6 +874,48 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                 }
                 p!("}}");
             }
+            ty::CoroutineClosure(did, args) => {
+                p!(write("{{"));
+                if !self.should_print_verbose() {
+                    p!(write("coroutine-closure"));
+                    // FIXME(eddyb) should use `def_span`.
+                    if let Some(did) = did.as_local() {
+                        if self.tcx().sess.opts.unstable_opts.span_free_formats {
+                            p!("@", print_def_path(did.to_def_id(), args));
+                        } else {
+                            let span = self.tcx().def_span(did);
+                            let preference = if with_forced_trimmed_paths() {
+                                FileNameDisplayPreference::Short
+                            } else {
+                                FileNameDisplayPreference::Remapped
+                            };
+                            p!(write(
+                                "@{}",
+                                // This may end up in stderr diagnostics but it may also be emitted
+                                // into MIR. Hence we use the remapped path if available
+                                self.tcx().sess.source_map().span_to_string(span, preference)
+                            ));
+                        }
+                    } else {
+                        p!(write("@"), print_def_path(did, args));
+                    }
+                } else {
+                    p!(print_def_path(did, args));
+                    p!(
+                        " closure_kind_ty=",
+                        print(args.as_coroutine_closure().kind_ty()),
+                        " signature_parts_ty=",
+                        print(args.as_coroutine_closure().signature_parts_ty()),
+                        " upvar_tys=",
+                        print(args.as_coroutine_closure().tupled_upvars_ty()),
+                        " coroutine_captures_by_ref_ty=",
+                        print(args.as_coroutine_closure().coroutine_captures_by_ref_ty()),
+                        " coroutine_witness_ty=",
+                        print(args.as_coroutine_closure().coroutine_witness_ty())
+                    );
+                }
+                p!("}}");
+            }
             ty::Array(ty, sz) => p!("[", print(ty), "; ", print(sz), "]"),
             ty::Slice(ty) => p!("[", print(ty), "]"),
         }
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 8543bd0bbdd..f2321e7e1d2 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -481,6 +481,13 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             Ok(Ty::new_closure(tcx, a_id, args))
         }
 
+        (&ty::CoroutineClosure(a_id, a_args), &ty::CoroutineClosure(b_id, b_args))
+            if a_id == b_id =>
+        {
+            let args = relate_args_invariantly(relation, a_args, b_args)?;
+            Ok(Ty::new_coroutine_closure(tcx, a_id, args))
+        }
+
         (&ty::RawPtr(a_mt), &ty::RawPtr(b_mt)) => {
             let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?;
             Ok(Ty::new_ptr(tcx, mt))
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 11b579a1f85..c6805ba9323 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -584,6 +584,9 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for Ty<'tcx> {
                 ty::CoroutineWitness(did, args.try_fold_with(folder)?)
             }
             ty::Closure(did, args) => ty::Closure(did, args.try_fold_with(folder)?),
+            ty::CoroutineClosure(did, args) => {
+                ty::CoroutineClosure(did, args.try_fold_with(folder)?)
+            }
             ty::Alias(kind, data) => ty::Alias(kind, data.try_fold_with(folder)?),
 
             ty::Bool
@@ -632,6 +635,7 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for Ty<'tcx> {
             ty::Coroutine(_did, ref args) => args.visit_with(visitor),
             ty::CoroutineWitness(_did, ref args) => args.visit_with(visitor),
             ty::Closure(_did, ref args) => args.visit_with(visitor),
+            ty::CoroutineClosure(_did, ref args) => args.visit_with(visitor),
             ty::Alias(_, ref data) => data.visit_with(visitor),
 
             ty::Bool
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index f5fdf210592..927924452f9 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -36,6 +36,7 @@ use rustc_type_ir::TyKind as IrTyKind;
 use rustc_type_ir::TyKind::*;
 use rustc_type_ir::TypeAndMut as IrTypeAndMut;
 
+use super::fold::FnMutDelegate;
 use super::GenericParamDefKind;
 
 // Re-export and re-parameterize some `I = TyCtxt<'tcx>` types here
@@ -269,6 +270,275 @@ impl<'tcx> ClosureArgs<'tcx> {
     }
 }
 
+#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable, Lift)]
+pub struct CoroutineClosureArgs<'tcx> {
+    pub args: GenericArgsRef<'tcx>,
+}
+
+/// See docs for explanation of how each argument is used.
+///
+/// See [`CoroutineClosureSignature`] for how these arguments are put together
+/// to make a callable [`FnSig`] suitable for typeck and borrowck.
+pub struct CoroutineClosureArgsParts<'tcx> {
+    /// This is the args of the typeck root.
+    pub parent_args: &'tcx [GenericArg<'tcx>],
+    /// Represents the maximum calling capability of the closure.
+    pub closure_kind_ty: Ty<'tcx>,
+    /// Represents all of the relevant parts of the coroutine returned by this
+    /// coroutine-closure. This signature parts type will have the general
+    /// shape of `fn(tupled_inputs, resume_ty) -> (return_ty, yield_ty)`, where
+    /// `resume_ty`, `return_ty`, and `yield_ty` are the respective types for the
+    /// coroutine returned by the coroutine-closure.
+    ///
+    /// Use `coroutine_closure_sig` to break up this type rather than using it
+    /// yourself.
+    pub signature_parts_ty: Ty<'tcx>,
+    /// The upvars captured by the closure. Remains an inference variable
+    /// until the upvar analysis, which happens late in HIR typeck.
+    pub tupled_upvars_ty: Ty<'tcx>,
+    /// a function pointer that has the shape `for<'env> fn() -> (&'env T, ...)`.
+    /// This allows us to represent the binder of the self-captures of the closure.
+    ///
+    /// For example, if the coroutine returned by the closure borrows `String`
+    /// from the closure's upvars, this will be `for<'env> fn() -> (&'env String,)`,
+    /// while the `tupled_upvars_ty`, representing the by-move version of the same
+    /// captures, will be `(String,)`.
+    pub coroutine_captures_by_ref_ty: Ty<'tcx>,
+    /// Witness type returned by the generator produced by this coroutine-closure.
+    pub coroutine_witness_ty: Ty<'tcx>,
+}
+
+impl<'tcx> CoroutineClosureArgs<'tcx> {
+    pub fn new(
+        tcx: TyCtxt<'tcx>,
+        parts: CoroutineClosureArgsParts<'tcx>,
+    ) -> CoroutineClosureArgs<'tcx> {
+        CoroutineClosureArgs {
+            args: tcx.mk_args_from_iter(parts.parent_args.iter().copied().chain([
+                parts.closure_kind_ty.into(),
+                parts.signature_parts_ty.into(),
+                parts.tupled_upvars_ty.into(),
+                parts.coroutine_captures_by_ref_ty.into(),
+                parts.coroutine_witness_ty.into(),
+            ])),
+        }
+    }
+
+    fn split(self) -> CoroutineClosureArgsParts<'tcx> {
+        match self.args[..] {
+            [
+                ref parent_args @ ..,
+                closure_kind_ty,
+                signature_parts_ty,
+                tupled_upvars_ty,
+                coroutine_captures_by_ref_ty,
+                coroutine_witness_ty,
+            ] => CoroutineClosureArgsParts {
+                parent_args,
+                closure_kind_ty: closure_kind_ty.expect_ty(),
+                signature_parts_ty: signature_parts_ty.expect_ty(),
+                tupled_upvars_ty: tupled_upvars_ty.expect_ty(),
+                coroutine_captures_by_ref_ty: coroutine_captures_by_ref_ty.expect_ty(),
+                coroutine_witness_ty: coroutine_witness_ty.expect_ty(),
+            },
+            _ => bug!("closure args missing synthetics"),
+        }
+    }
+
+    pub fn parent_args(self) -> &'tcx [GenericArg<'tcx>] {
+        self.split().parent_args
+    }
+
+    #[inline]
+    pub fn upvar_tys(self) -> &'tcx List<Ty<'tcx>> {
+        match self.tupled_upvars_ty().kind() {
+            TyKind::Error(_) => ty::List::empty(),
+            TyKind::Tuple(..) => self.tupled_upvars_ty().tuple_fields(),
+            TyKind::Infer(_) => bug!("upvar_tys called before capture types are inferred"),
+            ty => bug!("Unexpected representation of upvar types tuple {:?}", ty),
+        }
+    }
+
+    #[inline]
+    pub fn tupled_upvars_ty(self) -> Ty<'tcx> {
+        self.split().tupled_upvars_ty
+    }
+
+    pub fn kind_ty(self) -> Ty<'tcx> {
+        self.split().closure_kind_ty
+    }
+
+    pub fn kind(self) -> ty::ClosureKind {
+        self.kind_ty().to_opt_closure_kind().unwrap()
+    }
+
+    pub fn signature_parts_ty(self) -> Ty<'tcx> {
+        self.split().signature_parts_ty
+    }
+
+    pub fn coroutine_closure_sig(self) -> ty::Binder<'tcx, CoroutineClosureSignature<'tcx>> {
+        let interior = self.coroutine_witness_ty();
+        let ty::FnPtr(sig) = self.signature_parts_ty().kind() else { bug!() };
+        sig.map_bound(|sig| {
+            let [resume_ty, tupled_inputs_ty] = *sig.inputs() else {
+                bug!();
+            };
+            let [yield_ty, return_ty] = **sig.output().tuple_fields() else { bug!() };
+            CoroutineClosureSignature {
+                interior,
+                tupled_inputs_ty,
+                resume_ty,
+                yield_ty,
+                return_ty,
+                c_variadic: sig.c_variadic,
+                unsafety: sig.unsafety,
+                abi: sig.abi,
+            }
+        })
+    }
+
+    pub fn coroutine_captures_by_ref_ty(self) -> Ty<'tcx> {
+        self.split().coroutine_captures_by_ref_ty
+    }
+
+    pub fn coroutine_witness_ty(self) -> Ty<'tcx> {
+        self.split().coroutine_witness_ty
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)]
+pub struct CoroutineClosureSignature<'tcx> {
+    pub interior: Ty<'tcx>,
+    pub tupled_inputs_ty: Ty<'tcx>,
+    pub resume_ty: Ty<'tcx>,
+    pub yield_ty: Ty<'tcx>,
+    pub return_ty: Ty<'tcx>,
+
+    // Like the `fn_sig_as_fn_ptr_ty` of a regular closure, these types
+    // never actually differ. But we save them rather than recreating them
+    // from scratch just for good measure.
+    /// Always false
+    pub c_variadic: bool,
+    /// Always [`hir::Unsafety::Normal`]
+    pub unsafety: hir::Unsafety,
+    /// Always [`abi::Abi::RustCall`]
+    pub abi: abi::Abi,
+}
+
+impl<'tcx> CoroutineClosureSignature<'tcx> {
+    /// Construct a coroutine from the closure signature. Since a coroutine signature
+    /// is agnostic to the type of generator that is returned (by-ref/by-move),
+    /// the caller must specify what "flavor" of generator that they'd like to
+    /// create. Additionally, they must manually compute the upvars of the closure.
+    ///
+    /// This helper is not really meant to be used directly except for early on
+    /// during typeck, when we want to put inference vars into the kind and upvars tys.
+    /// When the kind and upvars are known, use the other helper functions.
+    pub fn to_coroutine(
+        self,
+        tcx: TyCtxt<'tcx>,
+        parent_args: &'tcx [GenericArg<'tcx>],
+        coroutine_kind_ty: Ty<'tcx>,
+        coroutine_def_id: DefId,
+        tupled_upvars_ty: Ty<'tcx>,
+    ) -> Ty<'tcx> {
+        let coroutine_args = ty::CoroutineArgs::new(
+            tcx,
+            ty::CoroutineArgsParts {
+                parent_args,
+                kind_ty: coroutine_kind_ty,
+                resume_ty: self.resume_ty,
+                yield_ty: self.yield_ty,
+                return_ty: self.return_ty,
+                witness: self.interior,
+                tupled_upvars_ty,
+            },
+        );
+
+        Ty::new_coroutine(tcx, coroutine_def_id, coroutine_args.args)
+    }
+
+    /// Given known upvars and a [`ClosureKind`](ty::ClosureKind), compute the coroutine
+    /// returned by that corresponding async fn trait.
+    ///
+    /// This function expects the upvars to have been computed already, and doesn't check
+    /// that the `ClosureKind` is actually supported by the coroutine-closure.
+    pub fn to_coroutine_given_kind_and_upvars(
+        self,
+        tcx: TyCtxt<'tcx>,
+        parent_args: &'tcx [GenericArg<'tcx>],
+        coroutine_def_id: DefId,
+        goal_kind: ty::ClosureKind,
+        env_region: ty::Region<'tcx>,
+        closure_tupled_upvars_ty: Ty<'tcx>,
+        coroutine_captures_by_ref_ty: Ty<'tcx>,
+    ) -> Ty<'tcx> {
+        let tupled_upvars_ty = Self::tupled_upvars_by_closure_kind(
+            tcx,
+            goal_kind,
+            self.tupled_inputs_ty,
+            closure_tupled_upvars_ty,
+            coroutine_captures_by_ref_ty,
+            env_region,
+        );
+
+        self.to_coroutine(
+            tcx,
+            parent_args,
+            Ty::from_closure_kind(tcx, goal_kind),
+            coroutine_def_id,
+            tupled_upvars_ty,
+        )
+    }
+
+    /// Compute the tupled upvars that a coroutine-closure's output coroutine
+    /// would return for the given `ClosureKind`.
+    ///
+    /// When `ClosureKind` is `FnMut`/`Fn`, then this will use the "captures by ref"
+    /// to return a set of upvars which are borrowed with the given `env_region`.
+    ///
+    /// This ensures that the `AsyncFn::call` will return a coroutine whose upvars'
+    /// lifetimes are related to the lifetime of the borrow on the closure made for
+    /// the call. This allows borrowck to enforce the self-borrows correctly.
+    pub fn tupled_upvars_by_closure_kind(
+        tcx: TyCtxt<'tcx>,
+        kind: ty::ClosureKind,
+        tupled_inputs_ty: Ty<'tcx>,
+        closure_tupled_upvars_ty: Ty<'tcx>,
+        coroutine_captures_by_ref_ty: Ty<'tcx>,
+        env_region: ty::Region<'tcx>,
+    ) -> Ty<'tcx> {
+        match kind {
+            ty::ClosureKind::Fn | ty::ClosureKind::FnMut => {
+                let ty::FnPtr(sig) = *coroutine_captures_by_ref_ty.kind() else {
+                    bug!();
+                };
+                let coroutine_captures_by_ref_ty = tcx.replace_escaping_bound_vars_uncached(
+                    sig.output().skip_binder(),
+                    FnMutDelegate {
+                        consts: &mut |c, t| ty::Const::new_bound(tcx, ty::INNERMOST, c, t),
+                        types: &mut |t| Ty::new_bound(tcx, ty::INNERMOST, t),
+                        regions: &mut |_| env_region,
+                    },
+                );
+                Ty::new_tup_from_iter(
+                    tcx,
+                    tupled_inputs_ty
+                        .tuple_fields()
+                        .iter()
+                        .chain(coroutine_captures_by_ref_ty.tuple_fields()),
+                )
+            }
+            ty::ClosureKind::FnOnce => Ty::new_tup_from_iter(
+                tcx,
+                tupled_inputs_ty
+                    .tuple_fields()
+                    .iter()
+                    .chain(closure_tupled_upvars_ty.tuple_fields()),
+            ),
+        }
+    }
+}
 /// Similar to `ClosureArgs`; see the above documentation for more.
 #[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)]
 pub struct CoroutineArgs<'tcx> {
@@ -278,13 +548,27 @@ pub struct CoroutineArgs<'tcx> {
 pub struct CoroutineArgsParts<'tcx> {
     /// This is the args of the typeck root.
     pub parent_args: &'tcx [GenericArg<'tcx>],
+
+    /// The coroutines returned by a coroutine-closure's `AsyncFnOnce`/`AsyncFnMut`
+    /// implementations must be distinguished since the former takes the closure's
+    /// upvars by move, and the latter takes the closure's upvars by ref.
+    ///
+    /// This field distinguishes these fields so that codegen can select the right
+    /// body for the coroutine. This has the same type representation as the closure
+    /// kind: `i8`/`i16`/`i32`.
+    ///
+    /// For regular coroutines, this field will always just be `()`.
+    pub kind_ty: Ty<'tcx>,
+
     pub resume_ty: Ty<'tcx>,
     pub yield_ty: Ty<'tcx>,
     pub return_ty: Ty<'tcx>,
+
     /// The interior type of the coroutine.
     /// Represents all types that are stored in locals
     /// in the coroutine's body.
     pub witness: Ty<'tcx>,
+
     /// The upvars captured by the closure. Remains an inference variable
     /// until the upvar analysis, which happens late in HIR typeck.
     pub tupled_upvars_ty: Ty<'tcx>,
@@ -296,6 +580,7 @@ impl<'tcx> CoroutineArgs<'tcx> {
     pub fn new(tcx: TyCtxt<'tcx>, parts: CoroutineArgsParts<'tcx>) -> CoroutineArgs<'tcx> {
         CoroutineArgs {
             args: tcx.mk_args_from_iter(parts.parent_args.iter().copied().chain([
+                parts.kind_ty.into(),
                 parts.resume_ty.into(),
                 parts.yield_ty.into(),
                 parts.return_ty.into(),
@@ -309,16 +594,23 @@ impl<'tcx> CoroutineArgs<'tcx> {
     /// The ordering assumed here must match that used by `CoroutineArgs::new` above.
     fn split(self) -> CoroutineArgsParts<'tcx> {
         match self.args[..] {
-            [ref parent_args @ .., resume_ty, yield_ty, return_ty, witness, tupled_upvars_ty] => {
-                CoroutineArgsParts {
-                    parent_args,
-                    resume_ty: resume_ty.expect_ty(),
-                    yield_ty: yield_ty.expect_ty(),
-                    return_ty: return_ty.expect_ty(),
-                    witness: witness.expect_ty(),
-                    tupled_upvars_ty: tupled_upvars_ty.expect_ty(),
-                }
-            }
+            [
+                ref parent_args @ ..,
+                kind_ty,
+                resume_ty,
+                yield_ty,
+                return_ty,
+                witness,
+                tupled_upvars_ty,
+            ] => CoroutineArgsParts {
+                parent_args,
+                kind_ty: kind_ty.expect_ty(),
+                resume_ty: resume_ty.expect_ty(),
+                yield_ty: yield_ty.expect_ty(),
+                return_ty: return_ty.expect_ty(),
+                witness: witness.expect_ty(),
+                tupled_upvars_ty: tupled_upvars_ty.expect_ty(),
+            },
             _ => bug!("coroutine args missing synthetics"),
         }
     }
@@ -328,6 +620,11 @@ impl<'tcx> CoroutineArgs<'tcx> {
         self.split().parent_args
     }
 
+    // Returns the kind of the coroutine. See docs on the `kind_ty` field.
+    pub fn kind_ty(self) -> Ty<'tcx> {
+        self.split().kind_ty
+    }
+
     /// This describes the types that can be contained in a coroutine.
     /// It will be a type variable initially and unified in the last stages of typeck of a body.
     /// It contains a tuple of all the types that could end up on a coroutine frame.
@@ -479,6 +776,7 @@ impl<'tcx> CoroutineArgs<'tcx> {
 pub enum UpvarArgs<'tcx> {
     Closure(GenericArgsRef<'tcx>),
     Coroutine(GenericArgsRef<'tcx>),
+    CoroutineClosure(GenericArgsRef<'tcx>),
 }
 
 impl<'tcx> UpvarArgs<'tcx> {
@@ -490,6 +788,7 @@ impl<'tcx> UpvarArgs<'tcx> {
         let tupled_tys = match self {
             UpvarArgs::Closure(args) => args.as_closure().tupled_upvars_ty(),
             UpvarArgs::Coroutine(args) => args.as_coroutine().tupled_upvars_ty(),
+            UpvarArgs::CoroutineClosure(args) => args.as_coroutine_closure().tupled_upvars_ty(),
         };
 
         match tupled_tys.kind() {
@@ -505,6 +804,7 @@ impl<'tcx> UpvarArgs<'tcx> {
         match self {
             UpvarArgs::Closure(args) => args.as_closure().tupled_upvars_ty(),
             UpvarArgs::Coroutine(args) => args.as_coroutine().tupled_upvars_ty(),
+            UpvarArgs::CoroutineClosure(args) => args.as_coroutine_closure().tupled_upvars_ty(),
         }
     }
 }
@@ -1394,6 +1694,20 @@ impl<'tcx> Ty<'tcx> {
     }
 
     #[inline]
+    pub fn new_coroutine_closure(
+        tcx: TyCtxt<'tcx>,
+        def_id: DefId,
+        closure_args: GenericArgsRef<'tcx>,
+    ) -> Ty<'tcx> {
+        debug_assert_eq!(
+            closure_args.len(),
+            tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 5,
+            "closure constructed with incorrect substitutions"
+        );
+        Ty::new(tcx, CoroutineClosure(def_id, closure_args))
+    }
+
+    #[inline]
     pub fn new_coroutine(
         tcx: TyCtxt<'tcx>,
         def_id: DefId,
@@ -1401,7 +1715,7 @@ impl<'tcx> Ty<'tcx> {
     ) -> Ty<'tcx> {
         debug_assert_eq!(
             coroutine_args.len(),
-            tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 5,
+            tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 6,
             "coroutine constructed with incorrect number of substitutions"
         );
         Ty::new(tcx, Coroutine(def_id, coroutine_args))
@@ -1728,6 +2042,11 @@ impl<'tcx> Ty<'tcx> {
     }
 
     #[inline]
+    pub fn is_coroutine_closure(self) -> bool {
+        matches!(self.kind(), CoroutineClosure(..))
+    }
+
+    #[inline]
     pub fn is_integral(self) -> bool {
         matches!(self.kind(), Infer(IntVar(_)) | Int(_) | Uint(_))
     }
@@ -1795,7 +2114,7 @@ impl<'tcx> Ty<'tcx> {
             type BreakTy = ();
 
             fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-                if let ty::Closure(_, _) = t.kind() {
+                if let ty::Closure(..) = t.kind() {
                     ControlFlow::Break(())
                 } else {
                     t.super_visit_with(self)
@@ -1942,6 +2261,7 @@ impl<'tcx> Ty<'tcx> {
             | ty::FnPtr(..)
             | ty::Dynamic(..)
             | ty::Closure(..)
+            | ty::CoroutineClosure(..)
             | ty::CoroutineWitness(..)
             | ty::Never
             | ty::Tuple(_)
@@ -1980,6 +2300,7 @@ impl<'tcx> Ty<'tcx> {
             | ty::CoroutineWitness(..)
             | ty::Array(..)
             | ty::Closure(..)
+            | ty::CoroutineClosure(..)
             | ty::Never
             | ty::Error(_)
             // Extern types have metadata = ().
@@ -2034,7 +2355,7 @@ impl<'tcx> Ty<'tcx> {
 
             // "Bound" types appear in canonical queries when the
             // closure type is not yet known
-            Bound(..) | Infer(_) => None,
+            Bound(..) | Param(_) | Infer(_) => None,
 
             Error(_) => Some(ty::ClosureKind::Fn),
 
@@ -2077,6 +2398,7 @@ impl<'tcx> Ty<'tcx> {
             | ty::CoroutineWitness(..)
             | ty::Array(..)
             | ty::Closure(..)
+            | ty::CoroutineClosure(..)
             | ty::Never
             | ty::Error(_) => true,
 
@@ -2140,7 +2462,7 @@ impl<'tcx> Ty<'tcx> {
             ty::Coroutine(..) | ty::CoroutineWitness(..) => false,
 
             // Might be, but not "trivial" so just giving the safe answer.
-            ty::Adt(..) | ty::Closure(..) => false,
+            ty::Adt(..) | ty::Closure(..) | ty::CoroutineClosure(..) => false,
 
             // Needs normalization or revealing to determine, so no is the safe answer.
             ty::Alias(..) => false,
@@ -2212,6 +2534,7 @@ impl<'tcx> Ty<'tcx> {
             | FnPtr(_)
             | Dynamic(_, _, _)
             | Closure(_, _)
+            | CoroutineClosure(_, _)
             | Coroutine(_, _)
             | CoroutineWitness(..)
             | Never
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 8cc8abbe718..4feaeb0dd05 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -1119,6 +1119,7 @@ impl<'tcx> Ty<'tcx> {
             ty::Adt(..)
             | ty::Bound(..)
             | ty::Closure(..)
+            | ty::CoroutineClosure(..)
             | ty::Dynamic(..)
             | ty::Foreign(_)
             | ty::Coroutine(..)
@@ -1158,6 +1159,7 @@ impl<'tcx> Ty<'tcx> {
             ty::Adt(..)
             | ty::Bound(..)
             | ty::Closure(..)
+            | ty::CoroutineClosure(..)
             | ty::Dynamic(..)
             | ty::Foreign(_)
             | ty::Coroutine(..)
@@ -1280,7 +1282,11 @@ impl<'tcx> Ty<'tcx> {
             // Conservatively return `false` for all others...
 
             // Anonymous function types
-            ty::FnDef(..) | ty::Closure(..) | ty::Dynamic(..) | ty::Coroutine(..) => false,
+            ty::FnDef(..)
+            | ty::Closure(..)
+            | ty::CoroutineClosure(..)
+            | ty::Dynamic(..)
+            | ty::Coroutine(..) => false,
 
             // Generic or inferred types
             //
@@ -1424,6 +1430,7 @@ pub fn needs_drop_components<'tcx>(
         | ty::Placeholder(..)
         | ty::Infer(_)
         | ty::Closure(..)
+        | ty::CoroutineClosure(..)
         | ty::Coroutine(..)
         | ty::CoroutineWitness(..) => Ok(smallvec![ty]),
     }
@@ -1456,7 +1463,11 @@ pub fn is_trivially_const_drop(ty: Ty<'_>) -> bool {
 
         // Not trivial because they have components, and instead of looking inside,
         // we'll just perform trait selection.
-        ty::Closure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Adt(..) => false,
+        ty::Closure(..)
+        | ty::CoroutineClosure(..)
+        | ty::Coroutine(..)
+        | ty::CoroutineWitness(..)
+        | ty::Adt(..) => false,
 
         ty::Array(ty, _) | ty::Slice(ty) => is_trivially_const_drop(ty),
 
diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs
index 9050716db9d..46c26241c3e 100644
--- a/compiler/rustc_middle/src/ty/walk.rs
+++ b/compiler/rustc_middle/src/ty/walk.rs
@@ -189,6 +189,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
             }
             ty::Adt(_, args)
             | ty::Closure(_, args)
+            | ty::CoroutineClosure(_, args)
             | ty::Coroutine(_, args)
             | ty::CoroutineWitness(_, args)
             | ty::FnDef(_, args) => {
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index 6e8af7bb6df..c77f4a06d05 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -483,6 +483,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     UpvarArgs::Closure(args) => {
                         Box::new(AggregateKind::Closure(closure_id.to_def_id(), args))
                     }
+                    UpvarArgs::CoroutineClosure(args) => {
+                        Box::new(AggregateKind::CoroutineClosure(closure_id.to_def_id(), args))
+                    }
                 };
                 block.and(Rvalue::Aggregate(result, operands))
             }
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 714c5f2686e..9a2f2ceced1 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -495,7 +495,7 @@ fn construct_fn<'tcx>(
             args.as_coroutine().yield_ty(),
             args.as_coroutine().resume_ty(),
         ))),
-        ty::Closure(..) | ty::FnDef(..) => None,
+        ty::Closure(..) | ty::CoroutineClosure(..) | ty::FnDef(..) => None,
         ty => span_bug!(span_with_body, "unexpected type of body: {ty:?}"),
     };
 
@@ -822,6 +822,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let upvar_args = match closure_ty.kind() {
             ty::Closure(_, args) => ty::UpvarArgs::Closure(args),
             ty::Coroutine(_, args) => ty::UpvarArgs::Coroutine(args),
+            ty::CoroutineClosure(_, args) => ty::UpvarArgs::CoroutineClosure(args),
             _ => return,
         };
 
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 22094c112fc..35adcc33480 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -556,6 +556,9 @@ impl<'tcx> Cx<'tcx> {
                     ty::Coroutine(def_id, args) => {
                         (def_id, UpvarArgs::Coroutine(args), Some(tcx.coroutine_movability(def_id)))
                     }
+                    ty::CoroutineClosure(def_id, args) => {
+                        (def_id, UpvarArgs::CoroutineClosure(args), None)
+                    }
                     _ => {
                         span_bug!(expr.span, "closure expr w/o closure type: {:?}", closure_ty);
                     }
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index 5d0bb3954cc..f4f591d15b9 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -127,10 +127,24 @@ impl<'tcx> Cx<'tcx> {
             ty::Coroutine(..) => {
                 Param { ty: closure_ty, pat: None, ty_span: None, self_kind: None, hir_id: None }
             }
-            ty::Closure(_, closure_args) => {
+            ty::Closure(_, args) => {
                 let closure_env_ty = self.tcx.closure_env_ty(
                     closure_ty,
-                    closure_args.as_closure().kind(),
+                    args.as_closure().kind(),
+                    self.tcx.lifetimes.re_erased,
+                );
+                Param {
+                    ty: closure_env_ty,
+                    pat: None,
+                    ty_span: None,
+                    self_kind: None,
+                    hir_id: None,
+                }
+            }
+            ty::CoroutineClosure(_, args) => {
+                let closure_env_ty = self.tcx.closure_env_ty(
+                    closure_ty,
+                    args.as_coroutine_closure().kind(),
                     self.tcx.lifetimes.re_erased,
                 );
                 Param {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index caf7f4227db..1156e8be13e 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -291,7 +291,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
                 err = err.and(check_never_pattern(cx, pat));
             });
             err?;
-            Ok(cx.pattern_arena.alloc(cx.lower_pat(pat)))
+            Ok(self.pattern_arena.alloc(cx.lower_pat(pat)))
         }
     }
 
@@ -388,7 +388,6 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
             typeck_results: self.typeck_results,
             param_env: self.param_env,
             module: self.tcx.parent_module(self.lint_level).to_def_id(),
-            pattern_arena: self.pattern_arena,
             dropless_arena: self.dropless_arena,
             match_lint_level: self.lint_level,
             whole_match_span,
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 9d3a9bf6745..18a00724c3d 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -1,6 +1,5 @@
 use rustc_apfloat::Float;
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
 use rustc_index::Idx;
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::Obligation;
@@ -17,8 +16,8 @@ use std::cell::Cell;
 
 use super::PatCtxt;
 use crate::errors::{
-    IndirectStructuralMatch, InvalidPattern, NaNPattern, NonPartialEqMatch,
-    NontrivialStructuralMatch, PointerPattern, TypeNotStructural, UnionPattern, UnsizedPattern,
+    IndirectStructuralMatch, InvalidPattern, NaNPattern, NonPartialEqMatch, PointerPattern,
+    TypeNotStructural, UnionPattern, UnsizedPattern,
 };
 
 impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
@@ -33,11 +32,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         cv: mir::Const<'tcx>,
         id: hir::HirId,
         span: Span,
-        check_body_for_struct_match_violation: Option<DefId>,
     ) -> Box<Pat<'tcx>> {
         let infcx = self.tcx.infer_ctxt().build();
         let mut convert = ConstToPat::new(self, id, span, infcx);
-        convert.to_pat(cv, check_body_for_struct_match_violation)
+        convert.to_pat(cv)
     }
 }
 
@@ -103,11 +101,7 @@ impl<'tcx> ConstToPat<'tcx> {
         ty.is_structural_eq_shallow(self.infcx.tcx)
     }
 
-    fn to_pat(
-        &mut self,
-        cv: mir::Const<'tcx>,
-        check_body_for_struct_match_violation: Option<DefId>,
-    ) -> Box<Pat<'tcx>> {
+    fn to_pat(&mut self, cv: mir::Const<'tcx>) -> Box<Pat<'tcx>> {
         trace!(self.treat_byte_string_as_slice);
         // This method is just a wrapper handling a validity check; the heavy lifting is
         // performed by the recursive `recur` method, which is not meant to be
@@ -116,14 +110,6 @@ impl<'tcx> ConstToPat<'tcx> {
         // once indirect_structural_match is a full fledged error, this
         // level of indirection can be eliminated
 
-        let mir_structural_match_violation = check_body_for_struct_match_violation.map(|def_id| {
-            // `mir_const_qualif` must be called with the `DefId` of the item where the const is
-            // defined, not where it is declared. The difference is significant for associated
-            // constants.
-            self.tcx().mir_const_qualif(def_id).custom_eq
-        });
-        debug!(?check_body_for_struct_match_violation, ?mir_structural_match_violation);
-
         let have_valtree =
             matches!(cv, mir::Const::Ty(c) if matches!(c.kind(), ty::ConstKind::Value(_)));
         let inlined_const_as_pat = match cv {
@@ -137,15 +123,15 @@ impl<'tcx> ConstToPat<'tcx> {
                 | ty::ConstKind::Expr(_) => {
                     span_bug!(self.span, "unexpected const in `to_pat`: {:?}", c.kind())
                 }
-                ty::ConstKind::Value(valtree) => self
-                    .recur(valtree, cv.ty(), mir_structural_match_violation.unwrap_or(false))
-                    .unwrap_or_else(|_: FallbackToOpaqueConst| {
+                ty::ConstKind::Value(valtree) => {
+                    self.recur(valtree, cv.ty()).unwrap_or_else(|_: FallbackToOpaqueConst| {
                         Box::new(Pat {
                             span: self.span,
                             ty: cv.ty(),
                             kind: PatKind::Constant { value: cv },
                         })
-                    }),
+                    })
+                }
             },
             mir::Const::Unevaluated(_, _) => {
                 span_bug!(self.span, "unevaluated const in `to_pat`: {cv:?}")
@@ -160,7 +146,12 @@ impl<'tcx> ConstToPat<'tcx> {
         if self.saw_const_match_error.get().is_none() {
             // If we were able to successfully convert the const to some pat (possibly with some
             // lints, but no errors), double-check that all types in the const implement
-            // `Structural` and `PartialEq`.
+            // `PartialEq`. Even if we have a valtree, we may have found something
+            // in there with non-structural-equality, meaning we match using `PartialEq`
+            // and we hence have to check that that impl exists.
+            // This is all messy but not worth cleaning up: at some point we'll emit
+            // a hard error when we don't have a valtree or when we find something in
+            // the valtree that is not structural; then this can all be made a lot simpler.
 
             let structural =
                 traits::search_for_structural_match_violation(self.span, self.tcx(), cv.ty());
@@ -170,19 +161,12 @@ impl<'tcx> ConstToPat<'tcx> {
                 structural
             );
 
-            // This can occur because const qualification treats all associated constants as
-            // opaque, whereas `search_for_structural_match_violation` tries to monomorphize them
-            // before it runs.
-            //
-            // FIXME(#73448): Find a way to bring const qualification into parity with
-            // `search_for_structural_match_violation`.
-            if structural.is_none() && mir_structural_match_violation.unwrap_or(false) {
-                warn!("MIR const-checker found novel structural match violation. See #73448.");
-                return inlined_const_as_pat;
-            }
-
             if let Some(non_sm_ty) = structural {
                 if !self.type_has_partial_eq_impl(cv.ty()) {
+                    // This is reachable and important even if we have a valtree: there might be
+                    // non-structural things in a valtree, in which case we fall back to `PartialEq`
+                    // comparison, in which case we better make sure the trait is implemented for
+                    // each inner type (and not just for the surrounding type).
                     let e = if let ty::Adt(def, ..) = non_sm_ty.kind() {
                         if def.is_union() {
                             let err = UnionPattern { span: self.span };
@@ -201,35 +185,18 @@ impl<'tcx> ConstToPat<'tcx> {
                     // We errored. Signal that in the pattern, so that follow up errors can be silenced.
                     let kind = PatKind::Error(e);
                     return Box::new(Pat { span: self.span, ty: cv.ty(), kind });
-                } else if let ty::Adt(..) = cv.ty().kind()
-                    && matches!(cv, mir::Const::Val(..))
-                {
-                    // This branch is only entered when the current `cv` is `mir::Const::Val`.
-                    // This is because `mir::Const::ty` has already been handled by `Self::recur`
-                    // and the invalid types may be ignored.
+                } else if !have_valtree {
+                    // Not being structural prevented us from constructing a valtree,
+                    // so this is definitely a case we want to reject.
                     let err = TypeNotStructural { span: self.span, non_sm_ty };
                     let e = self.tcx().dcx().emit_err(err);
                     let kind = PatKind::Error(e);
                     return Box::new(Pat { span: self.span, ty: cv.ty(), kind });
-                } else if !self.saw_const_match_lint.get() {
-                    if let Some(mir_structural_match_violation) = mir_structural_match_violation {
-                        match non_sm_ty.kind() {
-                            ty::Adt(..) if mir_structural_match_violation => {
-                                self.tcx().emit_node_span_lint(
-                                    lint::builtin::INDIRECT_STRUCTURAL_MATCH,
-                                    self.id,
-                                    self.span,
-                                    IndirectStructuralMatch { non_sm_ty },
-                                );
-                            }
-                            _ => {
-                                debug!(
-                                    "`search_for_structural_match_violation` found one, but `CustomEq` was \
-                                  not in the qualifs for that `const`"
-                                );
-                            }
-                        }
-                    }
+                } else {
+                    // This could be a violation in an inactive enum variant.
+                    // Since we have a valtree, we trust that we have traversed the full valtree and
+                    // complained about structural match violations there, so we don't
+                    // have to check anything any more.
                 }
             } else if !have_valtree && !self.saw_const_match_lint.get() {
                 // The only way valtree construction can fail without the structural match
@@ -299,7 +266,7 @@ impl<'tcx> ConstToPat<'tcx> {
                 let field = FieldIdx::new(idx);
                 // Patterns can only use monomorphic types.
                 let ty = self.tcx().normalize_erasing_regions(self.param_env, ty);
-                Ok(FieldPat { field, pattern: self.recur(val, ty, false)? })
+                Ok(FieldPat { field, pattern: self.recur(val, ty)? })
             })
             .collect()
     }
@@ -310,7 +277,6 @@ impl<'tcx> ConstToPat<'tcx> {
         &self,
         cv: ValTree<'tcx>,
         ty: Ty<'tcx>,
-        mir_structural_match_violation: bool,
     ) -> Result<Box<Pat<'tcx>>, FallbackToOpaqueConst> {
         let id = self.id;
         let span = self.span;
@@ -395,7 +361,7 @@ impl<'tcx> ConstToPat<'tcx> {
                 prefix: cv
                     .unwrap_branch()
                     .iter()
-                    .map(|val| self.recur(*val, *elem_ty, false))
+                    .map(|val| self.recur(*val, *elem_ty))
                     .collect::<Result<_, _>>()?,
                 slice: None,
                 suffix: Box::new([]),
@@ -404,7 +370,7 @@ impl<'tcx> ConstToPat<'tcx> {
                 prefix: cv
                     .unwrap_branch()
                     .iter()
-                    .map(|val| self.recur(*val, *elem_ty, false))
+                    .map(|val| self.recur(*val, *elem_ty))
                     .collect::<Result<_, _>>()?,
                 slice: None,
                 suffix: Box::new([]),
@@ -471,7 +437,7 @@ impl<'tcx> ConstToPat<'tcx> {
                             _ => *pointee_ty,
                         };
                         // References have the same valtree representation as their pointee.
-                        let subpattern = self.recur(cv, pointee_ty, false)?;
+                        let subpattern = self.recur(cv, pointee_ty)?;
                         self.behind_reference.set(old);
                         PatKind::Deref { subpattern }
                     }
@@ -512,25 +478,6 @@ impl<'tcx> ConstToPat<'tcx> {
             }
         };
 
-        if self.saw_const_match_error.get().is_none()
-            && !self.saw_const_match_lint.get()
-            && mir_structural_match_violation
-            // FIXME(#73448): Find a way to bring const qualification into parity with
-            // `search_for_structural_match_violation` and then remove this condition.
-
-            // Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we
-            // could get `Option<NonStructEq>`, even though `Option` is annotated with derive.
-            && let Some(non_sm_ty) = traits::search_for_structural_match_violation(span, tcx, ty)
-        {
-            self.saw_const_match_lint.set(true);
-            tcx.emit_node_span_lint(
-                lint::builtin::NONTRIVIAL_STRUCTURAL_MATCH,
-                id,
-                span,
-                NontrivialStructuralMatch { non_sm_ty },
-            );
-        }
-
         Ok(Box::new(Pat { span, ty, kind }))
     }
 }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 2190ad14b55..1a5cf13e289 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -542,7 +542,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
 
         match const_value {
             Ok(const_) => {
-                let pattern = self.const_to_pat(const_, id, span, Some(instance.def_id()));
+                let pattern = self.const_to_pat(const_, id, span);
 
                 if !is_associated_const {
                     return pattern;
@@ -612,7 +612,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         };
         if let Some(lit_input) = lit_input {
             match tcx.at(expr.span).lit_to_const(lit_input) {
-                Ok(c) => return self.const_to_pat(Const::Ty(c), id, span, None).kind,
+                Ok(c) => return self.const_to_pat(Const::Ty(c), id, span).kind,
                 // If an error occurred, ignore that it's a literal
                 // and leave reporting the error up to const eval of
                 // the unevaluated constant below.
@@ -635,17 +635,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         if let Ok(Some(valtree)) =
             self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, Some(span))
         {
-            let subpattern = self.const_to_pat(
-                Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)),
-                id,
-                span,
-                None,
-            );
+            let subpattern =
+                self.const_to_pat(Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)), id, span);
             PatKind::InlineConstant { subpattern, def: def_id }
         } else {
             // If that fails, convert it to an opaque constant pattern.
             match tcx.const_eval_resolve(self.param_env, uneval, Some(span)) {
-                Ok(val) => self.const_to_pat(mir::Const::Val(val, ty), id, span, None).kind,
+                Ok(val) => self.const_to_pat(mir::Const::Val(val, ty), id, span).kind,
                 Err(ErrorHandled::TooGeneric(_)) => {
                     // If we land here it means the const can't be evaluated because it's `TooGeneric`.
                     let e = self.tcx.dcx().emit_err(ConstPatternDependsOnGenericParameter { span });
@@ -681,9 +677,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         let lit_input =
             LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg };
         match self.tcx.at(expr.span).lit_to_const(lit_input) {
-            Ok(constant) => {
-                self.const_to_pat(Const::Ty(constant), expr.hir_id, lit.span, None).kind
-            }
+            Ok(constant) => self.const_to_pat(Const::Ty(constant), expr.hir_id, lit.span).kind,
             Err(LitToConstError::Reported(e)) => PatKind::Error(e),
             Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"),
         }
diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
index 862876f53c7..1b2f2cd9477 100644
--- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
@@ -861,6 +861,9 @@ where
         let ty = self.place_ty(self.place);
         match ty.kind() {
             ty::Closure(_, args) => self.open_drop_for_tuple(args.as_closure().upvar_tys()),
+            ty::CoroutineClosure(_, args) => {
+                self.open_drop_for_tuple(args.as_coroutine_closure().upvar_tys())
+            }
             // Note that `elaborate_drops` only drops the upvars of a coroutine,
             // and this is ok because `open_drop` here can only be reached
             // within that own coroutine's resume function.
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index 38ee26c5a87..30dd915521c 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -154,7 +154,8 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> {
                     | ty::FnDef(_, _)
                     | ty::FnPtr(_)
                     | ty::Dynamic(_, _, _)
-                    | ty::Closure(_, _)
+                    | ty::Closure(..)
+                    | ty::CoroutineClosure(..)
                     | ty::Coroutine(_, _)
                     | ty::CoroutineWitness(..)
                     | ty::Never
@@ -177,7 +178,10 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> {
                             union_path.get_or_insert(base);
                         }
                     }
-                    ty::Closure(_, _) | ty::Coroutine(_, _) | ty::Tuple(_) => (),
+                    ty::Closure(..)
+                    | ty::CoroutineClosure(..)
+                    | ty::Coroutine(_, _)
+                    | ty::Tuple(_) => (),
                     ty::Bool
                     | ty::Char
                     | ty::Int(_)
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index 2802f5491be..2b2af6ee7da 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -1149,6 +1149,12 @@ pub fn iter_fields<'tcx>(
         ty::Closure(_, args) => {
             iter_fields(args.as_closure().tupled_upvars_ty(), tcx, param_env, f);
         }
+        ty::Coroutine(_, args) => {
+            iter_fields(args.as_coroutine().tupled_upvars_ty(), tcx, param_env, f);
+        }
+        ty::CoroutineClosure(_, args) => {
+            iter_fields(args.as_coroutine_closure().tupled_upvars_ty(), tcx, param_env, f);
+        }
         _ => (),
     }
 }
diff --git a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
index dfc7a9891f9..451d3be255f 100644
--- a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
+++ b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
@@ -39,6 +39,7 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls {
         let body_abi = match body_ty.kind() {
             ty::FnDef(..) => body_ty.fn_sig(tcx).abi(),
             ty::Closure(..) => Abi::RustCall,
+            ty::CoroutineClosure(..) => Abi::RustCall,
             ty::Coroutine(..) => Abi::Rust,
             _ => span_bug!(body.span, "unexpected body ty: {:?}", body_ty),
         };
diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
index 6c4c3917cb5..fbb62695383 100644
--- a/compiler/rustc_mir_transform/src/check_unsafety.rs
+++ b/compiler/rustc_mir_transform/src/check_unsafety.rs
@@ -128,7 +128,9 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
                         ),
                     }
                 }
-                &AggregateKind::Closure(def_id, _) | &AggregateKind::Coroutine(def_id, _) => {
+                &AggregateKind::Closure(def_id, _)
+                | &AggregateKind::CoroutineClosure(def_id, _)
+                | &AggregateKind::Coroutine(def_id, _) => {
                     let def_id = def_id.expect_local();
                     let UnsafetyCheckResult { violations, used_unsafe_blocks, .. } =
                         self.tcx.mir_unsafety_check_result(def_id);
diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs
index aa22b8c7c58..f2448ee3d44 100644
--- a/compiler/rustc_mir_transform/src/const_prop_lint.rs
+++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs
@@ -607,7 +607,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                     AggregateKind::Array(_)
                     | AggregateKind::Tuple
                     | AggregateKind::Closure(_, _)
-                    | AggregateKind::Coroutine(_, _) => VariantIdx::new(0),
+                    | AggregateKind::Coroutine(_, _)
+                    | AggregateKind::CoroutineClosure(_, _) => VariantIdx::new(0),
                 },
             },
 
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index bde879f6067..297b2fa143d 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -50,6 +50,9 @@
 //! For coroutines with state 1 (returned) and state 2 (poisoned) it does nothing.
 //! Otherwise it drops all the values in scope at the last suspension point.
 
+mod by_move_body;
+pub use by_move_body::ByMoveBody;
+
 use crate::abort_unwinding_calls;
 use crate::deref_separator::deref_finder;
 use crate::errors;
diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
new file mode 100644
index 00000000000..fcd4715b9e8
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
@@ -0,0 +1,156 @@
+//! A MIR pass which duplicates a coroutine's body and removes any derefs which
+//! would be present for upvars that are taken by-ref. The result of which will
+//! be a coroutine body that takes all of its upvars by-move, and which we stash
+//! into the `CoroutineInfo` for all coroutines returned by coroutine-closures.
+
+use rustc_data_structures::fx::FxIndexSet;
+use rustc_hir as hir;
+use rustc_middle::mir::visit::MutVisitor;
+use rustc_middle::mir::{self, dump_mir, MirPass};
+use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt};
+use rustc_target::abi::FieldIdx;
+
+pub struct ByMoveBody;
+
+impl<'tcx> MirPass<'tcx> for ByMoveBody {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) {
+        let Some(coroutine_def_id) = body.source.def_id().as_local() else {
+            return;
+        };
+        let Some(hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Closure)) =
+            tcx.coroutine_kind(coroutine_def_id)
+        else {
+            return;
+        };
+        let coroutine_ty = body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty;
+        let ty::Coroutine(_, args) = *coroutine_ty.kind() else { bug!() };
+
+        let coroutine_kind = args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap();
+        if coroutine_kind == ty::ClosureKind::FnOnce {
+            return;
+        }
+
+        let mut by_ref_fields = FxIndexSet::default();
+        let by_move_upvars = Ty::new_tup_from_iter(
+            tcx,
+            tcx.closure_captures(coroutine_def_id).iter().enumerate().map(|(idx, capture)| {
+                if capture.is_by_ref() {
+                    by_ref_fields.insert(FieldIdx::from_usize(idx));
+                }
+                capture.place.ty()
+            }),
+        );
+        let by_move_coroutine_ty = Ty::new_coroutine(
+            tcx,
+            coroutine_def_id.to_def_id(),
+            ty::CoroutineArgs::new(
+                tcx,
+                ty::CoroutineArgsParts {
+                    parent_args: args.as_coroutine().parent_args(),
+                    kind_ty: Ty::from_closure_kind(tcx, ty::ClosureKind::FnOnce),
+                    resume_ty: args.as_coroutine().resume_ty(),
+                    yield_ty: args.as_coroutine().yield_ty(),
+                    return_ty: args.as_coroutine().return_ty(),
+                    witness: args.as_coroutine().witness(),
+                    tupled_upvars_ty: by_move_upvars,
+                },
+            )
+            .args,
+        );
+
+        let mut by_move_body = body.clone();
+        MakeByMoveBody { tcx, by_ref_fields, by_move_coroutine_ty }.visit_body(&mut by_move_body);
+        dump_mir(tcx, false, "coroutine_by_move", &0, &by_move_body, |_, _| Ok(()));
+        by_move_body.source = mir::MirSource {
+            instance: InstanceDef::CoroutineKindShim {
+                coroutine_def_id: coroutine_def_id.to_def_id(),
+                target_kind: ty::ClosureKind::FnOnce,
+            },
+            promoted: None,
+        };
+        body.coroutine.as_mut().unwrap().by_move_body = Some(by_move_body);
+
+        // If this is coming from an `AsyncFn` coroutine-closure, we must also create a by-mut body.
+        // This is actually just a copy of the by-ref body, but with a different self type.
+        // FIXME(async_closures): We could probably unify this with the by-ref body somehow.
+        if coroutine_kind == ty::ClosureKind::Fn {
+            let by_mut_coroutine_ty = Ty::new_coroutine(
+                tcx,
+                coroutine_def_id.to_def_id(),
+                ty::CoroutineArgs::new(
+                    tcx,
+                    ty::CoroutineArgsParts {
+                        parent_args: args.as_coroutine().parent_args(),
+                        kind_ty: Ty::from_closure_kind(tcx, ty::ClosureKind::FnMut),
+                        resume_ty: args.as_coroutine().resume_ty(),
+                        yield_ty: args.as_coroutine().yield_ty(),
+                        return_ty: args.as_coroutine().return_ty(),
+                        witness: args.as_coroutine().witness(),
+                        tupled_upvars_ty: args.as_coroutine().tupled_upvars_ty(),
+                    },
+                )
+                .args,
+            );
+            let mut by_mut_body = body.clone();
+            by_mut_body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty = by_mut_coroutine_ty;
+            dump_mir(tcx, false, "coroutine_by_mut", &0, &by_mut_body, |_, _| Ok(()));
+            by_mut_body.source = mir::MirSource {
+                instance: InstanceDef::CoroutineKindShim {
+                    coroutine_def_id: coroutine_def_id.to_def_id(),
+                    target_kind: ty::ClosureKind::FnMut,
+                },
+                promoted: None,
+            };
+            body.coroutine.as_mut().unwrap().by_mut_body = Some(by_mut_body);
+        }
+    }
+}
+
+struct MakeByMoveBody<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    by_ref_fields: FxIndexSet<FieldIdx>,
+    by_move_coroutine_ty: Ty<'tcx>,
+}
+
+impl<'tcx> MutVisitor<'tcx> for MakeByMoveBody<'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn visit_place(
+        &mut self,
+        place: &mut mir::Place<'tcx>,
+        context: mir::visit::PlaceContext,
+        location: mir::Location,
+    ) {
+        if place.local == ty::CAPTURE_STRUCT_LOCAL
+            && !place.projection.is_empty()
+            && let mir::ProjectionElem::Field(idx, ty) = place.projection[0]
+            && self.by_ref_fields.contains(&idx)
+        {
+            let (begin, end) = place.projection[1..].split_first().unwrap();
+            // FIXME(async_closures): I'm actually a bit surprised to see that we always
+            // initially deref the by-ref upvars. If this is not actually true, then we
+            // will at least get an ICE that explains why this isn't true :^)
+            assert_eq!(*begin, mir::ProjectionElem::Deref);
+            // Peel one ref off of the ty.
+            let peeled_ty = ty.builtin_deref(true).unwrap().ty;
+            *place = mir::Place {
+                local: place.local,
+                projection: self.tcx.mk_place_elems_from_iter(
+                    [mir::ProjectionElem::Field(idx, peeled_ty)]
+                        .into_iter()
+                        .chain(end.iter().copied()),
+                ),
+            };
+        }
+        self.super_place(place, context, location);
+    }
+
+    fn visit_local_decl(&mut self, local: mir::Local, local_decl: &mut mir::LocalDecl<'tcx>) {
+        // Replace the type of the self arg.
+        if local == ty::CAPTURE_STRUCT_LOCAL {
+            local_decl.ty = self.by_move_coroutine_ty;
+        }
+    }
+}
diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs
index 8c11dea5d4e..9a1d8bae6b4 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters.rs
@@ -1,4 +1,5 @@
-use rustc_data_structures::fx::FxIndexMap;
+use rustc_data_structures::captures::Captures;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::graph::WithNumNodes;
 use rustc_index::bit_set::BitSet;
 use rustc_index::IndexVec;
@@ -38,19 +39,27 @@ impl Debug for BcbCounter {
     }
 }
 
+#[derive(Debug)]
+pub(super) enum CounterIncrementSite {
+    Node { bcb: BasicCoverageBlock },
+    Edge { from_bcb: BasicCoverageBlock, to_bcb: BasicCoverageBlock },
+}
+
 /// Generates and stores coverage counter and coverage expression information
 /// associated with nodes/edges in the BCB graph.
 pub(super) struct CoverageCounters {
-    next_counter_id: CounterId,
+    /// List of places where a counter-increment statement should be injected
+    /// into MIR, each with its corresponding counter ID.
+    counter_increment_sites: IndexVec<CounterId, CounterIncrementSite>,
 
     /// Coverage counters/expressions that are associated with individual BCBs.
     bcb_counters: IndexVec<BasicCoverageBlock, Option<BcbCounter>>,
     /// Coverage counters/expressions that are associated with the control-flow
     /// edge between two BCBs.
     ///
-    /// The iteration order of this map can affect the precise contents of MIR,
-    /// so we use `FxIndexMap` to avoid query stability hazards.
-    bcb_edge_counters: FxIndexMap<(BasicCoverageBlock, BasicCoverageBlock), BcbCounter>,
+    /// We currently don't iterate over this map, but if we do in the future,
+    /// switch it back to `FxIndexMap` to avoid query stability hazards.
+    bcb_edge_counters: FxHashMap<(BasicCoverageBlock, BasicCoverageBlock), BcbCounter>,
     /// Tracks which BCBs have a counter associated with some incoming edge.
     /// Only used by assertions, to verify that BCBs with incoming edge
     /// counters do not have their own physical counters (expressions are allowed).
@@ -71,9 +80,9 @@ impl CoverageCounters {
         let num_bcbs = basic_coverage_blocks.num_nodes();
 
         let mut this = Self {
-            next_counter_id: CounterId::START,
+            counter_increment_sites: IndexVec::new(),
             bcb_counters: IndexVec::from_elem_n(None, num_bcbs),
-            bcb_edge_counters: FxIndexMap::default(),
+            bcb_edge_counters: FxHashMap::default(),
             bcb_has_incoming_edge_counters: BitSet::new_empty(num_bcbs),
             expressions: IndexVec::new(),
         };
@@ -84,8 +93,8 @@ impl CoverageCounters {
         this
     }
 
-    fn make_counter(&mut self) -> BcbCounter {
-        let id = self.next_counter();
+    fn make_counter(&mut self, site: CounterIncrementSite) -> BcbCounter {
+        let id = self.counter_increment_sites.push(site);
         BcbCounter::Counter { id }
     }
 
@@ -103,15 +112,8 @@ impl CoverageCounters {
         self.make_expression(lhs, Op::Add, rhs)
     }
 
-    /// Counter IDs start from one and go up.
-    fn next_counter(&mut self) -> CounterId {
-        let next = self.next_counter_id;
-        self.next_counter_id = self.next_counter_id + 1;
-        next
-    }
-
     pub(super) fn num_counters(&self) -> usize {
-        self.next_counter_id.as_usize()
+        self.counter_increment_sites.len()
     }
 
     #[cfg(test)]
@@ -171,22 +173,26 @@ impl CoverageCounters {
         self.bcb_counters[bcb]
     }
 
-    pub(super) fn bcb_node_counters(
+    /// Returns an iterator over all the nodes/edges in the coverage graph that
+    /// should have a counter-increment statement injected into MIR, along with
+    /// each site's corresponding counter ID.
+    pub(super) fn counter_increment_sites(
         &self,
-    ) -> impl Iterator<Item = (BasicCoverageBlock, &BcbCounter)> {
-        self.bcb_counters
-            .iter_enumerated()
-            .filter_map(|(bcb, counter_kind)| Some((bcb, counter_kind.as_ref()?)))
+    ) -> impl Iterator<Item = (CounterId, &CounterIncrementSite)> {
+        self.counter_increment_sites.iter_enumerated()
     }
 
-    /// For each edge in the BCB graph that has an associated counter, yields
-    /// that edge's *from* and *to* nodes, and its counter.
-    pub(super) fn bcb_edge_counters(
+    /// Returns an iterator over the subset of BCB nodes that have been associated
+    /// with a counter *expression*, along with the ID of that expression.
+    pub(super) fn bcb_nodes_with_coverage_expressions(
         &self,
-    ) -> impl Iterator<Item = (BasicCoverageBlock, BasicCoverageBlock, &BcbCounter)> {
-        self.bcb_edge_counters
-            .iter()
-            .map(|(&(from_bcb, to_bcb), counter_kind)| (from_bcb, to_bcb, counter_kind))
+    ) -> impl Iterator<Item = (BasicCoverageBlock, ExpressionId)> + Captures<'_> {
+        self.bcb_counters.iter_enumerated().filter_map(|(bcb, &counter_kind)| match counter_kind {
+            // Yield the BCB along with its associated expression ID.
+            Some(BcbCounter::Expression { id }) => Some((bcb, id)),
+            // This BCB is associated with a counter or nothing, so skip it.
+            Some(BcbCounter::Counter { .. }) | None => None,
+        })
     }
 
     pub(super) fn into_expressions(self) -> IndexVec<ExpressionId, Expression> {
@@ -339,7 +345,8 @@ impl<'a> MakeBcbCounters<'a> {
         // program results in a tight infinite loop, but it should still compile.
         let one_path_to_target = !self.basic_coverage_blocks.bcb_has_multiple_in_edges(bcb);
         if one_path_to_target || self.bcb_predecessors(bcb).contains(&bcb) {
-            let counter_kind = self.coverage_counters.make_counter();
+            let counter_kind =
+                self.coverage_counters.make_counter(CounterIncrementSite::Node { bcb });
             if one_path_to_target {
                 debug!("{bcb:?} gets a new counter: {counter_kind:?}");
             } else {
@@ -401,7 +408,8 @@ impl<'a> MakeBcbCounters<'a> {
         }
 
         // Make a new counter to count this edge.
-        let counter_kind = self.coverage_counters.make_counter();
+        let counter_kind =
+            self.coverage_counters.make_counter(CounterIncrementSite::Edge { from_bcb, to_bcb });
         debug!("Edge {from_bcb:?}->{to_bcb:?} gets a new counter: {counter_kind:?}");
         self.coverage_counters.set_bcb_edge_counter(from_bcb, to_bcb, counter_kind)
     }
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 3aa41250fd3..4c5be0a3f4b 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -7,7 +7,7 @@ mod spans;
 #[cfg(test)]
 mod tests;
 
-use self::counters::{BcbCounter, CoverageCounters};
+use self::counters::{CounterIncrementSite, CoverageCounters};
 use self::graph::{BasicCoverageBlock, CoverageGraph};
 use self::spans::{BcbMapping, BcbMappingKind, CoverageSpans};
 
@@ -155,61 +155,52 @@ fn inject_coverage_statements<'tcx>(
     bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool,
     coverage_counters: &CoverageCounters,
 ) {
-    // Process the counters associated with BCB nodes.
-    for (bcb, counter_kind) in coverage_counters.bcb_node_counters() {
-        let do_inject = match counter_kind {
-            // Counter-increment statements always need to be injected.
-            BcbCounter::Counter { .. } => true,
-            // The only purpose of expression-used statements is to detect
-            // when a mapping is unreachable, so we only inject them for
-            // expressions with one or more mappings.
-            BcbCounter::Expression { .. } => bcb_has_coverage_spans(bcb),
-        };
-        if do_inject {
-            inject_statement(
-                mir_body,
-                make_mir_coverage_kind(counter_kind),
-                basic_coverage_blocks[bcb].leader_bb(),
-            );
-        }
-    }
-
-    // Process the counters associated with BCB edges.
-    for (from_bcb, to_bcb, counter_kind) in coverage_counters.bcb_edge_counters() {
-        let do_inject = match counter_kind {
-            // Counter-increment statements always need to be injected.
-            BcbCounter::Counter { .. } => true,
-            // BCB-edge expressions never have mappings, so they never need
-            // a corresponding statement.
-            BcbCounter::Expression { .. } => false,
+    // Inject counter-increment statements into MIR.
+    for (id, counter_increment_site) in coverage_counters.counter_increment_sites() {
+        // Determine the block to inject a counter-increment statement into.
+        // For BCB nodes this is just their first block, but for edges we need
+        // to create a new block between the two BCBs, and inject into that.
+        let target_bb = match *counter_increment_site {
+            CounterIncrementSite::Node { bcb } => basic_coverage_blocks[bcb].leader_bb(),
+            CounterIncrementSite::Edge { from_bcb, to_bcb } => {
+                // Create a new block between the last block of `from_bcb` and
+                // the first block of `to_bcb`.
+                let from_bb = basic_coverage_blocks[from_bcb].last_bb();
+                let to_bb = basic_coverage_blocks[to_bcb].leader_bb();
+
+                let new_bb = inject_edge_counter_basic_block(mir_body, from_bb, to_bb);
+                debug!(
+                    "Edge {from_bcb:?} (last {from_bb:?}) -> {to_bcb:?} (leader {to_bb:?}) \
+                    requires a new MIR BasicBlock {new_bb:?} for counter increment {id:?}",
+                );
+                new_bb
+            }
         };
-        if !do_inject {
-            continue;
-        }
-
-        // We need to inject a coverage statement into a new BB between the
-        // last BB of `from_bcb` and the first BB of `to_bcb`.
-        let from_bb = basic_coverage_blocks[from_bcb].last_bb();
-        let to_bb = basic_coverage_blocks[to_bcb].leader_bb();
 
-        let new_bb = inject_edge_counter_basic_block(mir_body, from_bb, to_bb);
-        debug!(
-            "Edge {from_bcb:?} (last {from_bb:?}) -> {to_bcb:?} (leader {to_bb:?}) \
-                requires a new MIR BasicBlock {new_bb:?} for edge counter {counter_kind:?}",
-        );
-
-        // Inject a counter into the newly-created BB.
-        inject_statement(mir_body, make_mir_coverage_kind(counter_kind), new_bb);
+        inject_statement(mir_body, CoverageKind::CounterIncrement { id }, target_bb);
     }
-}
 
-fn make_mir_coverage_kind(counter_kind: &BcbCounter) -> CoverageKind {
-    match *counter_kind {
-        BcbCounter::Counter { id } => CoverageKind::CounterIncrement { id },
-        BcbCounter::Expression { id } => CoverageKind::ExpressionUsed { id },
+    // For each counter expression that is directly associated with at least one
+    // span, we inject an "expression-used" statement, so that coverage codegen
+    // can check whether the injected statement survived MIR optimization.
+    // (BCB edges can't have spans, so we only need to process BCB nodes here.)
+    //
+    // See the code in `rustc_codegen_llvm::coverageinfo::map_data` that deals
+    // with "expressions seen" and "zero terms".
+    for (bcb, expression_id) in coverage_counters
+        .bcb_nodes_with_coverage_expressions()
+        .filter(|&(bcb, _)| bcb_has_coverage_spans(bcb))
+    {
+        inject_statement(
+            mir_body,
+            CoverageKind::ExpressionUsed { id: expression_id },
+            basic_coverage_blocks[bcb].leader_bb(),
+        );
     }
 }
 
+/// Given two basic blocks that have a control-flow edge between them, creates
+/// and returns a new block that sits between those blocks.
 fn inject_edge_counter_basic_block(
     mir_body: &mut mir::Body<'_>,
     from_bb: BasicBlock,
diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
index 5b4d58836b4..01fae7c0bec 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
@@ -156,7 +156,9 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>(
 fn is_closure_or_coroutine(statement: &Statement<'_>) -> bool {
     match statement.kind {
         StatementKind::Assign(box (_, Rvalue::Aggregate(box ref agg_kind, _))) => match agg_kind {
-            AggregateKind::Closure(_, _) | AggregateKind::Coroutine(_, _) => true,
+            AggregateKind::Closure(_, _)
+            | AggregateKind::Coroutine(_, _)
+            | AggregateKind::CoroutineClosure(..) => true,
             _ => false,
         },
         _ => false,
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index ad12bce9b02..6a37047a693 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -696,6 +696,7 @@ fn try_write_constant<'tcx>(
         | ty::Bound(..)
         | ty::Placeholder(..)
         | ty::Closure(..)
+        | ty::CoroutineClosure(..)
         | ty::Coroutine(..)
         | ty::Dynamic(..) => throw_machine_stop_str!("unsupported type"),
 
diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
index db7dfc5b43e..b0d758bcbfe 100644
--- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
+++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
@@ -57,6 +57,7 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool {
     let body_abi = match body_ty.kind() {
         ty::FnDef(..) => body_ty.fn_sig(tcx).abi(),
         ty::Closure(..) => Abi::RustCall,
+        ty::CoroutineClosure(..) => Abi::RustCall,
         ty::Coroutine(..) => Abi::Rust,
         _ => span_bug!(body.span, "unexpected body ty: {:?}", body_ty),
     };
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 390ec3e1a36..f9798bc4e70 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -861,9 +861,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         let tcx = self.tcx;
         if fields.is_empty() {
             let is_zst = match *kind {
-                AggregateKind::Array(..) | AggregateKind::Tuple | AggregateKind::Closure(..) => {
-                    true
-                }
+                AggregateKind::Array(..)
+                | AggregateKind::Tuple
+                | AggregateKind::Closure(..)
+                | AggregateKind::CoroutineClosure(..) => true,
                 // Only enums can be non-ZST.
                 AggregateKind::Adt(did, ..) => tcx.def_kind(did) != DefKind::Enum,
                 // Coroutines are never ZST, as they at least contain the implicit states.
@@ -885,7 +886,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 assert!(!fields.is_empty());
                 (AggregateTy::Tuple, FIRST_VARIANT)
             }
-            AggregateKind::Closure(did, substs) | AggregateKind::Coroutine(did, substs) => {
+            AggregateKind::Closure(did, substs)
+            | AggregateKind::CoroutineClosure(did, substs)
+            | AggregateKind::Coroutine(did, substs) => {
                 (AggregateTy::Def(did, substs), FIRST_VARIANT)
             }
             AggregateKind::Adt(did, variant_index, substs, _, None) => {
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 67668a216de..e77553a03d6 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -317,6 +317,8 @@ impl<'tcx> Inliner<'tcx> {
             | InstanceDef::ReifyShim(_)
             | InstanceDef::FnPtrShim(..)
             | InstanceDef::ClosureOnceShim { .. }
+            | InstanceDef::ConstructCoroutineInClosureShim { .. }
+            | InstanceDef::CoroutineKindShim { .. }
             | InstanceDef::DropGlue(..)
             | InstanceDef::CloneShim(..)
             | InstanceDef::ThreadLocalShim(..)
diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs
index d30e0bad813..5b03bc361dd 100644
--- a/compiler/rustc_mir_transform/src/inline/cycle.rs
+++ b/compiler/rustc_mir_transform/src/inline/cycle.rs
@@ -87,6 +87,8 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
                 | InstanceDef::ReifyShim(_)
                 | InstanceDef::FnPtrShim(..)
                 | InstanceDef::ClosureOnceShim { .. }
+                | InstanceDef::ConstructCoroutineInClosureShim { .. }
+                | InstanceDef::CoroutineKindShim { .. }
                 | InstanceDef::ThreadLocalShim { .. }
                 | InstanceDef::CloneShim(..) => {}
 
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 69f93fa3a0e..031515ea958 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -307,6 +307,10 @@ fn mir_const(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
             &Lint(check_packed_ref::CheckPackedRef),
             &Lint(check_const_item_mutation::CheckConstItemMutation),
             &Lint(function_item_references::FunctionItemReferences),
+            // If this is an async closure's output coroutine, generate
+            // by-move and by-mut bodies if needed. We do this first so
+            // they can be optimized in lockstep with their parent bodies.
+            &coroutine::ByMoveBody,
             // What we need to do constant evaluation.
             &simplify::SimplifyCfg::Initial,
             &rustc_peek::SanityCheck, // Just a lint
diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs
index 211a4057ff0..77478cc741d 100644
--- a/compiler/rustc_mir_transform/src/pass_manager.rs
+++ b/compiler/rustc_mir_transform/src/pass_manager.rs
@@ -181,6 +181,15 @@ fn run_passes_inner<'tcx>(
 
         body.pass_count = 1;
     }
+
+    if let Some(coroutine) = body.coroutine.as_mut() {
+        if let Some(by_move_body) = coroutine.by_move_body.as_mut() {
+            run_passes_inner(tcx, by_move_body, passes, phase_change, validate_each);
+        }
+        if let Some(by_mut_body) = coroutine.by_mut_body.as_mut() {
+            run_passes_inner(tcx, by_mut_body, passes, phase_change, validate_each);
+        }
+    }
 }
 
 pub fn validate_body<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when: String) {
diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs
index 34d57a45301..9a94cae3382 100644
--- a/compiler/rustc_mir_transform/src/remove_zsts.rs
+++ b/compiler/rustc_mir_transform/src/remove_zsts.rs
@@ -46,6 +46,7 @@ fn maybe_zst(ty: Ty<'_>) -> bool {
         ty::Adt(..)
         | ty::Array(..)
         | ty::Closure(..)
+        | ty::CoroutineClosure(..)
         | ty::Tuple(..)
         | ty::Alias(ty::Opaque, ..) => true,
         // definitely ZST
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index 89414ce940e..7b6de3a5439 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -3,8 +3,8 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_middle::mir::*;
 use rustc_middle::query::Providers;
-use rustc_middle::ty::GenericArgs;
 use rustc_middle::ty::{self, CoroutineArgs, EarlyBinder, Ty, TyCtxt};
+use rustc_middle::ty::{GenericArgs, CAPTURE_STRUCT_LOCAL};
 use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT};
 
 use rustc_index::{Idx, IndexVec};
@@ -66,11 +66,76 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
             build_call_shim(tcx, instance, Some(Adjustment::RefMut), CallKind::Direct(call_mut))
         }
 
+        ty::InstanceDef::ConstructCoroutineInClosureShim {
+            coroutine_closure_def_id,
+            target_kind,
+        } => match target_kind {
+            ty::ClosureKind::Fn => unreachable!("shouldn't be building shim for Fn"),
+            ty::ClosureKind::FnMut => {
+                // No need to optimize the body, it has already been optimized
+                // since we steal it from the `AsyncFn::call` body and just fix
+                // the return type.
+                return build_construct_coroutine_by_mut_shim(tcx, coroutine_closure_def_id);
+            }
+            ty::ClosureKind::FnOnce => {
+                build_construct_coroutine_by_move_shim(tcx, coroutine_closure_def_id)
+            }
+        },
+
+        ty::InstanceDef::CoroutineKindShim { coroutine_def_id, target_kind } => match target_kind {
+            ty::ClosureKind::Fn => unreachable!(),
+            ty::ClosureKind::FnMut => {
+                return tcx
+                    .optimized_mir(coroutine_def_id)
+                    .coroutine_by_mut_body()
+                    .unwrap()
+                    .clone();
+            }
+            ty::ClosureKind::FnOnce => {
+                return tcx
+                    .optimized_mir(coroutine_def_id)
+                    .coroutine_by_move_body()
+                    .unwrap()
+                    .clone();
+            }
+        },
+
         ty::InstanceDef::DropGlue(def_id, ty) => {
             // FIXME(#91576): Drop shims for coroutines aren't subject to the MIR passes at the end
             // of this function. Is this intentional?
             if let Some(ty::Coroutine(coroutine_def_id, args)) = ty.map(Ty::kind) {
-                let body = tcx.optimized_mir(*coroutine_def_id).coroutine_drop().unwrap();
+                let coroutine_body = tcx.optimized_mir(*coroutine_def_id);
+
+                let ty::Coroutine(_, id_args) = *tcx.type_of(coroutine_def_id).skip_binder().kind()
+                else {
+                    bug!()
+                };
+
+                // If this is a regular coroutine, grab its drop shim. If this is a coroutine
+                // that comes from a coroutine-closure, and the kind ty differs from the "maximum"
+                // kind that it supports, then grab the appropriate drop shim. This ensures that
+                // the future returned by `<[coroutine-closure] as AsyncFnOnce>::call_once` will
+                // drop the coroutine-closure's upvars.
+                let body = if id_args.as_coroutine().kind_ty() == args.as_coroutine().kind_ty() {
+                    coroutine_body.coroutine_drop().unwrap()
+                } else {
+                    match args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap() {
+                        ty::ClosureKind::Fn => {
+                            unreachable!()
+                        }
+                        ty::ClosureKind::FnMut => coroutine_body
+                            .coroutine_by_mut_body()
+                            .unwrap()
+                            .coroutine_drop()
+                            .unwrap(),
+                        ty::ClosureKind::FnOnce => coroutine_body
+                            .coroutine_by_move_body()
+                            .unwrap()
+                            .coroutine_drop()
+                            .unwrap(),
+                    }
+                };
+
                 let mut body = EarlyBinder::bind(body.clone()).instantiate(tcx, args);
                 debug!("make_shim({:?}) = {:?}", instance, body);
 
@@ -981,3 +1046,114 @@ fn build_fn_ptr_addr_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'t
     let source = MirSource::from_instance(ty::InstanceDef::FnPtrAddrShim(def_id, self_ty));
     new_body(source, IndexVec::from_elem_n(start_block, 1), locals, sig.inputs().len(), span)
 }
+
+fn build_construct_coroutine_by_move_shim<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    coroutine_closure_def_id: DefId,
+) -> Body<'tcx> {
+    let self_ty = tcx.type_of(coroutine_closure_def_id).instantiate_identity();
+    let ty::CoroutineClosure(_, args) = *self_ty.kind() else {
+        bug!();
+    };
+
+    let poly_sig = args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| {
+        tcx.mk_fn_sig(
+            [self_ty].into_iter().chain(sig.tupled_inputs_ty.tuple_fields()),
+            sig.to_coroutine_given_kind_and_upvars(
+                tcx,
+                args.as_coroutine_closure().parent_args(),
+                tcx.coroutine_for_closure(coroutine_closure_def_id),
+                ty::ClosureKind::FnOnce,
+                tcx.lifetimes.re_erased,
+                args.as_coroutine_closure().tupled_upvars_ty(),
+                args.as_coroutine_closure().coroutine_captures_by_ref_ty(),
+            ),
+            sig.c_variadic,
+            sig.unsafety,
+            sig.abi,
+        )
+    });
+    let sig = tcx.liberate_late_bound_regions(coroutine_closure_def_id, poly_sig);
+    let ty::Coroutine(coroutine_def_id, coroutine_args) = *sig.output().kind() else {
+        bug!();
+    };
+
+    let span = tcx.def_span(coroutine_closure_def_id);
+    let locals = local_decls_for_sig(&sig, span);
+
+    let mut fields = vec![];
+    for idx in 1..sig.inputs().len() {
+        fields.push(Operand::Move(Local::from_usize(idx + 1).into()));
+    }
+    for (idx, ty) in args.as_coroutine_closure().upvar_tys().iter().enumerate() {
+        fields.push(Operand::Move(tcx.mk_place_field(
+            Local::from_usize(1).into(),
+            FieldIdx::from_usize(idx),
+            ty,
+        )));
+    }
+
+    let source_info = SourceInfo::outermost(span);
+    let rvalue = Rvalue::Aggregate(
+        Box::new(AggregateKind::Coroutine(coroutine_def_id, coroutine_args)),
+        IndexVec::from_raw(fields),
+    );
+    let stmt = Statement {
+        source_info,
+        kind: StatementKind::Assign(Box::new((Place::return_place(), rvalue))),
+    };
+    let statements = vec![stmt];
+    let start_block = BasicBlockData {
+        statements,
+        terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
+        is_cleanup: false,
+    };
+
+    let source = MirSource::from_instance(ty::InstanceDef::ConstructCoroutineInClosureShim {
+        coroutine_closure_def_id,
+        target_kind: ty::ClosureKind::FnOnce,
+    });
+
+    let body =
+        new_body(source, IndexVec::from_elem_n(start_block, 1), locals, sig.inputs().len(), span);
+    dump_mir(tcx, false, "coroutine_closure_by_move", &0, &body, |_, _| Ok(()));
+
+    body
+}
+
+fn build_construct_coroutine_by_mut_shim<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    coroutine_closure_def_id: DefId,
+) -> Body<'tcx> {
+    let mut body = tcx.optimized_mir(coroutine_closure_def_id).clone();
+    let coroutine_closure_ty = tcx.type_of(coroutine_closure_def_id).instantiate_identity();
+    let ty::CoroutineClosure(_, args) = *coroutine_closure_ty.kind() else {
+        bug!();
+    };
+    let args = args.as_coroutine_closure();
+
+    body.local_decls[RETURN_PLACE].ty =
+        tcx.instantiate_bound_regions_with_erased(args.coroutine_closure_sig().map_bound(|sig| {
+            sig.to_coroutine_given_kind_and_upvars(
+                tcx,
+                args.parent_args(),
+                tcx.coroutine_for_closure(coroutine_closure_def_id),
+                ty::ClosureKind::FnMut,
+                tcx.lifetimes.re_erased,
+                args.tupled_upvars_ty(),
+                args.coroutine_captures_by_ref_ty(),
+            )
+        }));
+    body.local_decls[CAPTURE_STRUCT_LOCAL].ty =
+        Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, coroutine_closure_ty);
+
+    body.source = MirSource::from_instance(ty::InstanceDef::ConstructCoroutineInClosureShim {
+        coroutine_closure_def_id,
+        target_kind: ty::ClosureKind::FnMut,
+    });
+
+    body.pass_count = 0;
+    dump_mir(tcx, false, "coroutine_closure_by_mut", &0, &body, |_, _| Ok(()));
+
+    body
+}
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index b86244e5a4b..3376af98653 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -983,6 +983,8 @@ fn visit_instance_use<'tcx>(
         | ty::InstanceDef::VTableShim(..)
         | ty::InstanceDef::ReifyShim(..)
         | ty::InstanceDef::ClosureOnceShim { .. }
+        | ty::InstanceDef::ConstructCoroutineInClosureShim { .. }
+        | ty::InstanceDef::CoroutineKindShim { .. }
         | ty::InstanceDef::Item(..)
         | ty::InstanceDef::FnPtrShim(..)
         | ty::InstanceDef::CloneShim(..)
diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs
index 7ff182381b8..5cfebcaa5a5 100644
--- a/compiler/rustc_monomorphize/src/partitioning.rs
+++ b/compiler/rustc_monomorphize/src/partitioning.rs
@@ -156,7 +156,7 @@ where
         placed
     };
 
-    // Merge until we have at most `max_cgu_count` codegen units.
+    // Merge until we don't exceed the max CGU count.
     // `merge_codegen_units` is responsible for updating the CGU size
     // estimates.
     {
@@ -620,6 +620,8 @@ fn characteristic_def_id_of_mono_item<'tcx>(
                 | ty::InstanceDef::ReifyShim(..)
                 | ty::InstanceDef::FnPtrShim(..)
                 | ty::InstanceDef::ClosureOnceShim { .. }
+                | ty::InstanceDef::ConstructCoroutineInClosureShim { .. }
+                | ty::InstanceDef::CoroutineKindShim { .. }
                 | ty::InstanceDef::Intrinsic(..)
                 | ty::InstanceDef::DropGlue(..)
                 | ty::InstanceDef::Virtual(..)
@@ -783,6 +785,8 @@ fn mono_item_visibility<'tcx>(
         | InstanceDef::Virtual(..)
         | InstanceDef::Intrinsic(..)
         | InstanceDef::ClosureOnceShim { .. }
+        | InstanceDef::ConstructCoroutineInClosureShim { .. }
+        | InstanceDef::CoroutineKindShim { .. }
         | InstanceDef::DropGlue(..)
         | InstanceDef::CloneShim(..)
         | InstanceDef::FnPtrAddrShim(..) => return Visibility::Hidden,
diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
index db1aee11903..42edbeaa622 100644
--- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs
+++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
@@ -332,7 +332,8 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
             | ty::FnDef(_, _)
             | ty::FnPtr(_)
             | ty::Dynamic(_, _, _)
-            | ty::Closure(_, _)
+            | ty::Closure(..)
+            | ty::CoroutineClosure(..)
             | ty::Coroutine(_, _)
             | ty::CoroutineWitness(..)
             | ty::Never
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index d41cc724408..648ef9d51de 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -323,9 +323,6 @@ passes_ffi_const_invalid_target =
 passes_ffi_pure_invalid_target =
     `#[ffi_pure]` may only be used on foreign functions
 
-passes_ffi_returns_twice_invalid_target =
-    `#[ffi_returns_twice]` may only be used on foreign functions
-
 passes_has_incoherent_inherent_impl =
     `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits.
     .label = only adts, extern types and traits are supported
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 0f0027db01d..e652c79d851 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -192,7 +192,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 }
                 sym::ffi_pure => self.check_ffi_pure(attr.span, attrs, target),
                 sym::ffi_const => self.check_ffi_const(attr.span, target),
-                sym::ffi_returns_twice => self.check_ffi_returns_twice(attr.span, target),
                 sym::rustc_const_unstable
                 | sym::rustc_const_stable
                 | sym::unstable
@@ -1309,15 +1308,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         }
     }
 
-    fn check_ffi_returns_twice(&self, attr_span: Span, target: Target) -> bool {
-        if target == Target::ForeignFn {
-            true
-        } else {
-            self.dcx().emit_err(errors::FfiReturnsTwiceInvalidTarget { attr_span });
-            false
-        }
-    }
-
     /// Warns against some misuses of `#[must_use]`
     fn check_must_use(&self, hir_id: HirId, attr: &Attribute, target: Target) -> bool {
         if !matches!(
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index d19987cb33c..e11102c459e 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -4,6 +4,7 @@
 // is dead.
 
 use hir::def_id::{LocalDefIdMap, LocalDefIdSet};
+use hir::ItemKind;
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::MultiSpan;
 use rustc_hir as hir;
@@ -14,7 +15,7 @@ use rustc_hir::{Node, PatKind, TyKind};
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::middle::privacy::Level;
 use rustc_middle::query::Providers;
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, TyCtxt, Visibility};
 use rustc_session::lint;
 use rustc_session::lint::builtin::DEAD_CODE;
 use rustc_span::symbol::{sym, Symbol};
@@ -381,9 +382,46 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
                     intravisit::walk_item(self, item)
                 }
                 hir::ItemKind::ForeignMod { .. } => {}
+                hir::ItemKind::Trait(..) => {
+                    for impl_def_id in self.tcx.all_impls(item.owner_id.to_def_id()) {
+                        if let Some(local_def_id) = impl_def_id.as_local()
+                            && let ItemKind::Impl(impl_ref) =
+                                self.tcx.hir().expect_item(local_def_id).kind
+                        {
+                            // skip items
+                            // mark dependent traits live
+                            intravisit::walk_generics(self, impl_ref.generics);
+                            // mark dependent parameters live
+                            intravisit::walk_path(self, impl_ref.of_trait.unwrap().path);
+                        }
+                    }
+
+                    intravisit::walk_item(self, item)
+                }
                 _ => intravisit::walk_item(self, item),
             },
             Node::TraitItem(trait_item) => {
+                // mark corresponing ImplTerm live
+                let trait_item_id = trait_item.owner_id.to_def_id();
+                if let Some(trait_id) = self.tcx.trait_of_item(trait_item_id) {
+                    // mark the trait live
+                    self.check_def_id(trait_id);
+
+                    for impl_id in self.tcx.all_impls(trait_id) {
+                        if let Some(local_impl_id) = impl_id.as_local()
+                            && let ItemKind::Impl(impl_ref) =
+                                self.tcx.hir().expect_item(local_impl_id).kind
+                        {
+                            // mark self_ty live
+                            intravisit::walk_ty(self, impl_ref.self_ty);
+                            if let Some(&impl_item_id) =
+                                self.tcx.impl_item_implementor_ids(impl_id).get(&trait_item_id)
+                            {
+                                self.check_def_id(impl_item_id);
+                            }
+                        }
+                    }
+                }
                 intravisit::walk_trait_item(self, trait_item);
             }
             Node::ImplItem(impl_item) => {
@@ -636,10 +674,6 @@ fn check_item<'tcx>(
             }
         }
         DefKind::Impl { of_trait } => {
-            if of_trait {
-                worklist.push((id.owner_id.def_id, ComesFromAllowExpect::No));
-            }
-
             // get DefIds from another query
             let local_def_ids = tcx
                 .associated_item_def_ids(id.owner_id)
@@ -648,7 +682,11 @@ fn check_item<'tcx>(
 
             // And we access the Map here to get HirId from LocalDefId
             for id in local_def_ids {
-                if of_trait {
+                // for impl trait blocks, mark associate functions live if the trait is public
+                if of_trait
+                    && (!matches!(tcx.def_kind(id), DefKind::AssocFn)
+                        || tcx.local_visibility(id) == Visibility::Public)
+                {
                     worklist.push((id, ComesFromAllowExpect::No));
                 } else if let Some(comes_from_allow) = has_allow_dead_code_or_lang_attr(tcx, id) {
                     worklist.push((id, comes_from_allow));
@@ -679,7 +717,7 @@ fn check_trait_item(
     use hir::TraitItemKind::{Const, Fn};
     if matches!(tcx.def_kind(id.owner_id), DefKind::AssocConst | DefKind::AssocFn) {
         let trait_item = tcx.hir().trait_item(id);
-        if matches!(trait_item.kind, Const(_, Some(_)) | Fn(_, hir::TraitFn::Provided(_)))
+        if matches!(trait_item.kind, Const(_, Some(_)) | Fn(..))
             && let Some(comes_from_allow) =
                 has_allow_dead_code_or_lang_attr(tcx, trait_item.owner_id.def_id)
         {
@@ -948,7 +986,8 @@ impl<'tcx> DeadVisitor<'tcx> {
             | DefKind::TyAlias
             | DefKind::Enum
             | DefKind::Union
-            | DefKind::ForeignTy => self.warn_dead_code(def_id, "used"),
+            | DefKind::ForeignTy
+            | DefKind::Trait => self.warn_dead_code(def_id, "used"),
             DefKind::Struct => self.warn_dead_code(def_id, "constructed"),
             DefKind::Variant | DefKind::Field => bug!("should be handled specially"),
             _ => {}
@@ -973,18 +1012,33 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
     let module_items = tcx.hir_module_items(module);
 
     for item in module_items.items() {
-        if let hir::ItemKind::Impl(impl_item) = tcx.hir().item(item).kind {
-            let mut dead_items = Vec::new();
-            for item in impl_item.items {
-                let def_id = item.id.owner_id.def_id;
-                if !visitor.is_live_code(def_id) {
-                    let name = tcx.item_name(def_id.to_def_id());
-                    let level = visitor.def_lint_level(def_id);
+        let def_kind = tcx.def_kind(item.owner_id);
 
-                    dead_items.push(DeadItem { def_id, name, level })
+        let mut dead_codes = Vec::new();
+        // if we have diagnosed the trait, do not diagnose unused methods
+        if matches!(def_kind, DefKind::Impl { .. })
+            || (def_kind == DefKind::Trait && live_symbols.contains(&item.owner_id.def_id))
+        {
+            for &def_id in tcx.associated_item_def_ids(item.owner_id.def_id) {
+                // We have diagnosed unused methods in traits
+                if matches!(def_kind, DefKind::Impl { of_trait: true })
+                    && tcx.def_kind(def_id) == DefKind::AssocFn
+                    || def_kind == DefKind::Trait && tcx.def_kind(def_id) != DefKind::AssocFn
+                {
+                    continue;
+                }
+
+                if let Some(local_def_id) = def_id.as_local()
+                    && !visitor.is_live_code(local_def_id)
+                {
+                    let name = tcx.item_name(def_id);
+                    let level = visitor.def_lint_level(local_def_id);
+                    dead_codes.push(DeadItem { def_id: local_def_id, name, level });
                 }
             }
-            visitor.warn_multiple(item.owner_id.def_id, "used", dead_items, ReportOn::NamedField);
+        }
+        if !dead_codes.is_empty() {
+            visitor.warn_multiple(item.owner_id.def_id, "used", dead_codes, ReportOn::NamedField);
         }
 
         if !live_symbols.contains(&item.owner_id.def_id) {
@@ -997,7 +1051,6 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
             continue;
         }
 
-        let def_kind = tcx.def_kind(item.owner_id);
         if let DefKind::Struct | DefKind::Union | DefKind::Enum = def_kind {
             let adt = tcx.adt_def(item.owner_id);
             let mut dead_variants = Vec::new();
@@ -1044,8 +1097,6 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
     for foreign_item in module_items.foreign_items() {
         visitor.check_definition(foreign_item.owner_id.def_id);
     }
-
-    // We do not warn trait items.
 }
 
 pub(crate) fn provide(providers: &mut Providers) {
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 77bfe57e370..61c953bcb59 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -390,13 +390,6 @@ pub struct FfiConstInvalidTarget {
     pub attr_span: Span,
 }
 
-#[derive(Diagnostic)]
-#[diag(passes_ffi_returns_twice_invalid_target, code = E0724)]
-pub struct FfiReturnsTwiceInvalidTarget {
-    #[primary_span]
-    pub attr_span: Span,
-}
-
 #[derive(LintDiagnostic)]
 #[diag(passes_must_use_async)]
 pub struct MustUseAsync {
@@ -1739,7 +1732,7 @@ pub struct UnusedVariableTryPrefix {
 
 #[derive(Subdiagnostic)]
 pub enum UnusedVariableSugg {
-    #[multipart_suggestion(passes_suggestion, applicability = "machine-applicable")]
+    #[multipart_suggestion(passes_suggestion, applicability = "maybe-incorrect")]
     TryPrefixSugg {
         #[suggestion_part(code = "_{name}")]
         spans: Vec<Span>,
@@ -1778,7 +1771,7 @@ pub struct UnusedVarTryIgnore {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(passes_suggestion, applicability = "machine-applicable")]
+#[multipart_suggestion(passes_suggestion, applicability = "maybe-incorrect")]
 pub struct UnusedVarTryIgnoreSugg {
     #[suggestion_part(code = "{name}: _")]
     pub shorthands: Vec<Span>,
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 99f8186d554..f7c382bcd7a 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -719,6 +719,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                 ty::ClosureKind::FnMut => {}
                 ty::ClosureKind::FnOnce => return succ,
             },
+            ty::CoroutineClosure(_def_id, args) => match args.as_coroutine_closure().kind() {
+                ty::ClosureKind::Fn => {}
+                ty::ClosureKind::FnMut => {}
+                ty::ClosureKind::FnOnce => return succ,
+            },
             ty::Coroutine(..) => return succ,
             _ => {
                 span_bug!(
diff --git a/compiler/rustc_pattern_analysis/src/errors.rs b/compiler/rustc_pattern_analysis/src/errors.rs
index 88770b0c43b..bdb6cf19eac 100644
--- a/compiler/rustc_pattern_analysis/src/errors.rs
+++ b/compiler/rustc_pattern_analysis/src/errors.rs
@@ -23,7 +23,10 @@ impl<'tcx> Uncovered<'tcx> {
         span: Span,
         cx: &RustcMatchCheckCtxt<'p, 'tcx>,
         witnesses: Vec<WitnessPat<'p, 'tcx>>,
-    ) -> Self {
+    ) -> Self
+    where
+        'tcx: 'p,
+    {
         let witness_1 = cx.hoist_witness_pat(witnesses.get(0).unwrap());
         Self {
             span,
diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs
index 8e16d4d7bf4..1a151e72488 100644
--- a/compiler/rustc_pattern_analysis/src/lib.rs
+++ b/compiler/rustc_pattern_analysis/src/lib.rs
@@ -119,7 +119,7 @@ pub trait TypeCx: Sized + fmt::Debug {
     /// `DeconstructedPat`. Only invoqued when `pat.ctor()` is `Struct | Variant(_) | UnionField`.
     fn write_variant_name(
         f: &mut fmt::Formatter<'_>,
-        pat: &crate::pat::DeconstructedPat<'_, Self>,
+        pat: &crate::pat::DeconstructedPat<Self>,
     ) -> fmt::Result;
 
     /// Raise a bug.
@@ -130,9 +130,9 @@ pub trait TypeCx: Sized + fmt::Debug {
     /// The default implementation does nothing.
     fn lint_overlapping_range_endpoints(
         &self,
-        _pat: &DeconstructedPat<'_, Self>,
+        _pat: &DeconstructedPat<Self>,
         _overlaps_on: IntRange,
-        _overlaps_with: &[&DeconstructedPat<'_, Self>],
+        _overlaps_with: &[&DeconstructedPat<Self>],
     ) {
     }
 }
@@ -140,7 +140,7 @@ pub trait TypeCx: Sized + fmt::Debug {
 /// The arm of a match expression.
 #[derive(Debug)]
 pub struct MatchArm<'p, Cx: TypeCx> {
-    pub pat: &'p DeconstructedPat<'p, Cx>,
+    pub pat: &'p DeconstructedPat<Cx>,
     pub has_guard: bool,
     pub arm_data: Cx::ArmData,
 }
diff --git a/compiler/rustc_pattern_analysis/src/pat.rs b/compiler/rustc_pattern_analysis/src/pat.rs
index d419ee46a8e..9bde23c7bf1 100644
--- a/compiler/rustc_pattern_analysis/src/pat.rs
+++ b/compiler/rustc_pattern_analysis/src/pat.rs
@@ -6,7 +6,7 @@ use std::fmt;
 use smallvec::{smallvec, SmallVec};
 
 use crate::constructor::{Constructor, Slice, SliceKind};
-use crate::{Captures, TypeCx};
+use crate::TypeCx;
 
 use self::Constructor::*;
 
@@ -21,9 +21,9 @@ use self::Constructor::*;
 /// This happens if a private or `non_exhaustive` field is uninhabited, because the code mustn't
 /// observe that it is uninhabited. In that case that field is not included in `fields`. Care must
 /// be taken when converting to/from `thir::Pat`.
-pub struct DeconstructedPat<'p, Cx: TypeCx> {
+pub struct DeconstructedPat<Cx: TypeCx> {
     ctor: Constructor<Cx>,
-    fields: &'p [DeconstructedPat<'p, Cx>],
+    fields: Vec<DeconstructedPat<Cx>>,
     ty: Cx::Ty,
     /// Extra data to store in a pattern. `None` if the pattern is a wildcard that does not
     /// correspond to a user-supplied pattern.
@@ -32,14 +32,20 @@ pub struct DeconstructedPat<'p, Cx: TypeCx> {
     useful: Cell<bool>,
 }
 
-impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> {
+impl<Cx: TypeCx> DeconstructedPat<Cx> {
     pub fn wildcard(ty: Cx::Ty) -> Self {
-        DeconstructedPat { ctor: Wildcard, fields: &[], ty, data: None, useful: Cell::new(false) }
+        DeconstructedPat {
+            ctor: Wildcard,
+            fields: Vec::new(),
+            ty,
+            data: None,
+            useful: Cell::new(false),
+        }
     }
 
     pub fn new(
         ctor: Constructor<Cx>,
-        fields: &'p [DeconstructedPat<'p, Cx>],
+        fields: Vec<DeconstructedPat<Cx>>,
         ty: Cx::Ty,
         data: Cx::PatData,
     ) -> Self {
@@ -62,17 +68,17 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> {
         self.data.as_ref()
     }
 
-    pub fn iter_fields(&self) -> impl Iterator<Item = &'p DeconstructedPat<'p, Cx>> + Captures<'_> {
+    pub fn iter_fields<'a>(&'a self) -> impl Iterator<Item = &'a DeconstructedPat<Cx>> {
         self.fields.iter()
     }
 
     /// Specialize this pattern with a constructor.
     /// `other_ctor` can be different from `self.ctor`, but must be covered by it.
-    pub(crate) fn specialize(
-        &self,
+    pub(crate) fn specialize<'a>(
+        &'a self,
         other_ctor: &Constructor<Cx>,
         ctor_arity: usize,
-    ) -> SmallVec<[PatOrWild<'p, Cx>; 2]> {
+    ) -> SmallVec<[PatOrWild<'a, Cx>; 2]> {
         let wildcard_sub_tys = || (0..ctor_arity).map(|_| PatOrWild::Wild).collect();
         match (&self.ctor, other_ctor) {
             // Return a wildcard for each field of `other_ctor`.
@@ -139,7 +145,7 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> {
 }
 
 /// This is best effort and not good enough for a `Display` impl.
-impl<'p, Cx: TypeCx> fmt::Debug for DeconstructedPat<'p, Cx> {
+impl<Cx: TypeCx> fmt::Debug for DeconstructedPat<Cx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let pat = self;
         let mut first = true;
@@ -221,7 +227,7 @@ pub(crate) enum PatOrWild<'p, Cx: TypeCx> {
     /// A non-user-provided wildcard, created during specialization.
     Wild,
     /// A user-provided pattern.
-    Pat(&'p DeconstructedPat<'p, Cx>),
+    Pat(&'p DeconstructedPat<Cx>),
 }
 
 impl<'p, Cx: TypeCx> Clone for PatOrWild<'p, Cx> {
@@ -236,7 +242,7 @@ impl<'p, Cx: TypeCx> Clone for PatOrWild<'p, Cx> {
 impl<'p, Cx: TypeCx> Copy for PatOrWild<'p, Cx> {}
 
 impl<'p, Cx: TypeCx> PatOrWild<'p, Cx> {
-    pub(crate) fn as_pat(&self) -> Option<&'p DeconstructedPat<'p, Cx>> {
+    pub(crate) fn as_pat(&self) -> Option<&'p DeconstructedPat<Cx>> {
         match self {
             PatOrWild::Wild => None,
             PatOrWild::Pat(pat) => Some(pat),
diff --git a/compiler/rustc_pattern_analysis/src/pat_column.rs b/compiler/rustc_pattern_analysis/src/pat_column.rs
index 0339818d61d..ce14fdc364f 100644
--- a/compiler/rustc_pattern_analysis/src/pat_column.rs
+++ b/compiler/rustc_pattern_analysis/src/pat_column.rs
@@ -13,7 +13,7 @@ use crate::{Captures, MatchArm, TypeCx};
 #[derive(Debug)]
 pub struct PatternColumn<'p, Cx: TypeCx> {
     /// This must not contain an or-pattern. `expand_and_push` takes care to expand them.
-    patterns: Vec<&'p DeconstructedPat<'p, Cx>>,
+    patterns: Vec<&'p DeconstructedPat<Cx>>,
 }
 
 impl<'p, Cx: TypeCx> PatternColumn<'p, Cx> {
@@ -41,7 +41,7 @@ impl<'p, Cx: TypeCx> PatternColumn<'p, Cx> {
     pub fn head_ty(&self) -> Option<&Cx::Ty> {
         self.patterns.first().map(|pat| pat.ty())
     }
-    pub fn iter<'a>(&'a self) -> impl Iterator<Item = &'p DeconstructedPat<'p, Cx>> + Captures<'a> {
+    pub fn iter<'a>(&'a self) -> impl Iterator<Item = &'p DeconstructedPat<Cx>> + Captures<'a> {
         self.patterns.iter().copied()
     }
 
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index c02a24048f9..a8fe0cb6a1d 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -1,8 +1,7 @@
-use smallvec::SmallVec;
 use std::fmt;
 use std::iter::once;
 
-use rustc_arena::{DroplessArena, TypedArena};
+use rustc_arena::DroplessArena;
 use rustc_hir::def_id::DefId;
 use rustc_hir::HirId;
 use rustc_index::{Idx, IndexVec};
@@ -27,8 +26,7 @@ use crate::constructor::Constructor::*;
 pub type Constructor<'p, 'tcx> = crate::constructor::Constructor<RustcMatchCheckCtxt<'p, 'tcx>>;
 pub type ConstructorSet<'p, 'tcx> =
     crate::constructor::ConstructorSet<RustcMatchCheckCtxt<'p, 'tcx>>;
-pub type DeconstructedPat<'p, 'tcx> =
-    crate::pat::DeconstructedPat<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
+pub type DeconstructedPat<'p, 'tcx> = crate::pat::DeconstructedPat<RustcMatchCheckCtxt<'p, 'tcx>>;
 pub type MatchArm<'p, 'tcx> = crate::MatchArm<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
 pub type Usefulness<'p, 'tcx> = crate::usefulness::Usefulness<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
 pub type UsefulnessReport<'p, 'tcx> =
@@ -64,7 +62,7 @@ impl<'tcx> RevealedTy<'tcx> {
 }
 
 #[derive(Clone)]
-pub struct RustcMatchCheckCtxt<'p, 'tcx> {
+pub struct RustcMatchCheckCtxt<'p, 'tcx: 'p> {
     pub tcx: TyCtxt<'tcx>,
     pub typeck_results: &'tcx ty::TypeckResults<'tcx>,
     /// The module in which the match occurs. This is necessary for
@@ -74,8 +72,6 @@ pub struct RustcMatchCheckCtxt<'p, 'tcx> {
     /// outside its module and should not be matchable with an empty match statement.
     pub module: DefId,
     pub param_env: ty::ParamEnv<'tcx>,
-    /// To allocate lowered patterns
-    pub pattern_arena: &'p TypedArena<DeconstructedPat<'p, 'tcx>>,
     /// To allocate the result of `self.ctor_sub_tys()`
     pub dropless_arena: &'p DroplessArena,
     /// Lint level at the match.
@@ -91,13 +87,13 @@ pub struct RustcMatchCheckCtxt<'p, 'tcx> {
     pub known_valid_scrutinee: bool,
 }
 
-impl<'p, 'tcx> fmt::Debug for RustcMatchCheckCtxt<'p, 'tcx> {
+impl<'p, 'tcx: 'p> fmt::Debug for RustcMatchCheckCtxt<'p, 'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("RustcMatchCheckCtxt").finish()
     }
 }
 
-impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
+impl<'p, 'tcx: 'p> RustcMatchCheckCtxt<'p, 'tcx> {
     /// Type inference occasionally gives us opaque types in places where corresponding patterns
     /// have more specific types. To avoid inconsistencies as well as detect opaque uninhabited
     /// types, we use the corresponding concrete type if possible.
@@ -423,7 +419,8 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
             | ty::FnDef(_, _)
             | ty::FnPtr(_)
             | ty::Dynamic(_, _, _)
-            | ty::Closure(_, _)
+            | ty::Closure(..)
+            | ty::CoroutineClosure(..)
             | ty::Coroutine(_, _)
             | ty::Alias(_, _)
             | ty::Param(_)
@@ -458,21 +455,20 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
     /// Note: the input patterns must have been lowered through
     /// `rustc_mir_build::thir::pattern::check_match::MatchVisitor::lower_pattern`.
     pub fn lower_pat(&self, pat: &'p Pat<'tcx>) -> DeconstructedPat<'p, 'tcx> {
-        let singleton = |pat| std::slice::from_ref(self.pattern_arena.alloc(pat));
         let cx = self;
         let ty = cx.reveal_opaque_ty(pat.ty);
         let ctor;
-        let fields: &[_];
+        let mut fields: Vec<_>;
         match &pat.kind {
             PatKind::AscribeUserType { subpattern, .. }
             | PatKind::InlineConstant { subpattern, .. } => return self.lower_pat(subpattern),
             PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat),
             PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
                 ctor = Wildcard;
-                fields = &[];
+                fields = vec![];
             }
             PatKind::Deref { subpattern } => {
-                fields = singleton(self.lower_pat(subpattern));
+                fields = vec![self.lower_pat(subpattern)];
                 ctor = match ty.kind() {
                     // This is a box pattern.
                     ty::Adt(adt, ..) if adt.is_box() => Struct,
@@ -484,15 +480,14 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
                 match ty.kind() {
                     ty::Tuple(fs) => {
                         ctor = Struct;
-                        let mut wilds: SmallVec<[_; 2]> = fs
+                        fields = fs
                             .iter()
                             .map(|ty| cx.reveal_opaque_ty(ty))
                             .map(|ty| DeconstructedPat::wildcard(ty))
                             .collect();
                         for pat in subpatterns {
-                            wilds[pat.field.index()] = self.lower_pat(&pat.pattern);
+                            fields[pat.field.index()] = self.lower_pat(&pat.pattern);
                         }
-                        fields = cx.pattern_arena.alloc_from_iter(wilds);
                     }
                     ty::Adt(adt, args) if adt.is_box() => {
                         // The only legal patterns of type `Box` (outside `std`) are `_` and box
@@ -514,7 +509,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
                             DeconstructedPat::wildcard(self.reveal_opaque_ty(args.type_at(0)))
                         };
                         ctor = Struct;
-                        fields = singleton(pat);
+                        fields = vec![pat];
                     }
                     ty::Adt(adt, _) => {
                         ctor = match pat.kind {
@@ -534,14 +529,12 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
                                 ty
                             },
                         );
-                        let mut wilds: SmallVec<[_; 2]> =
-                            tys.map(|ty| DeconstructedPat::wildcard(ty)).collect();
+                        fields = tys.map(|ty| DeconstructedPat::wildcard(ty)).collect();
                         for pat in subpatterns {
                             if let Some(i) = field_id_to_id[pat.field.index()] {
-                                wilds[i] = self.lower_pat(&pat.pattern);
+                                fields[i] = self.lower_pat(&pat.pattern);
                             }
                         }
-                        fields = cx.pattern_arena.alloc_from_iter(wilds);
                     }
                     _ => bug!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, ty),
                 }
@@ -553,7 +546,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
                             Some(b) => Bool(b),
                             None => Opaque(OpaqueId::new()),
                         };
-                        fields = &[];
+                        fields = vec![];
                     }
                     ty::Char | ty::Int(_) | ty::Uint(_) => {
                         ctor = match value.try_eval_bits(cx.tcx, cx.param_env) {
@@ -569,7 +562,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
                             }
                             None => Opaque(OpaqueId::new()),
                         };
-                        fields = &[];
+                        fields = vec![];
                     }
                     ty::Float(ty::FloatTy::F32) => {
                         ctor = match value.try_eval_bits(cx.tcx, cx.param_env) {
@@ -580,7 +573,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
                             }
                             None => Opaque(OpaqueId::new()),
                         };
-                        fields = &[];
+                        fields = vec![];
                     }
                     ty::Float(ty::FloatTy::F64) => {
                         ctor = match value.try_eval_bits(cx.tcx, cx.param_env) {
@@ -591,7 +584,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
                             }
                             None => Opaque(OpaqueId::new()),
                         };
-                        fields = &[];
+                        fields = vec![];
                     }
                     ty::Ref(_, t, _) if t.is_str() => {
                         // We want a `&str` constant to behave like a `Deref` pattern, to be compatible
@@ -602,16 +595,16 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
                         // subfields.
                         // Note: `t` is `str`, not `&str`.
                         let ty = self.reveal_opaque_ty(*t);
-                        let subpattern = DeconstructedPat::new(Str(*value), &[], ty, pat);
+                        let subpattern = DeconstructedPat::new(Str(*value), Vec::new(), ty, pat);
                         ctor = Ref;
-                        fields = singleton(subpattern)
+                        fields = vec![subpattern]
                     }
                     // All constants that can be structurally matched have already been expanded
                     // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are
                     // opaque.
                     _ => {
                         ctor = Opaque(OpaqueId::new());
-                        fields = &[];
+                        fields = vec![];
                     }
                 }
             }
@@ -648,7 +641,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
                     }
                     _ => bug!("invalid type for range pattern: {}", ty.inner()),
                 };
-                fields = &[];
+                fields = vec![];
             }
             PatKind::Array { prefix, slice, suffix } | PatKind::Slice { prefix, slice, suffix } => {
                 let array_len = match ty.kind() {
@@ -664,26 +657,23 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
                     SliceKind::FixedLen(prefix.len() + suffix.len())
                 };
                 ctor = Slice(Slice::new(array_len, kind));
-                fields = cx.pattern_arena.alloc_from_iter(
-                    prefix.iter().chain(suffix.iter()).map(|p| self.lower_pat(&*p)),
-                )
+                fields = prefix.iter().chain(suffix.iter()).map(|p| self.lower_pat(&*p)).collect();
             }
             PatKind::Or { .. } => {
                 ctor = Or;
                 let pats = expand_or_pat(pat);
-                fields =
-                    cx.pattern_arena.alloc_from_iter(pats.into_iter().map(|p| self.lower_pat(p)))
+                fields = pats.into_iter().map(|p| self.lower_pat(p)).collect();
             }
             PatKind::Never => {
                 // A never pattern matches all the values of its type (namely none). Moreover it
                 // must be compatible with other constructors, since we can use `!` on a type like
                 // `Result<!, !>` which has other constructors. Hence we lower it as a wildcard.
                 ctor = Wildcard;
-                fields = &[];
+                fields = vec![];
             }
             PatKind::Error(_) => {
                 ctor = Opaque(OpaqueId::new());
-                fields = &[];
+                fields = vec![];
             }
         }
         DeconstructedPat::new(ctor, fields, ty, pat)
@@ -854,7 +844,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
     }
 }
 
-impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
+impl<'p, 'tcx: 'p> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
     type Ty = RevealedTy<'tcx>;
     type Error = ErrorGuaranteed;
     type VariantIdx = VariantIdx;
@@ -888,7 +878,7 @@ impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
 
     fn write_variant_name(
         f: &mut fmt::Formatter<'_>,
-        pat: &crate::pat::DeconstructedPat<'_, Self>,
+        pat: &crate::pat::DeconstructedPat<Self>,
     ) -> fmt::Result {
         if let ty::Adt(adt, _) = pat.ty().kind() {
             if adt.is_box() {
@@ -907,9 +897,9 @@ impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
 
     fn lint_overlapping_range_endpoints(
         &self,
-        pat: &crate::pat::DeconstructedPat<'_, Self>,
+        pat: &crate::pat::DeconstructedPat<Self>,
         overlaps_on: IntRange,
-        overlaps_with: &[&crate::pat::DeconstructedPat<'_, Self>],
+        overlaps_with: &[&crate::pat::DeconstructedPat<Self>],
     ) {
         let overlap_as_pat = self.hoist_pat_range(&overlaps_on, *pat.ty());
         let overlaps: Vec<_> = overlaps_with
diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs
index bbb68b353e4..576005b2c7f 100644
--- a/compiler/rustc_pattern_analysis/src/usefulness.rs
+++ b/compiler/rustc_pattern_analysis/src/usefulness.rs
@@ -767,12 +767,6 @@ impl<'a, Cx: TypeCx> PlaceCtxt<'a, Cx> {
     fn ctor_arity(&self, ctor: &Constructor<Cx>) -> usize {
         self.cx.ctor_arity(ctor, self.ty)
     }
-    fn ctor_sub_tys(
-        &'a self,
-        ctor: &'a Constructor<Cx>,
-    ) -> impl Iterator<Item = Cx::Ty> + ExactSizeIterator + Captures<'a> {
-        self.cx.ctor_sub_tys(ctor, self.ty)
-    }
     fn ctors_for_ty(&self) -> Result<ConstructorSet<Cx>, Cx::Error> {
         self.cx.ctors_for_ty(self.ty)
     }
@@ -828,6 +822,38 @@ impl fmt::Display for ValidityConstraint {
     }
 }
 
+/// Data about a place under investigation.
+struct PlaceInfo<Cx: TypeCx> {
+    /// The type of the place.
+    ty: Cx::Ty,
+    /// Whether the place is known to contain valid data.
+    validity: ValidityConstraint,
+    /// Whether the place is the scrutinee itself or a subplace of it.
+    is_scrutinee: bool,
+}
+
+impl<Cx: TypeCx> PlaceInfo<Cx> {
+    fn specialize<'a>(
+        &'a self,
+        cx: &'a Cx,
+        ctor: &'a Constructor<Cx>,
+    ) -> impl Iterator<Item = Self> + ExactSizeIterator + Captures<'a> {
+        let ctor_sub_tys = cx.ctor_sub_tys(ctor, &self.ty);
+        let ctor_sub_validity = self.validity.specialize(ctor);
+        ctor_sub_tys.map(move |ty| PlaceInfo {
+            ty,
+            validity: ctor_sub_validity,
+            is_scrutinee: false,
+        })
+    }
+}
+
+impl<Cx: TypeCx> Clone for PlaceInfo<Cx> {
+    fn clone(&self) -> Self {
+        Self { ty: self.ty.clone(), validity: self.validity, is_scrutinee: self.is_scrutinee }
+    }
+}
+
 /// Represents a pattern-tuple under investigation.
 // The three lifetimes are:
 // - 'p coming from the input
@@ -848,7 +874,7 @@ impl<'p, Cx: TypeCx> Clone for PatStack<'p, Cx> {
 }
 
 impl<'p, Cx: TypeCx> PatStack<'p, Cx> {
-    fn from_pattern(pat: &'p DeconstructedPat<'p, Cx>) -> Self {
+    fn from_pattern(pat: &'p DeconstructedPat<Cx>) -> Self {
         PatStack { pats: smallvec![PatOrWild::Pat(pat)], relevant: true }
     }
 
@@ -1001,10 +1027,9 @@ struct Matrix<'p, Cx: TypeCx> {
     /// each column must have the same type. Each column corresponds to a place within the
     /// scrutinee.
     rows: Vec<MatrixRow<'p, Cx>>,
-    /// Track the type of each column/place.
-    place_ty: SmallVec<[Cx::Ty; 2]>,
-    /// Track for each column/place whether it contains a known valid value.
-    place_validity: SmallVec<[ValidityConstraint; 2]>,
+    /// Track info about each place. Each place corresponds to a column in `rows`, and their types
+    /// must match.
+    place_info: SmallVec<[PlaceInfo<Cx>; 2]>,
     /// Track whether the virtual wildcard row used to compute exhaustiveness is relevant. See top
     /// of the file for details on relevancy.
     wildcard_row_is_relevant: bool,
@@ -1032,10 +1057,10 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> {
         scrut_ty: Cx::Ty,
         scrut_validity: ValidityConstraint,
     ) -> Self {
+        let place_info = PlaceInfo { ty: scrut_ty, validity: scrut_validity, is_scrutinee: true };
         let mut matrix = Matrix {
             rows: Vec::with_capacity(arms.len()),
-            place_ty: smallvec![scrut_ty],
-            place_validity: smallvec![scrut_validity],
+            place_info: smallvec![place_info],
             wildcard_row_is_relevant: true,
         };
         for (row_id, arm) in arms.iter().enumerate() {
@@ -1051,11 +1076,11 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> {
         matrix
     }
 
-    fn head_ty(&self) -> Option<&Cx::Ty> {
-        self.place_ty.first()
+    fn head_place(&self) -> Option<&PlaceInfo<Cx>> {
+        self.place_info.first()
     }
     fn column_count(&self) -> usize {
-        self.place_ty.len()
+        self.place_info.len()
     }
 
     fn rows(
@@ -1083,18 +1108,13 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> {
         ctor: &Constructor<Cx>,
         ctor_is_relevant: bool,
     ) -> Result<Matrix<'p, Cx>, Cx::Error> {
-        let ctor_sub_tys = pcx.ctor_sub_tys(ctor);
-        let arity = ctor_sub_tys.len();
-        let specialized_place_ty = ctor_sub_tys.chain(self.place_ty[1..].iter().cloned()).collect();
-        let ctor_sub_validity = self.place_validity[0].specialize(ctor);
-        let specialized_place_validity = std::iter::repeat(ctor_sub_validity)
-            .take(arity)
-            .chain(self.place_validity[1..].iter().copied())
-            .collect();
+        let subfield_place_info = self.place_info[0].specialize(pcx.cx, ctor);
+        let arity = subfield_place_info.len();
+        let specialized_place_info =
+            subfield_place_info.chain(self.place_info[1..].iter().cloned()).collect();
         let mut matrix = Matrix {
             rows: Vec::new(),
-            place_ty: specialized_place_ty,
-            place_validity: specialized_place_validity,
+            place_info: specialized_place_info,
             wildcard_row_is_relevant: self.wildcard_row_is_relevant && ctor_is_relevant,
         };
         for (i, row) in self.rows().enumerate() {
@@ -1127,11 +1147,11 @@ impl<'p, Cx: TypeCx> fmt::Debug for Matrix<'p, Cx> {
             .map(|row| row.iter().map(|pat| format!("{pat:?}")).collect())
             .collect();
         pretty_printed_matrix
-            .push(self.place_validity.iter().map(|validity| format!("{validity}")).collect());
+            .push(self.place_info.iter().map(|place| format!("{}", place.validity)).collect());
 
         let column_count = self.column_count();
         assert!(self.rows.iter().all(|row| row.len() == column_count));
-        assert!(self.place_validity.len() == column_count);
+        assert!(self.place_info.len() == column_count);
         let column_widths: Vec<usize> = (0..column_count)
             .map(|col| pretty_printed_matrix.iter().map(|row| row[col].len()).max().unwrap_or(0))
             .collect();
@@ -1432,11 +1452,10 @@ fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>(
 /// - unspecialization, where we lift the results from the previous step into results for this step
 ///     (using `apply_constructor` and by updating `row.useful` for each parent row).
 /// This is all explained at the top of the file.
-#[instrument(level = "debug", skip(mcx, is_top_level), ret)]
+#[instrument(level = "debug", skip(mcx), ret)]
 fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
     mcx: UsefulnessCtxt<'a, Cx>,
     matrix: &mut Matrix<'p, Cx>,
-    is_top_level: bool,
 ) -> Result<WitnessMatrix<Cx>, Cx::Error> {
     debug_assert!(matrix.rows().all(|r| r.len() == matrix.column_count()));
 
@@ -1447,7 +1466,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
         return Ok(WitnessMatrix::empty());
     }
 
-    let Some(ty) = matrix.head_ty().cloned() else {
+    let Some(place) = matrix.head_place() else {
         // The base case: there are no columns in the matrix. We are morally pattern-matching on ().
         // A row is useful iff it has no (unguarded) rows above it.
         let mut useful = true; // Whether the next row is useful.
@@ -1467,18 +1486,17 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
         };
     };
 
-    debug!("ty: {ty:?}");
-    let pcx = &PlaceCtxt { cx: mcx.tycx, ty: &ty };
+    let ty = &place.ty.clone(); // Clone it out so we can mutate `matrix` later.
+    let pcx = &PlaceCtxt { cx: mcx.tycx, ty };
+    debug!("ty: {:?}", pcx.ty);
     let ctors_for_ty = pcx.ctors_for_ty()?;
 
-    // Whether the place/column we are inspecting is known to contain valid data.
-    let place_validity = matrix.place_validity[0];
     // We treat match scrutinees of type `!` or `EmptyEnum` differently.
     let is_toplevel_exception =
-        is_top_level && matches!(ctors_for_ty, ConstructorSet::NoConstructors);
+        place.is_scrutinee && matches!(ctors_for_ty, ConstructorSet::NoConstructors);
     // Whether empty patterns are counted as useful or not. We only warn an empty arm unreachable if
     // it is guaranteed unreachable by the opsem (i.e. if the place is `known_valid`).
-    let empty_arms_are_unreachable = place_validity.is_known_valid()
+    let empty_arms_are_unreachable = place.validity.is_known_valid()
         && (is_toplevel_exception
             || mcx.tycx.is_exhaustive_patterns_feature_on()
             || mcx.tycx.is_min_exhaustive_patterns_feature_on());
@@ -1504,7 +1522,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
 
     // Decide what constructors to report.
     let is_integers = matches!(ctors_for_ty, ConstructorSet::Integers { .. });
-    let always_report_all = is_top_level && !is_integers;
+    let always_report_all = place.is_scrutinee && !is_integers;
     // Whether we should report "Enum::A and Enum::C are missing" or "_ is missing".
     let report_individual_missing_ctors = always_report_all || !all_missing;
     // Which constructors are considered missing. We ensure that `!missing_ctors.is_empty() =>
@@ -1525,7 +1543,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
         let ctor_is_relevant = matches!(ctor, Constructor::Missing) || missing_ctors.is_empty();
         let mut spec_matrix = matrix.specialize_constructor(pcx, &ctor, ctor_is_relevant)?;
         let mut witnesses = ensure_sufficient_stack(|| {
-            compute_exhaustiveness_and_usefulness(mcx, &mut spec_matrix, false)
+            compute_exhaustiveness_and_usefulness(mcx, &mut spec_matrix)
         })?;
 
         // Transform witnesses for `spec_matrix` into witnesses for `matrix`.
@@ -1575,7 +1593,7 @@ pub enum Usefulness<'p, Cx: TypeCx> {
     /// The arm is useful. This additionally carries a set of or-pattern branches that have been
     /// found to be redundant despite the overall arm being useful. Used only in the presence of
     /// or-patterns, otherwise it stays empty.
-    Useful(Vec<&'p DeconstructedPat<'p, Cx>>),
+    Useful(Vec<&'p DeconstructedPat<Cx>>),
     /// The arm is redundant and can be removed without changing the behavior of the match
     /// expression.
     Redundant,
@@ -1600,8 +1618,7 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>(
 ) -> Result<UsefulnessReport<'p, Cx>, Cx::Error> {
     let cx = UsefulnessCtxt { tycx };
     let mut matrix = Matrix::new(arms, scrut_ty, scrut_validity);
-    let non_exhaustiveness_witnesses =
-        compute_exhaustiveness_and_usefulness(cx, &mut matrix, true)?;
+    let non_exhaustiveness_witnesses = compute_exhaustiveness_and_usefulness(cx, &mut matrix)?;
 
     let non_exhaustiveness_witnesses: Vec<_> = non_exhaustiveness_witnesses.single_column();
     let arm_usefulness: Vec<_> = arms
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index a64b06e70d6..a37d8822480 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -182,6 +182,7 @@ where
             | ty::Foreign(def_id)
             | ty::FnDef(def_id, ..)
             | ty::Closure(def_id, ..)
+            | ty::CoroutineClosure(def_id, ..)
             | ty::Coroutine(def_id, ..) => {
                 self.def_id_visitor.visit_def_id(def_id, "type", &ty)?;
                 if V::SHALLOW {
diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl
index 02847a0f5f9..0747685c35c 100644
--- a/compiler/rustc_resolve/messages.ftl
+++ b/compiler/rustc_resolve/messages.ftl
@@ -118,17 +118,27 @@ resolve_forward_declared_generic_param =
     .label = defaulted generic parameters cannot be forward declared
 
 resolve_generic_params_from_outer_item =
-    can't use generic parameters from outer item
-    .label = use of generic parameter from outer item
+    can't use {$is_self ->
+        [true] `Self`
+        *[false] generic parameters
+    } from outer item
+    .label = use of {$is_self ->
+        [true] `Self`
+        *[false] generic parameter
+    } from outer item
     .refer_to_type_directly = refer to the type directly here instead
     .suggestion = try introducing a local generic parameter here
 
+resolve_generic_params_from_outer_item_const = a `const` is a separate item from the item that contains it
+
 resolve_generic_params_from_outer_item_const_param = const parameter from outer item
 
 resolve_generic_params_from_outer_item_self_ty_alias = `Self` type implicitly declared here, by this `impl`
 
 resolve_generic_params_from_outer_item_self_ty_param = can't use `Self` here
 
+resolve_generic_params_from_outer_item_static = a `static` is a separate item from the item that contains it
+
 resolve_generic_params_from_outer_item_ty_param = type parameter from outer item
 
 
@@ -292,6 +302,9 @@ resolve_underscore_lifetime_name_cannot_be_used_here =
 resolve_unexpected_res_change_ty_to_const_param_sugg =
     you might have meant to write a const parameter here
 
+resolve_unexpected_res_use_at_op_in_slice_pat_with_range_sugg =
+    if you meant to collect the rest of the slice in `{$ident}`, use the at operator
+
 resolve_unreachable_label =
     use of unreachable label `{$name}`
     .label = unreachable label `{$name}`
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index f3a6eb65a72..d91a865e38a 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -561,13 +561,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         resolution_error: ResolutionError<'a>,
     ) -> DiagnosticBuilder<'_> {
         match resolution_error {
-            ResolutionError::GenericParamsFromOuterItem(outer_res, has_generic_params) => {
+            ResolutionError::GenericParamsFromOuterItem(outer_res, has_generic_params, def_kind) => {
                 use errs::GenericParamsFromOuterItemLabel as Label;
+                let static_or_const = match def_kind {
+                    DefKind::Static(_) => Some(errs::GenericParamsFromOuterItemStaticOrConst::Static),
+                    DefKind::Const => Some(errs::GenericParamsFromOuterItemStaticOrConst::Const),
+                    _ => None,
+                };
+                let is_self = matches!(outer_res, Res::SelfTyParam { .. } | Res::SelfTyAlias { .. });
                 let mut err = errs::GenericParamsFromOuterItem {
                     span,
                     label: None,
                     refer_to_type_directly: None,
                     sugg: None,
+                    static_or_const,
+                    is_self,
                 };
 
                 let sm = self.tcx.sess.source_map();
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index 655fc9812d7..adc4cd911a7 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -45,6 +45,17 @@ pub(crate) struct GenericParamsFromOuterItem {
     pub(crate) refer_to_type_directly: Option<Span>,
     #[subdiagnostic]
     pub(crate) sugg: Option<GenericParamsFromOuterItemSugg>,
+    #[subdiagnostic]
+    pub(crate) static_or_const: Option<GenericParamsFromOuterItemStaticOrConst>,
+    pub(crate) is_self: bool,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum GenericParamsFromOuterItemStaticOrConst {
+    #[note(resolve_generic_params_from_outer_item_static)]
+    Static,
+    #[note(resolve_generic_params_from_outer_item_const)]
+    Const,
 }
 
 #[derive(Subdiagnostic)]
@@ -800,3 +811,17 @@ pub(crate) struct UnexpectedResChangeTyToConstParamSugg {
     #[applicability]
     pub applicability: Applicability,
 }
+
+#[derive(Subdiagnostic)]
+#[suggestion(
+    resolve_unexpected_res_use_at_op_in_slice_pat_with_range_sugg,
+    code = "{snippet}",
+    applicability = "maybe-incorrect",
+    style = "verbose"
+)]
+pub(crate) struct UnexpectedResUseAtOpInSlicePatWithRangeSugg {
+    #[primary_span]
+    pub span: Span,
+    pub ident: Ident,
+    pub snippet: String,
+}
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 7fb9db16e9c..e47f2bdd4d2 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -10,9 +10,7 @@ use rustc_span::symbol::{kw, Ident};
 use rustc_span::Span;
 
 use crate::errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst};
-use crate::late::{
-    ConstantHasGenerics, HasGenericParams, NoConstantGenericsReason, PathSource, Rib, RibKind,
-};
+use crate::late::{ConstantHasGenerics, NoConstantGenericsReason, PathSource, Rib, RibKind};
 use crate::macros::{sub_namespace_match, MacroRulesScope};
 use crate::BindingKey;
 use crate::{errors, AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize};
@@ -1090,7 +1088,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         | RibKind::ForwardGenericParamBan => {
                             // Nothing to do. Continue.
                         }
-                        RibKind::Item(_) | RibKind::AssocItem => {
+                        RibKind::Item(..) | RibKind::AssocItem => {
                             // This was an attempt to access an upvar inside a
                             // named function item. This is not allowed, so we
                             // report an error.
@@ -1155,7 +1153,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             }
             Res::Def(DefKind::TyParam, _) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => {
                 for rib in ribs {
-                    let has_generic_params: HasGenericParams = match rib.kind {
+                    let (has_generic_params, def_kind) = match rib.kind {
                         RibKind::Normal
                         | RibKind::FnOrCoroutine
                         | RibKind::Module(..)
@@ -1213,7 +1211,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         }
 
                         // This was an attempt to use a type parameter outside its scope.
-                        RibKind::Item(has_generic_params) => has_generic_params,
+                        RibKind::Item(has_generic_params, def_kind) => {
+                            (has_generic_params, def_kind)
+                        }
                         RibKind::ConstParamTy => {
                             if let Some(span) = finalize {
                                 self.report_error(
@@ -1231,7 +1231,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     if let Some(span) = finalize {
                         self.report_error(
                             span,
-                            ResolutionError::GenericParamsFromOuterItem(res, has_generic_params),
+                            ResolutionError::GenericParamsFromOuterItem(
+                                res,
+                                has_generic_params,
+                                def_kind,
+                            ),
                         );
                     }
                     return Res::Err;
@@ -1239,7 +1243,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             }
             Res::Def(DefKind::ConstParam, _) => {
                 for rib in ribs {
-                    let has_generic_params = match rib.kind {
+                    let (has_generic_params, def_kind) = match rib.kind {
                         RibKind::Normal
                         | RibKind::FnOrCoroutine
                         | RibKind::Module(..)
@@ -1276,7 +1280,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                             continue;
                         }
 
-                        RibKind::Item(has_generic_params) => has_generic_params,
+                        RibKind::Item(has_generic_params, def_kind) => {
+                            (has_generic_params, def_kind)
+                        }
                         RibKind::ConstParamTy => {
                             if let Some(span) = finalize {
                                 self.report_error(
@@ -1295,7 +1301,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     if let Some(span) = finalize {
                         self.report_error(
                             span,
-                            ResolutionError::GenericParamsFromOuterItem(res, has_generic_params),
+                            ResolutionError::GenericParamsFromOuterItem(
+                                res,
+                                has_generic_params,
+                                def_kind,
+                            ),
                         );
                     }
                     return Res::Err;
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 1f2803d4368..f0b5311f1e1 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -185,7 +185,7 @@ pub(crate) enum RibKind<'a> {
     FnOrCoroutine,
 
     /// We passed through an item scope. Disallow upvars.
-    Item(HasGenericParams),
+    Item(HasGenericParams, DefKind),
 
     /// We're in a constant item. Can't refer to dynamic stuff.
     ///
@@ -225,7 +225,7 @@ impl RibKind<'_> {
             | RibKind::MacroDefinition(_)
             | RibKind::ConstParamTy
             | RibKind::InlineAsmSym => false,
-            RibKind::AssocItem | RibKind::Item(_) | RibKind::ForwardGenericParamBan => true,
+            RibKind::AssocItem | RibKind::Item(..) | RibKind::ForwardGenericParamBan => true,
         }
     }
 
@@ -869,11 +869,12 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
     }
     fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
         self.resolve_doc_links(&foreign_item.attrs, MaybeExported::Ok(foreign_item.id));
+        let def_kind = self.r.local_def_kind(foreign_item.id);
         match foreign_item.kind {
             ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
                 self.with_generic_param_rib(
                     &generics.params,
-                    RibKind::Item(HasGenericParams::Yes(generics.span)),
+                    RibKind::Item(HasGenericParams::Yes(generics.span), def_kind),
                     LifetimeRibKind::Generics {
                         binder: foreign_item.id,
                         kind: LifetimeBinderKind::Item,
@@ -885,7 +886,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
             ForeignItemKind::Fn(box Fn { ref generics, .. }) => {
                 self.with_generic_param_rib(
                     &generics.params,
-                    RibKind::Item(HasGenericParams::Yes(generics.span)),
+                    RibKind::Item(HasGenericParams::Yes(generics.span), def_kind),
                     LifetimeRibKind::Generics {
                         binder: foreign_item.id,
                         kind: LifetimeBinderKind::Function,
@@ -895,7 +896,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
                 );
             }
             ForeignItemKind::Static(..) => {
-                self.with_static_rib(|this| {
+                self.with_static_rib(def_kind, |this| {
                     visit::walk_foreign_item(this, foreign_item);
                 });
             }
@@ -2266,10 +2267,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
 
     fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) {
         debug!("resolve_adt");
+        let kind = self.r.local_def_kind(item.id);
         self.with_current_self_item(item, |this| {
             this.with_generic_param_rib(
                 &generics.params,
-                RibKind::Item(HasGenericParams::Yes(generics.span)),
+                RibKind::Item(HasGenericParams::Yes(generics.span), kind),
                 LifetimeRibKind::Generics {
                     binder: item.id,
                     kind: LifetimeBinderKind::Item,
@@ -2343,11 +2345,12 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
         let name = item.ident.name;
         debug!("(resolving item) resolving {} ({:?})", name, item.kind);
 
+        let def_kind = self.r.local_def_kind(item.id);
         match item.kind {
             ItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
                 self.with_generic_param_rib(
                     &generics.params,
-                    RibKind::Item(HasGenericParams::Yes(generics.span)),
+                    RibKind::Item(HasGenericParams::Yes(generics.span), def_kind),
                     LifetimeRibKind::Generics {
                         binder: item.id,
                         kind: LifetimeBinderKind::Item,
@@ -2360,7 +2363,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             ItemKind::Fn(box Fn { ref generics, .. }) => {
                 self.with_generic_param_rib(
                     &generics.params,
-                    RibKind::Item(HasGenericParams::Yes(generics.span)),
+                    RibKind::Item(HasGenericParams::Yes(generics.span), def_kind),
                     LifetimeRibKind::Generics {
                         binder: item.id,
                         kind: LifetimeBinderKind::Function,
@@ -2399,7 +2402,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                 // Create a new rib for the trait-wide type parameters.
                 self.with_generic_param_rib(
                     &generics.params,
-                    RibKind::Item(HasGenericParams::Yes(generics.span)),
+                    RibKind::Item(HasGenericParams::Yes(generics.span), def_kind),
                     LifetimeRibKind::Generics {
                         binder: item.id,
                         kind: LifetimeBinderKind::Item,
@@ -2420,7 +2423,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                 // Create a new rib for the trait-wide type parameters.
                 self.with_generic_param_rib(
                     &generics.params,
-                    RibKind::Item(HasGenericParams::Yes(generics.span)),
+                    RibKind::Item(HasGenericParams::Yes(generics.span), def_kind),
                     LifetimeRibKind::Generics {
                         binder: item.id,
                         kind: LifetimeBinderKind::Item,
@@ -2454,7 +2457,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             }
 
             ItemKind::Static(box ast::StaticItem { ref ty, ref expr, .. }) => {
-                self.with_static_rib(|this| {
+                self.with_static_rib(def_kind, |this| {
                     this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
                         this.visit_ty(ty);
                     });
@@ -2469,11 +2472,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             ItemKind::Const(box ast::ConstItem { ref generics, ref ty, ref expr, .. }) => {
                 self.with_generic_param_rib(
                     &generics.params,
-                    RibKind::Item(if self.r.tcx.features().generic_const_items {
-                        HasGenericParams::Yes(generics.span)
-                    } else {
-                        HasGenericParams::No
-                    }),
+                    RibKind::Item(
+                        if self.r.tcx.features().generic_const_items {
+                            HasGenericParams::Yes(generics.span)
+                        } else {
+                            HasGenericParams::No
+                        },
+                        def_kind,
+                    ),
                     LifetimeRibKind::Generics {
                         binder: item.id,
                         kind: LifetimeBinderKind::ConstItem,
@@ -2558,7 +2564,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             let mut add_bindings_for_ns = |ns| {
                 let parent_rib = self.ribs[ns]
                     .iter()
-                    .rfind(|r| matches!(r.kind, RibKind::Item(_)))
+                    .rfind(|r| matches!(r.kind, RibKind::Item(..)))
                     .expect("associated item outside of an item");
                 seen_bindings.extend(parent_rib.bindings.keys().map(|ident| (*ident, ident.span)));
             };
@@ -2693,8 +2699,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
         self.label_ribs.pop();
     }
 
-    fn with_static_rib(&mut self, f: impl FnOnce(&mut Self)) {
-        let kind = RibKind::Item(HasGenericParams::No);
+    fn with_static_rib(&mut self, def_kind: DefKind, f: impl FnOnce(&mut Self)) {
+        let kind = RibKind::Item(HasGenericParams::No, def_kind);
         self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f))
     }
 
@@ -2875,7 +2881,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
         // If applicable, create a rib for the type parameters.
         self.with_generic_param_rib(
             &generics.params,
-            RibKind::Item(HasGenericParams::Yes(generics.span)),
+            RibKind::Item(HasGenericParams::Yes(generics.span), self.r.local_def_kind(item_id)),
             LifetimeRibKind::Generics {
                 span: generics.span,
                 binder: item_id,
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 310c126213a..5d712461993 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1077,24 +1077,34 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
         err: &mut Diagnostic,
         path: &[Segment],
     ) {
-        if let Some(pat) = self.diagnostic_metadata.current_pat
-            && let ast::PatKind::Range(Some(start), None, range) = &pat.kind
-            && let ExprKind::Path(None, range_path) = &start.kind
+        let Some(pat) = self.diagnostic_metadata.current_pat else { return };
+        let (bound, side, range) = match &pat.kind {
+            ast::PatKind::Range(Some(bound), None, range) => (bound, Side::Start, range),
+            ast::PatKind::Range(None, Some(bound), range) => (bound, Side::End, range),
+            _ => return,
+        };
+        if let ExprKind::Path(None, range_path) = &bound.kind
             && let [segment] = &range_path.segments[..]
             && let [s] = path
             && segment.ident == s.ident
+            && segment.ident.span.eq_ctxt(range.span)
         {
-            // We've encountered `[first, rest..]` where the user might have meant
-            // `[first, rest @ ..]` (#88404).
-            err.span_suggestion_verbose(
-                segment.ident.span.between(range.span),
-                format!(
-                    "if you meant to collect the rest of the slice in `{}`, use the at operator",
-                    segment.ident,
-                ),
-                " @ ",
-                Applicability::MaybeIncorrect,
-            );
+            // We've encountered `[first, rest..]` (#88404) or `[first, ..rest]` (#120591)
+            // where the user might have meant `[first, rest @ ..]`.
+            let (span, snippet) = match side {
+                Side::Start => (segment.ident.span.between(range.span), " @ ".into()),
+                Side::End => (range.span.to(segment.ident.span), format!("{} @ ..", segment.ident)),
+            };
+            err.subdiagnostic(errors::UnexpectedResUseAtOpInSlicePatWithRangeSugg {
+                span,
+                ident: segment.ident,
+                snippet,
+            });
+        }
+
+        enum Side {
+            Start,
+            End,
         }
     }
 
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 9d09d060b59..16dce7e431d 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -184,7 +184,7 @@ struct BindingError {
 #[derive(Debug)]
 enum ResolutionError<'a> {
     /// Error E0401: can't use type or const parameters from outer item.
-    GenericParamsFromOuterItem(Res, HasGenericParams),
+    GenericParamsFromOuterItem(Res, HasGenericParams, DefKind),
     /// Error E0403: the name is already used for a type or const parameter in this generic
     /// parameter list.
     NameAlreadyUsedInParameterList(Symbol, Span),
@@ -1217,6 +1217,10 @@ impl<'tcx> Resolver<'_, 'tcx> {
         self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{node:?}`"))
     }
 
+    fn local_def_kind(&self, node: NodeId) -> DefKind {
+        self.tcx.def_kind(self.local_def_id(node))
+    }
+
     /// Adds a definition with a parent definition.
     fn create_def(
         &mut self,
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index d8d201d5f24..ea93ac5841f 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1572,6 +1572,8 @@ options! {
     dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
         "in dep-info output, omit targets for tracking dependencies of the dep-info files \
         themselves (default: no)"),
+    direct_access_external_data: Option<bool> = (None, parse_opt_bool, [TRACKED],
+        "Direct or use GOT indirect to reference external data symbols"),
     dual_proc_macros: bool = (false, parse_bool, [TRACKED],
         "load proc macros for both target and host, but only link to the target (default: no)"),
     dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index f6af5a4f87e..188cf06d505 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -767,6 +767,13 @@ impl Session {
         self.opts.unstable_opts.tls_model.unwrap_or(self.target.tls_model)
     }
 
+    pub fn direct_access_external_data(&self) -> Option<bool> {
+        self.opts
+            .unstable_opts
+            .direct_access_external_data
+            .or(self.target.direct_access_external_data)
+    }
+
     pub fn split_debuginfo(&self) -> SplitDebuginfo {
         self.opts.cg.split_debuginfo.unwrap_or(self.target.split_debuginfo)
     }
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
index e433460e2ad..41a4edfc03b 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
@@ -538,6 +538,9 @@ impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> {
                     tables.tcx.coroutine_movability(*def_id).stable(tables),
                 )
             }
+            mir::AggregateKind::CoroutineClosure(..) => {
+                todo!("FIXME(async_closures): Lower these to SMIR")
+            }
         }
     }
 }
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
index ba957843bb0..959a17d24b7 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
@@ -383,6 +383,7 @@ impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> {
                 tables.closure_def(*def_id),
                 generic_args.stable(tables),
             )),
+            ty::CoroutineClosure(..) => todo!("FIXME(async_closures): Lower these to SMIR"),
             ty::Coroutine(def_id, generic_args) => TyKind::RigidTy(RigidTy::Coroutine(
                 tables.coroutine_def(*def_id),
                 generic_args.stable(tables),
@@ -798,6 +799,8 @@ impl<'tcx> Stable<'tcx> for ty::Instance<'tcx> {
             | ty::InstanceDef::ReifyShim(..)
             | ty::InstanceDef::FnPtrAddrShim(..)
             | ty::InstanceDef::ClosureOnceShim { .. }
+            | ty::InstanceDef::ConstructCoroutineInClosureShim { .. }
+            | ty::InstanceDef::CoroutineKindShim { .. }
             | ty::InstanceDef::ThreadLocalShim(..)
             | ty::InstanceDef::DropGlue(..)
             | ty::InstanceDef::CloneShim(..)
diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs
index 5788d11ed43..51f8aa04e8a 100644
--- a/compiler/rustc_span/src/source_map/tests.rs
+++ b/compiler/rustc_span/src/source_map/tests.rs
@@ -1,5 +1,7 @@
 use super::*;
 
+use rustc_data_structures::sync::FreezeLock;
+
 fn init_source_map() -> SourceMap {
     let sm = SourceMap::new(FilePathMapping::empty());
     sm.new_source_file(PathBuf::from("blork.rs").into(), "first line.\nsecond line".to_string());
@@ -263,53 +265,6 @@ fn t10() {
     );
 }
 
-/// Returns the span corresponding to the `n`th occurrence of `substring` in `source_text`.
-trait SourceMapExtension {
-    fn span_substr(
-        &self,
-        file: &Lrc<SourceFile>,
-        source_text: &str,
-        substring: &str,
-        n: usize,
-    ) -> Span;
-}
-
-impl SourceMapExtension for SourceMap {
-    fn span_substr(
-        &self,
-        file: &Lrc<SourceFile>,
-        source_text: &str,
-        substring: &str,
-        n: usize,
-    ) -> Span {
-        eprintln!(
-            "span_substr(file={:?}/{:?}, substring={:?}, n={})",
-            file.name, file.start_pos, substring, n
-        );
-        let mut i = 0;
-        let mut hi = 0;
-        loop {
-            let offset = source_text[hi..].find(substring).unwrap_or_else(|| {
-                panic!(
-                    "source_text `{}` does not have {} occurrences of `{}`, only {}",
-                    source_text, n, substring, i
-                );
-            });
-            let lo = hi + offset;
-            hi = lo + substring.len();
-            if i == n {
-                let span = Span::with_root_ctxt(
-                    BytePos(lo as u32 + file.start_pos.0),
-                    BytePos(hi as u32 + file.start_pos.0),
-                );
-                assert_eq!(&self.span_to_snippet(span).unwrap()[..], substring);
-                return span;
-            }
-            i += 1;
-        }
-    }
-}
-
 // Takes a unix-style path and returns a platform specific path.
 fn path(p: &str) -> PathBuf {
     path_str(p).into()
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 2dca9808ada..ed6e69d9199 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -167,6 +167,9 @@ symbols! {
         Break,
         C,
         CStr,
+        CallFuture,
+        CallMutFuture,
+        CallOnceFuture,
         Capture,
         Center,
         Cleanup,
@@ -318,6 +321,7 @@ symbols! {
         TyCtxt,
         TyKind,
         Unknown,
+        Upvars,
         Vec,
         VecDeque,
         Wrapper,
@@ -420,6 +424,7 @@ symbols! {
         async_closure,
         async_fn,
         async_fn_in_trait,
+        async_fn_kind_helper,
         async_fn_mut,
         async_fn_once,
         async_fn_track_caller,
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index 4a5f58443bc..646649293fc 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -64,16 +64,29 @@ pub(super) fn mangle<'tcx>(
         )
         .unwrap();
 
-    if let ty::InstanceDef::ThreadLocalShim(..) = instance.def {
-        let _ = printer.write_str("{{tls-shim}}");
-    }
-
-    if let ty::InstanceDef::VTableShim(..) = instance.def {
-        let _ = printer.write_str("{{vtable-shim}}");
-    }
-
-    if let ty::InstanceDef::ReifyShim(..) = instance.def {
-        let _ = printer.write_str("{{reify-shim}}");
+    match instance.def {
+        ty::InstanceDef::ThreadLocalShim(..) => {
+            printer.write_str("{{tls-shim}}").unwrap();
+        }
+        ty::InstanceDef::VTableShim(..) => {
+            printer.write_str("{{vtable-shim}}").unwrap();
+        }
+        ty::InstanceDef::ReifyShim(..) => {
+            printer.write_str("{{reify-shim}}").unwrap();
+        }
+        // FIXME(async_closures): This shouldn't be needed when we fix
+        // `Instance::ty`/`Instance::def_id`.
+        ty::InstanceDef::ConstructCoroutineInClosureShim { target_kind, .. }
+        | ty::InstanceDef::CoroutineKindShim { target_kind, .. } => match target_kind {
+            ty::ClosureKind::Fn => unreachable!(),
+            ty::ClosureKind::FnMut => {
+                printer.write_str("{{fn-mut-shim}}").unwrap();
+            }
+            ty::ClosureKind::FnOnce => {
+                printer.write_str("{{fn-once-shim}}").unwrap();
+            }
+        },
+        _ => {}
     }
 
     printer.path.finish(hash)
@@ -211,6 +224,7 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> {
             ty::FnDef(def_id, args)
             | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. })
             | ty::Closure(def_id, args)
+            | ty::CoroutineClosure(def_id, args)
             | ty::Coroutine(def_id, args) => self.print_def_path(def_id, args),
 
             // The `pretty_print_type` formatting of array size depends on
@@ -281,7 +295,11 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> {
         // Similar to `pretty_path_qualified`, but for the other
         // types that are printed as paths (see `print_type` above).
         match self_ty.kind() {
-            ty::FnDef(..) | ty::Alias(..) | ty::Closure(..) | ty::Coroutine(..)
+            ty::FnDef(..)
+            | ty::Alias(..)
+            | ty::Closure(..)
+            | ty::CoroutineClosure(..)
+            | ty::Coroutine(..)
                 if trait_ref.is_none() =>
             {
                 self.print_type(self_ty)
diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
index 0cc82ac7506..9d1b92e1068 100644
--- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
@@ -628,7 +628,9 @@ fn encode_ty<'tcx>(
         }
 
         // Function types
-        ty::FnDef(def_id, args) | ty::Closure(def_id, args) => {
+        ty::FnDef(def_id, args)
+        | ty::Closure(def_id, args)
+        | ty::CoroutineClosure(def_id, args) => {
             // u<length><name>[I<element-type1..element-typeN>E], where <element-type> is <subst>,
             // as vendor extended type.
             let mut s = String::new();
@@ -895,6 +897,10 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
             ty = Ty::new_closure(tcx, *def_id, transform_args(tcx, args, options));
         }
 
+        ty::CoroutineClosure(def_id, args) => {
+            ty = Ty::new_coroutine_closure(tcx, *def_id, transform_args(tcx, args, options));
+        }
+
         ty::Coroutine(def_id, args) => {
             ty = Ty::new_coroutine(tcx, *def_id, transform_args(tcx, args, options));
         }
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 16ebda55a7a..530221555c5 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -46,6 +46,13 @@ pub(super) fn mangle<'tcx>(
         ty::InstanceDef::VTableShim(_) => Some("vtable"),
         ty::InstanceDef::ReifyShim(_) => Some("reify"),
 
+        ty::InstanceDef::ConstructCoroutineInClosureShim { target_kind, .. }
+        | ty::InstanceDef::CoroutineKindShim { target_kind, .. } => match target_kind {
+            ty::ClosureKind::Fn => unreachable!(),
+            ty::ClosureKind::FnMut => Some("fn_mut"),
+            ty::ClosureKind::FnOnce => Some("fn_once"),
+        },
+
         _ => None,
     };
 
@@ -386,6 +393,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
             | ty::FnDef(def_id, args)
             | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. })
             | ty::Closure(def_id, args)
+            | ty::CoroutineClosure(def_id, args)
             | ty::Coroutine(def_id, args) => {
                 self.print_def_path(def_id, args)?;
             }
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 6c698c5b01d..d04bcb2d78a 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1543,6 +1543,7 @@ supported_targets! {
     ("armebv7r-none-eabihf", armebv7r_none_eabihf),
     ("armv7r-none-eabi", armv7r_none_eabi),
     ("armv7r-none-eabihf", armv7r_none_eabihf),
+    ("armv8r-none-eabihf", armv8r_none_eabihf),
 
     ("x86_64-pc-solaris", x86_64_pc_solaris),
     ("sparcv9-sun-solaris", sparcv9_sun_solaris),
@@ -1886,6 +1887,8 @@ pub struct TargetOptions {
     /// passed, and cannot be disabled even via `-C`. Corresponds to `llc
     /// -mattr=$features`.
     pub features: StaticCow<str>,
+    /// Direct or use GOT indirect to reference external data symbols
+    pub direct_access_external_data: Option<bool>,
     /// Whether dynamic linking is available on this target. Defaults to false.
     pub dynamic_linking: bool,
     /// Whether dynamic linking can export TLS globals. Defaults to true.
@@ -2280,6 +2283,7 @@ impl Default for TargetOptions {
             asm_args: cvs![],
             cpu: "generic".into(),
             features: "".into(),
+            direct_access_external_data: None,
             dynamic_linking: false,
             dll_tls_export: true,
             only_cdylib: false,
@@ -2579,6 +2583,12 @@ impl Target {
                     base.$key_name = s as u32;
                 }
             } );
+            ($key_name:ident, Option<bool>) => ( {
+                let name = (stringify!($key_name)).replace("_", "-");
+                if let Some(s) = obj.remove(&name).and_then(|b| b.as_bool()) {
+                    base.$key_name = Some(s);
+                }
+            } );
             ($key_name:ident, Option<u64>) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
                 if let Some(s) = obj.remove(&name).and_then(|b| b.as_u64()) {
@@ -3007,6 +3017,7 @@ impl Target {
         key!(cpu);
         key!(features);
         key!(dynamic_linking, bool);
+        key!(direct_access_external_data, Option<bool>);
         key!(dll_tls_export, bool);
         key!(only_cdylib, bool);
         key!(executables, bool);
@@ -3261,6 +3272,7 @@ impl ToJson for Target {
         target_option_val!(cpu);
         target_option_val!(features);
         target_option_val!(dynamic_linking);
+        target_option_val!(direct_access_external_data);
         target_option_val!(dll_tls_export);
         target_option_val!(only_cdylib);
         target_option_val!(executables);
diff --git a/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs
new file mode 100644
index 00000000000..28dba4f7f5d
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs
@@ -0,0 +1,35 @@
+// Targets the Little-endian Cortex-R52 processor (ARMv8-R)
+
+use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+
+pub fn target() -> Target {
+    Target {
+        llvm_target: "armv8r-none-eabihf".into(),
+        pointer_width: 32,
+        data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
+        arch: "arm".into(),
+
+        options: TargetOptions {
+            abi: "eabihf".into(),
+            linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
+            linker: Some("rust-lld".into()),
+            relocation_model: RelocModel::Static,
+            panic_strategy: PanicStrategy::Abort,
+            // The Cortex-R52 has two variants with respect to floating-point support:
+            // 1. fp-armv8, SP-only, with 16 DP (32 SP) registers
+            // 2. neon-fp-armv8, SP+DP, with 32 DP registers
+            // Use the lesser of these two options as the default, as it will produce code
+            // compatible with either variant.
+            //
+            // Reference:
+            // Arm Cortex-R52 Processor Technical Reference Manual
+            // - Chapter 15 Advanced SIMD and floating-point support
+            features: "+fp-armv8,-fp64,-d32".into(),
+            max_atomic_width: Some(64),
+            emit_debug_gdb_scripts: false,
+            // GCC defaults to 8 for arm-none here.
+            c_enum_min_bits: Some(8),
+            ..Default::default()
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs
index cb24e740c86..f4350708986 100644
--- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs
@@ -12,6 +12,7 @@ pub fn target() -> Target {
             features: "+f,+d".into(),
             llvm_abiname: "lp64d".into(),
             max_atomic_width: Some(64),
+            direct_access_external_data: Some(false),
             ..base::linux_gnu::opts()
         },
     }
diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs
index e8929f114e1..756db7cc206 100644
--- a/compiler/rustc_trait_selection/src/regions.rs
+++ b/compiler/rustc_trait_selection/src/regions.rs
@@ -1,5 +1,6 @@
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{InferCtxt, RegionResolutionError};
+use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::ObligationCause;
 
 pub trait InferCtxtRegionExt<'tcx> {
@@ -31,7 +32,7 @@ impl<'tcx> InferCtxtRegionExt<'tcx> for InferCtxt<'tcx> {
                     ),
                     ty,
                 )
-                .map_err(|_| ty)
+                .map_err(|_| NoSolution)
             } else {
                 Ok(ty)
             }
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 915d722dd02..7052fd776b0 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -182,6 +182,22 @@ pub(super) trait GoalKind<'tcx>:
         kind: ty::ClosureKind,
     ) -> QueryResult<'tcx>;
 
+    /// An async closure is known to implement the `AsyncFn<A>` family of traits
+    /// where `A` is given by the signature of the type.
+    fn consider_builtin_async_fn_trait_candidates(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+        kind: ty::ClosureKind,
+    ) -> QueryResult<'tcx>;
+
+    /// Compute the built-in logic of the `AsyncFnKindHelper` helper trait, which
+    /// is used internally to delay computation for async closures until after
+    /// upvar analysis is performed in HIR typeck.
+    fn consider_builtin_async_fn_kind_helper_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx>;
+
     /// `Tuple` is implemented if the `Self` type is a tuple.
     fn consider_builtin_tuple_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
@@ -340,7 +356,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             | ty::FnDef(_, _)
             | ty::FnPtr(_)
             | ty::Dynamic(_, _, _)
-            | ty::Closure(_, _)
+            | ty::Closure(..)
+            | ty::CoroutineClosure(..)
             | ty::Coroutine(_, _)
             | ty::Never
             | ty::Tuple(_) => {
@@ -460,6 +477,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             G::consider_builtin_fn_ptr_trait_candidate(self, goal)
         } else if let Some(kind) = self.tcx().fn_trait_kind_from_def_id(trait_def_id) {
             G::consider_builtin_fn_trait_candidates(self, goal, kind)
+        } else if let Some(kind) = self.tcx().async_fn_trait_kind_from_def_id(trait_def_id) {
+            G::consider_builtin_async_fn_trait_candidates(self, goal, kind)
+        } else if lang_items.async_fn_kind_helper() == Some(trait_def_id) {
+            G::consider_builtin_async_fn_kind_helper_candidate(self, goal)
         } else if lang_items.tuple_trait() == Some(trait_def_id) {
             G::consider_builtin_tuple_candidate(self, goal)
         } else if lang_items.pointee_trait() == Some(trait_def_id) {
@@ -538,6 +559,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             | ty::FnPtr(_)
             | ty::Dynamic(..)
             | ty::Closure(..)
+            | ty::CoroutineClosure(..)
             | ty::Coroutine(..)
             | ty::CoroutineWitness(..)
             | ty::Never
@@ -694,6 +716,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             | ty::FnPtr(_)
             | ty::Alias(..)
             | ty::Closure(..)
+            | ty::CoroutineClosure(..)
             | ty::Coroutine(..)
             | ty::CoroutineWitness(..)
             | ty::Never
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
index 274a75a125c..d02578c4846 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
@@ -1,12 +1,14 @@
 //! Code which is used by built-in goals that match "structurally", such a auto
 //! traits, `Copy`/`Clone`.
 use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::LangItem;
 use rustc_hir::{def_id::DefId, Movability, Mutability};
 use rustc_infer::traits::query::NoSolution;
 use rustc_middle::traits::solve::Goal;
 use rustc_middle::ty::{
-    self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
+    self, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
 };
+use rustc_span::sym;
 
 use crate::solve::EvalCtxt;
 
@@ -57,6 +59,8 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
 
         ty::Closure(_, args) => Ok(vec![args.as_closure().tupled_upvars_ty()]),
 
+        ty::CoroutineClosure(_, args) => Ok(vec![args.as_coroutine_closure().tupled_upvars_ty()]),
+
         ty::Coroutine(_, args) => {
             let coroutine_args = args.as_coroutine();
             Ok(vec![coroutine_args.tupled_upvars_ty(), coroutine_args.witness()])
@@ -128,6 +132,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
         | ty::CoroutineWitness(..)
         | ty::Array(..)
         | ty::Closure(..)
+        | ty::CoroutineClosure(..)
         | ty::Never
         | ty::Dynamic(_, _, ty::DynStar)
         | ty::Error(_) => Ok(vec![]),
@@ -193,6 +198,8 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
 
         ty::Closure(_, args) => Ok(vec![args.as_closure().tupled_upvars_ty()]),
 
+        ty::CoroutineClosure(..) => Err(NoSolution),
+
         ty::Coroutine(def_id, args) => match ecx.tcx().coroutine_movability(def_id) {
             Movability::Static => Err(NoSolution),
             Movability::Movable => {
@@ -267,6 +274,131 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
             }
             Ok(Some(closure_args.sig().map_bound(|sig| (sig.inputs()[0], sig.output()))))
         }
+
+        // Coroutine-closures don't implement `Fn` traits the normal way.
+        ty::CoroutineClosure(..) => Err(NoSolution),
+
+        ty::Bool
+        | ty::Char
+        | ty::Int(_)
+        | ty::Uint(_)
+        | ty::Float(_)
+        | ty::Adt(_, _)
+        | ty::Foreign(_)
+        | ty::Str
+        | ty::Array(_, _)
+        | ty::Slice(_)
+        | ty::RawPtr(_)
+        | ty::Ref(_, _, _)
+        | ty::Dynamic(_, _, _)
+        | ty::Coroutine(_, _)
+        | ty::CoroutineWitness(..)
+        | ty::Never
+        | ty::Tuple(_)
+        | ty::Alias(_, _)
+        | ty::Param(_)
+        | ty::Placeholder(..)
+        | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
+        | ty::Error(_) => Err(NoSolution),
+
+        ty::Bound(..)
+        | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+            bug!("unexpected type `{self_ty}`")
+        }
+    }
+}
+
+// Returns a binder of the tupled inputs types, output type, and coroutine type
+// from a builtin coroutine-closure type. If we don't yet know the closure kind of
+// the coroutine-closure, emit an additional trait predicate for `AsyncFnKindHelper`
+// which enforces the closure is actually callable with the given trait. When we
+// know the kind already, we can short-circuit this check.
+pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    self_ty: Ty<'tcx>,
+    goal_kind: ty::ClosureKind,
+    env_region: ty::Region<'tcx>,
+) -> Result<
+    (ty::Binder<'tcx, (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>)>, Option<ty::Predicate<'tcx>>),
+    NoSolution,
+> {
+    match *self_ty.kind() {
+        ty::CoroutineClosure(def_id, args) => {
+            let args = args.as_coroutine_closure();
+            let kind_ty = args.kind_ty();
+
+            if let Some(closure_kind) = kind_ty.to_opt_closure_kind() {
+                if !closure_kind.extends(goal_kind) {
+                    return Err(NoSolution);
+                }
+                Ok((
+                    args.coroutine_closure_sig().map_bound(|sig| {
+                        let coroutine_ty = sig.to_coroutine_given_kind_and_upvars(
+                            tcx,
+                            args.parent_args(),
+                            tcx.coroutine_for_closure(def_id),
+                            goal_kind,
+                            env_region,
+                            args.tupled_upvars_ty(),
+                            args.coroutine_captures_by_ref_ty(),
+                        );
+                        (sig.tupled_inputs_ty, sig.return_ty, coroutine_ty)
+                    }),
+                    None,
+                ))
+            } else {
+                let async_fn_kind_trait_def_id =
+                    tcx.require_lang_item(LangItem::AsyncFnKindHelper, None);
+                let upvars_projection_def_id = tcx
+                    .associated_items(async_fn_kind_trait_def_id)
+                    .filter_by_name_unhygienic(sym::Upvars)
+                    .next()
+                    .unwrap()
+                    .def_id;
+                // When we don't know the closure kind (and therefore also the closure's upvars,
+                // which are computed at the same time), we must delay the computation of the
+                // generator's upvars. We do this using the `AsyncFnKindHelper`, which as a trait
+                // goal functions similarly to the old `ClosureKind` predicate, and ensures that
+                // the goal kind <= the closure kind. As a projection `AsyncFnKindHelper::Upvars`
+                // will project to the right upvars for the generator, appending the inputs and
+                // coroutine upvars respecting the closure kind.
+                Ok((
+                    args.coroutine_closure_sig().map_bound(|sig| {
+                        let tupled_upvars_ty = Ty::new_projection(
+                            tcx,
+                            upvars_projection_def_id,
+                            [
+                                ty::GenericArg::from(kind_ty),
+                                Ty::from_closure_kind(tcx, goal_kind).into(),
+                                env_region.into(),
+                                sig.tupled_inputs_ty.into(),
+                                args.tupled_upvars_ty().into(),
+                                args.coroutine_captures_by_ref_ty().into(),
+                            ],
+                        );
+                        let coroutine_ty = sig.to_coroutine(
+                            tcx,
+                            args.parent_args(),
+                            Ty::from_closure_kind(tcx, goal_kind),
+                            tcx.coroutine_for_closure(def_id),
+                            tupled_upvars_ty,
+                        );
+                        (sig.tupled_inputs_ty, sig.return_ty, coroutine_ty)
+                    }),
+                    Some(
+                        ty::TraitRef::new(
+                            tcx,
+                            async_fn_kind_trait_def_id,
+                            [kind_ty, Ty::from_closure_kind(tcx, goal_kind)],
+                        )
+                        .to_predicate(tcx),
+                    ),
+                ))
+            }
+        }
+
+        ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..) => Err(NoSolution),
+
         ty::Bool
         | ty::Char
         | ty::Int(_)
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
index 9f1b4a09a20..47ba549022d 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
@@ -366,6 +366,119 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
         Self::consider_implied_clause(ecx, goal, pred, [goal.with(tcx, output_is_sized_pred)])
     }
 
+    fn consider_builtin_async_fn_trait_candidates(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+        goal_kind: ty::ClosureKind,
+    ) -> QueryResult<'tcx> {
+        let tcx = ecx.tcx();
+
+        let env_region = match goal_kind {
+            ty::ClosureKind::Fn | ty::ClosureKind::FnMut => goal.predicate.alias.args.region_at(2),
+            // Doesn't matter what this region is
+            ty::ClosureKind::FnOnce => tcx.lifetimes.re_static,
+        };
+        let (tupled_inputs_and_output_and_coroutine, nested_preds) =
+            structural_traits::extract_tupled_inputs_and_output_from_async_callable(
+                tcx,
+                goal.predicate.self_ty(),
+                goal_kind,
+                env_region,
+            )?;
+        let output_is_sized_pred =
+            tupled_inputs_and_output_and_coroutine.map_bound(|(_, output, _)| {
+                ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output])
+            });
+
+        let pred = tupled_inputs_and_output_and_coroutine
+            .map_bound(|(inputs, output, coroutine)| {
+                let (projection_ty, term) = match tcx.item_name(goal.predicate.def_id()) {
+                    sym::CallOnceFuture => (
+                        ty::AliasTy::new(
+                            tcx,
+                            goal.predicate.def_id(),
+                            [goal.predicate.self_ty(), inputs],
+                        ),
+                        coroutine.into(),
+                    ),
+                    sym::CallMutFuture | sym::CallFuture => (
+                        ty::AliasTy::new(
+                            tcx,
+                            goal.predicate.def_id(),
+                            [
+                                ty::GenericArg::from(goal.predicate.self_ty()),
+                                inputs.into(),
+                                env_region.into(),
+                            ],
+                        ),
+                        coroutine.into(),
+                    ),
+                    sym::Output => (
+                        ty::AliasTy::new(
+                            tcx,
+                            goal.predicate.def_id(),
+                            [ty::GenericArg::from(goal.predicate.self_ty()), inputs.into()],
+                        ),
+                        output.into(),
+                    ),
+                    name => bug!("no such associated type: {name}"),
+                };
+                ty::ProjectionPredicate { projection_ty, term }
+            })
+            .to_predicate(tcx);
+
+        // A built-in `AsyncFn` impl only holds if the output is sized.
+        // (FIXME: technically we only need to check this if the type is a fn ptr...)
+        Self::consider_implied_clause(
+            ecx,
+            goal,
+            pred,
+            [goal.with(tcx, output_is_sized_pred)]
+                .into_iter()
+                .chain(nested_preds.into_iter().map(|pred| goal.with(tcx, pred))),
+        )
+    }
+
+    fn consider_builtin_async_fn_kind_helper_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        let [
+            closure_fn_kind_ty,
+            goal_kind_ty,
+            borrow_region,
+            tupled_inputs_ty,
+            tupled_upvars_ty,
+            coroutine_captures_by_ref_ty,
+        ] = **goal.predicate.alias.args
+        else {
+            bug!();
+        };
+
+        let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() else {
+            // We don't need to worry about the self type being an infer var.
+            return Err(NoSolution);
+        };
+        let Some(goal_kind) = goal_kind_ty.expect_ty().to_opt_closure_kind() else {
+            return Err(NoSolution);
+        };
+        if !closure_kind.extends(goal_kind) {
+            return Err(NoSolution);
+        }
+
+        let upvars_ty = ty::CoroutineClosureSignature::tupled_upvars_by_closure_kind(
+            ecx.tcx(),
+            goal_kind,
+            tupled_inputs_ty.expect_ty(),
+            tupled_upvars_ty.expect_ty(),
+            coroutine_captures_by_ref_ty.expect_ty(),
+            borrow_region.expect_region(),
+        );
+
+        ecx.eq(goal.param_env, goal.predicate.term.ty().unwrap(), upvars_ty)?;
+        ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+    }
+
     fn consider_builtin_tuple_candidate(
         _ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
@@ -391,6 +504,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
                 | ty::FnDef(..)
                 | ty::FnPtr(..)
                 | ty::Closure(..)
+                | ty::CoroutineClosure(..)
                 | ty::Infer(ty::IntVar(..) | ty::FloatVar(..))
                 | ty::Coroutine(..)
                 | ty::CoroutineWitness(..)
@@ -627,6 +741,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
             | ty::FnDef(..)
             | ty::FnPtr(..)
             | ty::Closure(..)
+            | ty::CoroutineClosure(..)
             | ty::Infer(ty::IntVar(..) | ty::FloatVar(..))
             | ty::Coroutine(..)
             | ty::CoroutineWitness(..)
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index b185e4e5f8e..fd09a6b671d 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -303,6 +303,66 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         Self::consider_implied_clause(ecx, goal, pred, [goal.with(tcx, output_is_sized_pred)])
     }
 
+    fn consider_builtin_async_fn_trait_candidates(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+        goal_kind: ty::ClosureKind,
+    ) -> QueryResult<'tcx> {
+        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+            return Err(NoSolution);
+        }
+
+        let tcx = ecx.tcx();
+        let (tupled_inputs_and_output_and_coroutine, nested_preds) =
+            structural_traits::extract_tupled_inputs_and_output_from_async_callable(
+                tcx,
+                goal.predicate.self_ty(),
+                goal_kind,
+                // This region doesn't matter because we're throwing away the coroutine type
+                tcx.lifetimes.re_static,
+            )?;
+        let output_is_sized_pred =
+            tupled_inputs_and_output_and_coroutine.map_bound(|(_, output, _)| {
+                ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output])
+            });
+
+        let pred = tupled_inputs_and_output_and_coroutine
+            .map_bound(|(inputs, _, _)| {
+                ty::TraitRef::new(tcx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
+            })
+            .to_predicate(tcx);
+        // A built-in `AsyncFn` impl only holds if the output is sized.
+        // (FIXME: technically we only need to check this if the type is a fn ptr...)
+        Self::consider_implied_clause(
+            ecx,
+            goal,
+            pred,
+            [goal.with(tcx, output_is_sized_pred)]
+                .into_iter()
+                .chain(nested_preds.into_iter().map(|pred| goal.with(tcx, pred))),
+        )
+    }
+
+    fn consider_builtin_async_fn_kind_helper_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        let [closure_fn_kind_ty, goal_kind_ty] = **goal.predicate.trait_ref.args else {
+            bug!();
+        };
+
+        let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() else {
+            // We don't need to worry about the self type being an infer var.
+            return Err(NoSolution);
+        };
+        let goal_kind = goal_kind_ty.expect_ty().to_opt_closure_kind().unwrap();
+        if closure_kind.extends(goal_kind) {
+            ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+        } else {
+            Err(NoSolution)
+        }
+    }
+
     fn consider_builtin_tuple_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
@@ -950,7 +1010,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             | ty::Ref(_, _, _)
             | ty::FnDef(_, _)
             | ty::FnPtr(_)
-            | ty::Closure(_, _)
+            | ty::Closure(..)
+            | ty::CoroutineClosure(..)
             | ty::Coroutine(_, _)
             | ty::CoroutineWitness(..)
             | ty::Never
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 7933654a915..81c72fc4b7b 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -179,7 +179,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
         }
 
         let outlives_env = OutlivesEnvironment::new(full_env);
-        let _ = infcx.process_registered_region_obligations::<!>(&outlives_env, |ty, _| Ok(ty));
+        let _ = infcx.process_registered_region_obligations(&outlives_env, |ty, _| Ok(ty));
 
         let region_data =
             infcx.inner.borrow_mut().unwrap_region_constraints().region_constraint_data().clone();
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index c49185a52c7..4b20de26219 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -863,7 +863,7 @@ where
                 }
             }
             ty::Error(_) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
-            ty::Closure(did, ..) | ty::Coroutine(did, ..) => {
+            ty::Closure(did, ..) | ty::CoroutineClosure(did, ..) | ty::Coroutine(did, ..) => {
                 if self.def_id_is_local(did) {
                     ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
                 } else {
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
index a8715b0764f..1ac0f172ef4 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
@@ -959,9 +959,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         obligation: &PredicateObligation<'tcx>,
         trait_ref: ty::PolyTraitRef<'tcx>,
     ) -> Option<ErrorGuaranteed> {
-        if let ty::Closure(closure_def_id, closure_args) = *trait_ref.self_ty().skip_binder().kind()
+        let self_ty = trait_ref.self_ty().skip_binder();
+        if let ty::Closure(closure_def_id, closure_args) = *self_ty.kind()
             && let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id())
-            && let Some(found_kind) = self.closure_kind(closure_args)
+            && let Some(found_kind) = self.closure_kind(self_ty)
             && !found_kind.extends(expected_kind)
             && let sig = closure_args.as_closure().sig()
             && self.can_sub(
@@ -1875,6 +1876,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 ty::Coroutine(..) => Some(18),
                 ty::Foreign(..) => Some(19),
                 ty::CoroutineWitness(..) => Some(20),
+                ty::CoroutineClosure(..) => Some(21),
                 ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
             }
         }
@@ -1924,45 +1926,50 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
     fn describe_closure(&self, kind: hir::ClosureKind) -> &'static str {
         match kind {
             hir::ClosureKind::Closure => "a closure",
-            hir::ClosureKind::Coroutine(kind) => match kind {
-                hir::CoroutineKind::Coroutine(_) => "a coroutine",
-                hir::CoroutineKind::Desugared(
-                    hir::CoroutineDesugaring::Async,
-                    hir::CoroutineSource::Block,
-                ) => "an async block",
-                hir::CoroutineKind::Desugared(
-                    hir::CoroutineDesugaring::Async,
-                    hir::CoroutineSource::Fn,
-                ) => "an async function",
-                hir::CoroutineKind::Desugared(
-                    hir::CoroutineDesugaring::Async,
-                    hir::CoroutineSource::Closure,
-                ) => "an async closure",
-                hir::CoroutineKind::Desugared(
-                    hir::CoroutineDesugaring::AsyncGen,
-                    hir::CoroutineSource::Block,
-                ) => "an async gen block",
-                hir::CoroutineKind::Desugared(
-                    hir::CoroutineDesugaring::AsyncGen,
-                    hir::CoroutineSource::Fn,
-                ) => "an async gen function",
-                hir::CoroutineKind::Desugared(
-                    hir::CoroutineDesugaring::AsyncGen,
-                    hir::CoroutineSource::Closure,
-                ) => "an async gen closure",
-                hir::CoroutineKind::Desugared(
-                    hir::CoroutineDesugaring::Gen,
-                    hir::CoroutineSource::Block,
-                ) => "a gen block",
-                hir::CoroutineKind::Desugared(
-                    hir::CoroutineDesugaring::Gen,
-                    hir::CoroutineSource::Fn,
-                ) => "a gen function",
-                hir::CoroutineKind::Desugared(
-                    hir::CoroutineDesugaring::Gen,
-                    hir::CoroutineSource::Closure,
-                ) => "a gen closure",
-            },
+            hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(_)) => "a coroutine",
+            hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
+                hir::CoroutineDesugaring::Async,
+                hir::CoroutineSource::Block,
+            )) => "an async block",
+            hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
+                hir::CoroutineDesugaring::Async,
+                hir::CoroutineSource::Fn,
+            )) => "an async function",
+            hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
+                hir::CoroutineDesugaring::Async,
+                hir::CoroutineSource::Closure,
+            ))
+            | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => {
+                "an async closure"
+            }
+            hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
+                hir::CoroutineDesugaring::AsyncGen,
+                hir::CoroutineSource::Block,
+            )) => "an async gen block",
+            hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
+                hir::CoroutineDesugaring::AsyncGen,
+                hir::CoroutineSource::Fn,
+            )) => "an async gen function",
+            hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
+                hir::CoroutineDesugaring::AsyncGen,
+                hir::CoroutineSource::Closure,
+            ))
+            | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::AsyncGen) => {
+                "an async gen closure"
+            }
+            hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
+                hir::CoroutineDesugaring::Gen,
+                hir::CoroutineSource::Block,
+            )) => "a gen block",
+            hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
+                hir::CoroutineDesugaring::Gen,
+                hir::CoroutineSource::Fn,
+            )) => "a gen function",
+            hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
+                hir::CoroutineDesugaring::Gen,
+                hir::CoroutineSource::Closure,
+            ))
+            | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Gen) => "a gen closure",
         }
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index abbc2066eac..955c81eee6b 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1833,10 +1833,28 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                     lang_items.fn_trait(),
                     lang_items.fn_mut_trait(),
                     lang_items.fn_once_trait(),
+                    lang_items.async_fn_trait(),
+                    lang_items.async_fn_mut_trait(),
+                    lang_items.async_fn_once_trait(),
                 ].contains(&Some(trait_ref.def_id))
                 {
                     true
-                }else if lang_items.discriminant_kind_trait() == Some(trait_ref.def_id) {
+                } else if lang_items.async_fn_kind_helper() == Some(trait_ref.def_id) {
+                    // FIXME(async_closures): Validity constraints here could be cleaned up.
+                    if obligation.predicate.args.type_at(0).is_ty_var()
+                        || obligation.predicate.args.type_at(4).is_ty_var()
+                        || obligation.predicate.args.type_at(5).is_ty_var()
+                    {
+                        candidate_set.mark_ambiguous();
+                        true
+                    } else if obligation.predicate.args.type_at(0).to_opt_closure_kind().is_some()
+                        && obligation.predicate.args.type_at(1).to_opt_closure_kind().is_some()
+                    {
+                        true
+                    } else {
+                        false
+                    }
+                } else if lang_items.discriminant_kind_trait() == Some(trait_ref.def_id) {
                     match self_ty.kind() {
                         ty::Bool
                         | ty::Char
@@ -1854,6 +1872,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                         | ty::FnPtr(..)
                         | ty::Dynamic(..)
                         | ty::Closure(..)
+                        | ty::CoroutineClosure(..)
                         | ty::Coroutine(..)
                         | ty::CoroutineWitness(..)
                         | ty::Never
@@ -1903,6 +1922,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                         | ty::FnPtr(..)
                         | ty::Dynamic(..)
                         | ty::Closure(..)
+                        | ty::CoroutineClosure(..)
                         | ty::Coroutine(..)
                         | ty::CoroutineWitness(..)
                         | ty::Never
@@ -2059,6 +2079,10 @@ fn confirm_select_candidate<'cx, 'tcx>(
                 } else {
                     confirm_fn_pointer_candidate(selcx, obligation, data)
                 }
+            } else if selcx.tcx().async_fn_trait_kind_from_def_id(trait_def_id).is_some() {
+                confirm_async_closure_candidate(selcx, obligation, data)
+            } else if lang_items.async_fn_kind_helper() == Some(trait_def_id) {
+                confirm_async_fn_kind_helper_candidate(selcx, obligation, data)
             } else {
                 confirm_builtin_candidate(selcx, obligation, data)
             }
@@ -2419,6 +2443,173 @@ fn confirm_callable_candidate<'cx, 'tcx>(
     confirm_param_env_candidate(selcx, obligation, predicate, true)
 }
 
+fn confirm_async_closure_candidate<'cx, 'tcx>(
+    selcx: &mut SelectionContext<'cx, 'tcx>,
+    obligation: &ProjectionTyObligation<'tcx>,
+    mut nested: Vec<PredicateObligation<'tcx>>,
+) -> Progress<'tcx> {
+    let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
+    let ty::CoroutineClosure(def_id, args) = *self_ty.kind() else {
+        unreachable!(
+            "expected coroutine-closure self type for coroutine-closure candidate, found {self_ty}"
+        )
+    };
+    let args = args.as_coroutine_closure();
+    let kind_ty = args.kind_ty();
+
+    let tcx = selcx.tcx();
+    let goal_kind =
+        tcx.async_fn_trait_kind_from_def_id(obligation.predicate.trait_def_id(tcx)).unwrap();
+
+    let async_fn_kind_helper_trait_def_id =
+        tcx.require_lang_item(LangItem::AsyncFnKindHelper, None);
+    nested.push(obligation.with(
+        tcx,
+        ty::TraitRef::new(
+            tcx,
+            async_fn_kind_helper_trait_def_id,
+            [kind_ty, Ty::from_closure_kind(tcx, goal_kind)],
+        ),
+    ));
+
+    let env_region = match goal_kind {
+        ty::ClosureKind::Fn | ty::ClosureKind::FnMut => obligation.predicate.args.region_at(2),
+        ty::ClosureKind::FnOnce => tcx.lifetimes.re_static,
+    };
+
+    let upvars_projection_def_id = tcx
+        .associated_items(async_fn_kind_helper_trait_def_id)
+        .filter_by_name_unhygienic(sym::Upvars)
+        .next()
+        .unwrap()
+        .def_id;
+
+    // FIXME(async_closures): Confirmation is kind of a mess here. Ideally,
+    // we'd short-circuit when we know that the goal_kind >= closure_kind, and not
+    // register a nested predicate or create a new projection ty here. But I'm too
+    // lazy to make this more efficient atm, and we can always tweak it later,
+    // since all this does is make the solver do more work.
+    //
+    // The code duplication due to the different length args is kind of weird, too.
+    //
+    // See the logic in `structural_traits` in the new solver to understand a bit
+    // more clearly how this *should* look.
+    let poly_cache_entry = args.coroutine_closure_sig().map_bound(|sig| {
+        let (projection_ty, term) = match tcx.item_name(obligation.predicate.def_id) {
+            sym::CallOnceFuture => {
+                let tupled_upvars_ty = Ty::new_projection(
+                    tcx,
+                    upvars_projection_def_id,
+                    [
+                        ty::GenericArg::from(kind_ty),
+                        Ty::from_closure_kind(tcx, goal_kind).into(),
+                        env_region.into(),
+                        sig.tupled_inputs_ty.into(),
+                        args.tupled_upvars_ty().into(),
+                        args.coroutine_captures_by_ref_ty().into(),
+                    ],
+                );
+                let coroutine_ty = sig.to_coroutine(
+                    tcx,
+                    args.parent_args(),
+                    Ty::from_closure_kind(tcx, goal_kind),
+                    tcx.coroutine_for_closure(def_id),
+                    tupled_upvars_ty,
+                );
+                (
+                    ty::AliasTy::new(
+                        tcx,
+                        obligation.predicate.def_id,
+                        [self_ty, sig.tupled_inputs_ty],
+                    ),
+                    coroutine_ty.into(),
+                )
+            }
+            sym::CallMutFuture | sym::CallFuture => {
+                let tupled_upvars_ty = Ty::new_projection(
+                    tcx,
+                    upvars_projection_def_id,
+                    [
+                        ty::GenericArg::from(kind_ty),
+                        Ty::from_closure_kind(tcx, goal_kind).into(),
+                        env_region.into(),
+                        sig.tupled_inputs_ty.into(),
+                        args.tupled_upvars_ty().into(),
+                        args.coroutine_captures_by_ref_ty().into(),
+                    ],
+                );
+                let coroutine_ty = sig.to_coroutine(
+                    tcx,
+                    args.parent_args(),
+                    Ty::from_closure_kind(tcx, goal_kind),
+                    tcx.coroutine_for_closure(def_id),
+                    tupled_upvars_ty,
+                );
+                (
+                    ty::AliasTy::new(
+                        tcx,
+                        obligation.predicate.def_id,
+                        [
+                            ty::GenericArg::from(self_ty),
+                            sig.tupled_inputs_ty.into(),
+                            env_region.into(),
+                        ],
+                    ),
+                    coroutine_ty.into(),
+                )
+            }
+            sym::Output => (
+                ty::AliasTy::new(tcx, obligation.predicate.def_id, [self_ty, sig.tupled_inputs_ty]),
+                sig.return_ty.into(),
+            ),
+            name => bug!("no such associated type: {name}"),
+        };
+        ty::ProjectionPredicate { projection_ty, term }
+    });
+
+    confirm_param_env_candidate(selcx, obligation, poly_cache_entry, true)
+        .with_addl_obligations(nested)
+}
+
+fn confirm_async_fn_kind_helper_candidate<'cx, 'tcx>(
+    selcx: &mut SelectionContext<'cx, 'tcx>,
+    obligation: &ProjectionTyObligation<'tcx>,
+    nested: Vec<PredicateObligation<'tcx>>,
+) -> Progress<'tcx> {
+    let [
+        // We already checked that the goal_kind >= closure_kind
+        _closure_kind_ty,
+        goal_kind_ty,
+        borrow_region,
+        tupled_inputs_ty,
+        tupled_upvars_ty,
+        coroutine_captures_by_ref_ty,
+    ] = **obligation.predicate.args
+    else {
+        bug!();
+    };
+
+    let predicate = ty::ProjectionPredicate {
+        projection_ty: ty::AliasTy::new(
+            selcx.tcx(),
+            obligation.predicate.def_id,
+            obligation.predicate.args,
+        ),
+        term: ty::CoroutineClosureSignature::tupled_upvars_by_closure_kind(
+            selcx.tcx(),
+            goal_kind_ty.expect_ty().to_opt_closure_kind().unwrap(),
+            tupled_inputs_ty.expect_ty(),
+            tupled_upvars_ty.expect_ty(),
+            coroutine_captures_by_ref_ty.expect_ty(),
+            borrow_region.expect_region(),
+        )
+        .into(),
+    };
+
+    confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
+        .with_addl_obligations(nested)
+}
+
 fn confirm_param_env_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
index 79f03242c58..6c8834f11f1 100644
--- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -48,7 +48,11 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
         // (T1..Tn) and closures have same properties as T1..Tn --
         // check if *all* of them are trivial.
         ty::Tuple(tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t)),
+
         ty::Closure(_, args) => trivial_dropck_outlives(tcx, args.as_closure().tupled_upvars_ty()),
+        ty::CoroutineClosure(_, args) => {
+            trivial_dropck_outlives(tcx, args.as_coroutine_closure().tupled_upvars_ty())
+        }
 
         ty::Adt(def, _) => {
             if Some(def.did()) == tcx.lang_items().manually_drop() {
@@ -239,6 +243,22 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
             Ok::<_, NoSolution>(())
         })?,
 
+        ty::CoroutineClosure(_, args) => {
+            rustc_data_structures::stack::ensure_sufficient_stack(|| {
+                for ty in args.as_coroutine_closure().upvar_tys() {
+                    dtorck_constraint_for_ty_inner(
+                        tcx,
+                        param_env,
+                        span,
+                        depth + 1,
+                        ty,
+                        constraints,
+                    )?;
+                }
+                Ok::<_, NoSolution>(())
+            })?
+        }
+
         ty::Coroutine(_, args) => {
             // rust-lang/rust#49918: types can be constructed, stored
             // in the interior, and sit idle when coroutine yields
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 12aea88e9b6..2258e796103 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -117,10 +117,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     self.assemble_iterator_candidates(obligation, &mut candidates);
                 } else if lang_items.async_iterator_trait() == Some(def_id) {
                     self.assemble_async_iterator_candidates(obligation, &mut candidates);
+                } else if lang_items.async_fn_kind_helper() == Some(def_id) {
+                    self.assemble_async_fn_kind_helper_candidates(obligation, &mut candidates);
                 }
 
+                // FIXME: Put these into `else if` blocks above, since they're built-in.
                 self.assemble_closure_candidates(obligation, &mut candidates);
+                self.assemble_async_closure_candidates(obligation, &mut candidates);
                 self.assemble_fn_pointer_candidates(obligation, &mut candidates);
+
                 self.assemble_candidates_from_impls(obligation, &mut candidates);
                 self.assemble_candidates_from_object_ty(obligation, &mut candidates);
             }
@@ -306,11 +311,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // Okay to skip binder because the args on closure types never
         // touch bound regions, they just capture the in-scope
         // type/region parameters
-        match *obligation.self_ty().skip_binder().kind() {
-            ty::Closure(def_id, closure_args) => {
+        let self_ty = obligation.self_ty().skip_binder();
+        match *self_ty.kind() {
+            ty::Closure(def_id, _) => {
                 let is_const = self.tcx().is_const_fn_raw(def_id);
                 debug!(?kind, ?obligation, "assemble_unboxed_candidates");
-                match self.infcx.closure_kind(closure_args) {
+                match self.infcx.closure_kind(self_ty) {
                     Some(closure_kind) => {
                         debug!(?closure_kind, "assemble_unboxed_candidates");
                         if closure_kind.extends(kind) {
@@ -334,6 +340,61 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
     }
 
+    fn assemble_async_closure_candidates(
+        &mut self,
+        obligation: &PolyTraitObligation<'tcx>,
+        candidates: &mut SelectionCandidateSet<'tcx>,
+    ) {
+        let Some(goal_kind) =
+            self.tcx().async_fn_trait_kind_from_def_id(obligation.predicate.def_id())
+        else {
+            return;
+        };
+
+        match *obligation.self_ty().skip_binder().kind() {
+            ty::CoroutineClosure(_, args) => {
+                if let Some(closure_kind) =
+                    args.as_coroutine_closure().kind_ty().to_opt_closure_kind()
+                    && !closure_kind.extends(goal_kind)
+                {
+                    return;
+                }
+                candidates.vec.push(AsyncClosureCandidate);
+            }
+            ty::Infer(ty::TyVar(_)) => {
+                candidates.ambiguous = true;
+            }
+            _ => {}
+        }
+    }
+
+    fn assemble_async_fn_kind_helper_candidates(
+        &mut self,
+        obligation: &PolyTraitObligation<'tcx>,
+        candidates: &mut SelectionCandidateSet<'tcx>,
+    ) {
+        let self_ty = obligation.self_ty().skip_binder();
+        let target_kind_ty = obligation.predicate.skip_binder().trait_ref.args.type_at(1);
+
+        // `to_opt_closure_kind` is kind of ICEy when it sees non-int types.
+        if !(self_ty.is_integral() || self_ty.is_ty_var()) {
+            return;
+        }
+        if !(target_kind_ty.is_integral() || self_ty.is_ty_var()) {
+            return;
+        }
+
+        // Check that the self kind extends the goal kind. If it does,
+        // then there's nothing else to check.
+        if let Some(closure_kind) = self_ty.to_opt_closure_kind()
+            && let Some(goal_kind) = target_kind_ty.to_opt_closure_kind()
+        {
+            if closure_kind.extends(goal_kind) {
+                candidates.vec.push(AsyncFnKindHelperCandidate);
+            }
+        }
+    }
+
     /// Implements one of the `Fn()` family for a fn pointer.
     fn assemble_fn_pointer_candidates(
         &mut self,
@@ -488,7 +549,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 | ty::Slice(_)
                 | ty::RawPtr(_)
                 | ty::Ref(_, _, _)
-                | ty::Closure(_, _)
+                | ty::Closure(..)
+                | ty::CoroutineClosure(..)
                 | ty::Coroutine(_, _)
                 | ty::CoroutineWitness(..)
                 | ty::Never
@@ -623,7 +685,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 | ty::Ref(..)
                 | ty::FnDef(..)
                 | ty::FnPtr(_)
-                | ty::Closure(_, _)
+                | ty::Closure(..)
+                | ty::CoroutineClosure(..)
                 | ty::Coroutine(..)
                 | ty::Never
                 | ty::Tuple(_)
@@ -1000,6 +1063,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             | ty::Array(..)
             | ty::Slice(_)
             | ty::Closure(..)
+            | ty::CoroutineClosure(..)
             | ty::Coroutine(..)
             | ty::Tuple(_)
             | ty::CoroutineWitness(..) => {
@@ -1076,7 +1140,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             | ty::FnDef(_, _)
             | ty::FnPtr(_)
             | ty::Dynamic(_, _, _)
-            | ty::Closure(_, _)
+            | ty::Closure(..)
+            | ty::CoroutineClosure(..)
             | ty::Coroutine(_, _)
             | ty::CoroutineWitness(..)
             | ty::Never
@@ -1139,6 +1204,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             | ty::Placeholder(..)
             | ty::Dynamic(..)
             | ty::Closure(..)
+            | ty::CoroutineClosure(..)
             | ty::Coroutine(..)
             | ty::CoroutineWitness(..)
             | ty::Never
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 74f388e53a3..c9d06b0f675 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -83,6 +83,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 ImplSource::Builtin(BuiltinImplSource::Misc, vtable_closure)
             }
 
+            AsyncClosureCandidate => {
+                let vtable_closure = self.confirm_async_closure_candidate(obligation)?;
+                ImplSource::Builtin(BuiltinImplSource::Misc, vtable_closure)
+            }
+
+            // No nested obligations or confirmation process. The checks that we do in
+            // candidate assembly are sufficient.
+            AsyncFnKindHelperCandidate => ImplSource::Builtin(BuiltinImplSource::Misc, vec![]),
+
             CoroutineCandidate => {
                 let vtable_coroutine = self.confirm_coroutine_candidate(obligation)?;
                 ImplSource::Builtin(BuiltinImplSource::Misc, vtable_coroutine)
@@ -869,6 +878,49 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         Ok(nested)
     }
 
+    #[instrument(skip(self), level = "debug")]
+    fn confirm_async_closure_candidate(
+        &mut self,
+        obligation: &PolyTraitObligation<'tcx>,
+    ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+        // Okay to skip binder because the args on closure types never
+        // touch bound regions, they just capture the in-scope
+        // type/region parameters.
+        let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
+        let ty::CoroutineClosure(closure_def_id, args) = *self_ty.kind() else {
+            bug!("async closure candidate for non-coroutine-closure {:?}", obligation);
+        };
+
+        let trait_ref = args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| {
+            ty::TraitRef::new(
+                self.tcx(),
+                obligation.predicate.def_id(),
+                [self_ty, sig.tupled_inputs_ty],
+            )
+        });
+
+        let mut nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
+
+        let goal_kind =
+            self.tcx().async_fn_trait_kind_from_def_id(obligation.predicate.def_id()).unwrap();
+        nested.push(obligation.with(
+            self.tcx(),
+            ty::TraitRef::from_lang_item(
+                self.tcx(),
+                LangItem::AsyncFnKindHelper,
+                obligation.cause.span,
+                [
+                    args.as_coroutine_closure().kind_ty(),
+                    Ty::from_closure_kind(self.tcx(), goal_kind),
+                ],
+            ),
+        ));
+
+        debug!(?closure_def_id, ?trait_ref, ?nested, "confirm closure candidate obligations");
+
+        Ok(nested)
+    }
+
     /// In the case of closure types and fn pointers,
     /// we currently treat the input type parameters on the trait as
     /// outputs. This means that when we have a match we have only
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 6a6adcbb680..7f41c73b72f 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -1864,6 +1864,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 ImplCandidate(..)
                 | AutoImplCandidate
                 | ClosureCandidate { .. }
+                | AsyncClosureCandidate
+                | AsyncFnKindHelperCandidate
                 | CoroutineCandidate
                 | FutureCandidate
                 | IteratorCandidate
@@ -1894,6 +1896,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 ImplCandidate(_)
                 | AutoImplCandidate
                 | ClosureCandidate { .. }
+                | AsyncClosureCandidate
+                | AsyncFnKindHelperCandidate
                 | CoroutineCandidate
                 | FutureCandidate
                 | IteratorCandidate
@@ -1930,6 +1934,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 ImplCandidate(..)
                 | AutoImplCandidate
                 | ClosureCandidate { .. }
+                | AsyncClosureCandidate
+                | AsyncFnKindHelperCandidate
                 | CoroutineCandidate
                 | FutureCandidate
                 | IteratorCandidate
@@ -1946,6 +1952,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 ImplCandidate(..)
                 | AutoImplCandidate
                 | ClosureCandidate { .. }
+                | AsyncClosureCandidate
+                | AsyncFnKindHelperCandidate
                 | CoroutineCandidate
                 | FutureCandidate
                 | IteratorCandidate
@@ -2054,6 +2062,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             (
                 ImplCandidate(_)
                 | ClosureCandidate { .. }
+                | AsyncClosureCandidate
+                | AsyncFnKindHelperCandidate
                 | CoroutineCandidate
                 | FutureCandidate
                 | IteratorCandidate
@@ -2066,6 +2076,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 | TraitAliasCandidate,
                 ImplCandidate(_)
                 | ClosureCandidate { .. }
+                | AsyncClosureCandidate
+                | AsyncFnKindHelperCandidate
                 | CoroutineCandidate
                 | FutureCandidate
                 | IteratorCandidate
@@ -2106,6 +2118,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             | ty::CoroutineWitness(..)
             | ty::Array(..)
             | ty::Closure(..)
+            | ty::CoroutineClosure(..)
             | ty::Never
             | ty::Dynamic(_, _, ty::DynStar)
             | ty::Error(_) => {
@@ -2227,6 +2240,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 }
             }
 
+            // FIXME(async_closures): These are never clone, for now.
+            ty::CoroutineClosure(_, _) => None,
+
             ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) => {
                 // Fallback to whatever user-defined impls exist in this case.
                 None
@@ -2305,6 +2321,11 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 t.rebind(vec![ty])
             }
 
+            ty::CoroutineClosure(_, args) => {
+                let ty = self.infcx.shallow_resolve(args.as_coroutine_closure().tupled_upvars_ty());
+                t.rebind(vec![ty])
+            }
+
             ty::Coroutine(_, args) => {
                 let ty = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty());
                 let witness = args.as_coroutine().witness();
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
index d5a37e63d87..89459f377dd 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_match.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs
@@ -79,6 +79,9 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Search<'tcx> {
             ty::Closure(..) => {
                 return ControlFlow::Break(ty);
             }
+            ty::CoroutineClosure(..) => {
+                return ControlFlow::Break(ty);
+            }
             ty::Coroutine(..) | ty::CoroutineWitness(..) => {
                 return ControlFlow::Break(ty);
             }
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 0f8d9c6bf4b..b4f13ee95a6 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -727,6 +727,14 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                     self.out.extend(obligations);
                 }
 
+                ty::CoroutineClosure(did, args) => {
+                    // See the above comments. The same apply to coroutine-closures.
+                    walker.skip_current_subtree();
+                    self.compute(args.as_coroutine_closure().tupled_upvars_ty().into());
+                    let obligations = self.nominal_obligations(did, args);
+                    self.out.extend(obligations);
+                }
+
                 ty::FnPtr(_) => {
                     // let the loop iterate into the argument/return
                     // types appearing in the fn signature
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index af26616831f..0542ef4ecf9 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -101,6 +101,49 @@ fn fn_sig_for_fn_abi<'tcx>(
                 bound_vars,
             )
         }
+        ty::CoroutineClosure(def_id, args) => {
+            let sig = args.as_coroutine_closure().coroutine_closure_sig();
+            let bound_vars = tcx.mk_bound_variable_kinds_from_iter(
+                sig.bound_vars().iter().chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))),
+            );
+            let br = ty::BoundRegion {
+                var: ty::BoundVar::from_usize(bound_vars.len() - 1),
+                kind: ty::BoundRegionKind::BrEnv,
+            };
+            let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br);
+
+            // When this `CoroutineClosure` comes from a `ConstructCoroutineInClosureShim`,
+            // make sure we respect the `target_kind` in that shim.
+            // FIXME(async_closures): This shouldn't be needed, and we should be populating
+            // a separate def-id for these bodies.
+            let mut kind = args.as_coroutine_closure().kind();
+            if let InstanceDef::ConstructCoroutineInClosureShim { target_kind, .. } = instance.def {
+                kind = target_kind;
+            }
+
+            let env_ty =
+                tcx.closure_env_ty(Ty::new_coroutine_closure(tcx, def_id, args), kind, env_region);
+
+            let sig = sig.skip_binder();
+            ty::Binder::bind_with_vars(
+                tcx.mk_fn_sig(
+                    iter::once(env_ty).chain([sig.tupled_inputs_ty]),
+                    sig.to_coroutine_given_kind_and_upvars(
+                        tcx,
+                        args.as_coroutine_closure().parent_args(),
+                        tcx.coroutine_for_closure(def_id),
+                        kind,
+                        env_region,
+                        args.as_coroutine_closure().tupled_upvars_ty(),
+                        args.as_coroutine_closure().coroutine_captures_by_ref_ty(),
+                    ),
+                    sig.c_variadic,
+                    sig.unsafety,
+                    sig.abi,
+                ),
+                bound_vars,
+            )
+        }
         ty::Coroutine(did, args) => {
             let coroutine_kind = tcx.coroutine_kind(did).unwrap();
             let sig = args.as_coroutine().sig();
@@ -112,6 +155,40 @@ fn fn_sig_for_fn_abi<'tcx>(
                 var: ty::BoundVar::from_usize(bound_vars.len() - 1),
                 kind: ty::BoundRegionKind::BrEnv,
             };
+
+            let mut ty = ty;
+            // When this `Closure` comes from a `CoroutineKindShim`,
+            // make sure we respect the `target_kind` in that shim.
+            // FIXME(async_closures): This shouldn't be needed, and we should be populating
+            // a separate def-id for these bodies.
+            if let InstanceDef::CoroutineKindShim { target_kind, .. } = instance.def {
+                // Grab the parent coroutine-closure. It has the same args for the purposes
+                // of substitution, so this will be okay to do.
+                let ty::CoroutineClosure(_, coroutine_closure_args) = *tcx
+                    .instantiate_and_normalize_erasing_regions(
+                        args,
+                        param_env,
+                        tcx.type_of(tcx.parent(did)),
+                    )
+                    .kind()
+                else {
+                    bug!("CoroutineKindShim comes from calling a coroutine-closure");
+                };
+                let coroutine_closure_args = coroutine_closure_args.as_coroutine_closure();
+                ty = tcx.instantiate_bound_regions_with_erased(
+                    coroutine_closure_args.coroutine_closure_sig().map_bound(|sig| {
+                        sig.to_coroutine_given_kind_and_upvars(
+                            tcx,
+                            coroutine_closure_args.parent_args(),
+                            did,
+                            target_kind,
+                            tcx.lifetimes.re_erased,
+                            coroutine_closure_args.tupled_upvars_ty(),
+                            coroutine_closure_args.coroutine_captures_by_ref_ty(),
+                        )
+                    }),
+                );
+            }
             let env_ty = Ty::new_mut_ref(tcx, ty::Region::new_bound(tcx, ty::INNERMOST, br), ty);
 
             let pin_did = tcx.require_lang_item(LangItem::Pin, None);
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 2d76cf994e4..9faad10dd14 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -38,6 +38,7 @@ fn resolve_instance<'tcx>(
                 debug!(" => nontrivial drop glue");
                 match *ty.kind() {
                     ty::Closure(..)
+                    | ty::CoroutineClosure(..)
                     | ty::Coroutine(..)
                     | ty::Tuple(..)
                     | ty::Adt(..)
@@ -215,6 +216,7 @@ fn resolve_associated_item<'tcx>(
                         ty::Coroutine(..)
                         | ty::CoroutineWitness(..)
                         | ty::Closure(..)
+                        | ty::CoroutineClosure(..)
                         | ty::Tuple(..) => {}
                         _ => return Ok(None),
                     };
@@ -281,6 +283,34 @@ fn resolve_associated_item<'tcx>(
                         tcx.item_name(trait_item_id)
                     ),
                 }
+            } else if let Some(target_kind) = tcx.async_fn_trait_kind_from_def_id(trait_ref.def_id)
+            {
+                match *rcvr_args.type_at(0).kind() {
+                    ty::CoroutineClosure(coroutine_closure_def_id, args) => {
+                        // If we're computing `AsyncFnOnce`/`AsyncFnMut` for a by-ref closure,
+                        // or `AsyncFnOnce` for a by-mut closure, then construct a new body that
+                        // has the right return types.
+                        //
+                        // Specifically, `AsyncFnMut` for a by-ref coroutine-closure just needs
+                        // to have its input and output types fixed (`&mut self` and returning
+                        // `i16` coroutine kind).
+                        if target_kind > args.as_coroutine_closure().kind() {
+                            Some(Instance {
+                                def: ty::InstanceDef::ConstructCoroutineInClosureShim {
+                                    coroutine_closure_def_id,
+                                    target_kind,
+                                },
+                                args,
+                            })
+                        } else {
+                            Some(Instance::new(coroutine_closure_def_id, args))
+                        }
+                    }
+                    _ => bug!(
+                        "no built-in definition for `{trait_ref}::{}` for non-lending-closure type",
+                        tcx.item_name(trait_item_id)
+                    ),
+                }
             } else {
                 Instance::try_resolve_item_for_coroutine(tcx, trait_item_id, trait_id, rcvr_args)
             }
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 2fc4bfd4aa3..f20ded355b1 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -328,6 +328,17 @@ fn layout_of_uncached<'tcx>(
             )?
         }
 
+        ty::CoroutineClosure(_, args) => {
+            let tys = args.as_coroutine_closure().upvar_tys();
+            univariant(
+                &tys.iter()
+                    .map(|ty| Ok(cx.layout_of(ty)?.layout))
+                    .try_collect::<IndexVec<_, _>>()?,
+                &ReprOptions::default(),
+                StructKind::AlwaysSized,
+            )?
+        }
+
         ty::Tuple(tys) => {
             let kind =
                 if tys.len() == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized };
diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs
index 08e5476ae43..7b3d2ab22cf 100644
--- a/compiler/rustc_ty_utils/src/needs_drop.rs
+++ b/compiler/rustc_ty_utils/src/needs_drop.rs
@@ -172,6 +172,12 @@ where
                         }
                     }
 
+                    ty::CoroutineClosure(_, args) => {
+                        for upvar in args.as_coroutine_closure().upvar_tys() {
+                            queue_type(self, upvar);
+                        }
+                    }
+
                     // Check for a `Drop` impl and whether this is a union or
                     // `ManuallyDrop`. If it's a struct or enum without a `Drop`
                     // impl then check whether the field types need `Drop`.
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 2158aacab03..60b1bbe8c2a 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -18,7 +18,9 @@ fn sized_constraint_for_ty<'tcx>(
 
     let result = match ty.kind() {
         Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..)
-        | FnPtr(_) | Array(..) | Closure(..) | Coroutine(..) | Never => vec![],
+        | FnPtr(_) | Array(..) | Closure(..) | CoroutineClosure(..) | Coroutine(..) | Never => {
+            vec![]
+        }
 
         Str | Dynamic(..) | Slice(_) | Foreign(..) | Error(_) | CoroutineWitness(..) => {
             // these are never sized - return the target type
diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs
index 859000fb6cb..a4fe572067b 100644
--- a/compiler/rustc_type_ir/src/ty_kind.rs
+++ b/compiler/rustc_type_ir/src/ty_kind.rs
@@ -202,6 +202,13 @@ pub enum TyKind<I: Interner> {
     /// `ClosureArgs` for more details.
     Closure(I::DefId, I::GenericArgs),
 
+    /// The anonymous type of a closure. Used to represent the type of `async |a| a`.
+    ///
+    /// Coroutine-closure args contain both the - potentially substituted - generic
+    /// parameters of its parent and some synthetic parameters. See the documentation
+    /// for `CoroutineClosureArgs` for more details.
+    CoroutineClosure(I::DefId, I::GenericArgs),
+
     /// The anonymous type of a coroutine. Used to represent the type of
     /// `|a| yield a`.
     ///
@@ -317,16 +324,17 @@ const fn tykind_discriminant<I: Interner>(value: &TyKind<I>) -> usize {
         FnPtr(_) => 13,
         Dynamic(..) => 14,
         Closure(_, _) => 15,
-        Coroutine(_, _) => 16,
-        CoroutineWitness(_, _) => 17,
-        Never => 18,
-        Tuple(_) => 19,
-        Alias(_, _) => 20,
-        Param(_) => 21,
-        Bound(_, _) => 22,
-        Placeholder(_) => 23,
-        Infer(_) => 24,
-        Error(_) => 25,
+        CoroutineClosure(_, _) => 16,
+        Coroutine(_, _) => 17,
+        CoroutineWitness(_, _) => 18,
+        Never => 19,
+        Tuple(_) => 20,
+        Alias(_, _) => 21,
+        Param(_) => 22,
+        Bound(_, _) => 23,
+        Placeholder(_) => 24,
+        Infer(_) => 25,
+        Error(_) => 26,
     }
 }
 
@@ -356,6 +364,7 @@ impl<I: Interner> PartialEq for TyKind<I> {
                 a_p == b_p && a_r == b_r && a_repr == b_repr
             }
             (Closure(a_d, a_s), Closure(b_d, b_s)) => a_d == b_d && a_s == b_s,
+            (CoroutineClosure(a_d, a_s), CoroutineClosure(b_d, b_s)) => a_d == b_d && a_s == b_s,
             (Coroutine(a_d, a_s), Coroutine(b_d, b_s)) => a_d == b_d && a_s == b_s,
             (CoroutineWitness(a_d, a_s), CoroutineWitness(b_d, b_s)) => a_d == b_d && a_s == b_s,
             (Tuple(a_t), Tuple(b_t)) => a_t == b_t,
@@ -430,6 +439,9 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
                 }
             },
             Closure(d, s) => f.debug_tuple("Closure").field(d).field(&this.wrap(s)).finish(),
+            CoroutineClosure(d, s) => {
+                f.debug_tuple("CoroutineClosure").field(d).field(&this.wrap(s)).finish()
+            }
             Coroutine(d, s) => f.debug_tuple("Coroutine").field(d).field(&this.wrap(s)).finish(),
             CoroutineWitness(d, s) => {
                 f.debug_tuple("CoroutineWitness").field(d).field(&this.wrap(s)).finish()
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 43124535ab5..6ea80c8d42f 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -2749,13 +2749,13 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -
 #[doc(alias = "memcpy")]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_allowed_through_unstable_modules]
-#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
+#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
 #[inline(always)]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 #[rustc_diagnostic_item = "ptr_copy_nonoverlapping"]
 pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
     extern "rust-intrinsic" {
-        #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
+        #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
         #[rustc_nounwind]
         pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
     }
@@ -2845,13 +2845,13 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
 #[doc(alias = "memmove")]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_allowed_through_unstable_modules]
-#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
+#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
 #[inline(always)]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 #[rustc_diagnostic_item = "ptr_copy"]
 pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
     extern "rust-intrinsic" {
-        #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
+        #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
         #[rustc_nounwind]
         fn copy<T>(src: *const T, dst: *mut T, count: usize);
     }
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index a3279dcafef..09d589f7cd8 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -135,6 +135,7 @@
 #![feature(const_hint_assert_unchecked)]
 #![feature(const_index_range_slice_index)]
 #![feature(const_int_unchecked_arith)]
+#![feature(const_intrinsic_copy)]
 #![feature(const_intrinsic_forget)]
 #![feature(const_ipv4)]
 #![feature(const_ipv6)]
diff --git a/library/core/src/ops/async_function.rs b/library/core/src/ops/async_function.rs
index 965873f163e..efbe9d164c3 100644
--- a/library/core/src/ops/async_function.rs
+++ b/library/core/src/ops/async_function.rs
@@ -106,3 +106,28 @@ mod impls {
         }
     }
 }
+
+mod internal_implementation_detail {
+    /// A helper trait that is used to enforce that the `ClosureKind` of a goal
+    /// is within the capabilities of a `CoroutineClosure`, and which allows us
+    /// to delay the projection of the tupled upvar types until after upvar
+    /// analysis is complete.
+    ///
+    /// The `Self` type is expected to be the `kind_ty` of the coroutine-closure,
+    /// and thus either `?0` or `i8`/`i16`/`i32` (see docs for `ClosureKind`
+    /// for an explanation of that). The `GoalKind` is also the same type, but
+    /// representing the kind of the trait that the closure is being called with.
+    #[cfg_attr(not(bootstrap), lang = "async_fn_kind_helper")]
+    trait AsyncFnKindHelper<GoalKind> {
+        // Projects a set of closure inputs (arguments), a region, and a set of upvars
+        // (by move and by ref) to the upvars that we expect the coroutine to have
+        // according to the `GoalKind` parameter above.
+        //
+        // The `Upvars` parameter should be the upvars of the parent coroutine-closure,
+        // and the `BorrowedUpvarsAsFnPtr` will be a function pointer that has the shape
+        // `for<'env> fn() -> (&'env T, ...)`. This allows us to represent the binder
+        // of the closure's self-capture, and these upvar types will be instantiated with
+        // the `'closure_env` region provided to the associated type.
+        type Upvars<'closure_env, Inputs, Upvars, BorrowedUpvarsAsFnPtr>;
+    }
+}
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index f3ceadee24c..1d5d683fa16 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -1284,7 +1284,7 @@ impl<T: ?Sized> *const T {
     /// See [`ptr::copy`] for safety concerns and examples.
     ///
     /// [`ptr::copy`]: crate::ptr::copy()
-    #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
+    #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[inline]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
@@ -1304,7 +1304,7 @@ impl<T: ?Sized> *const T {
     /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples.
     ///
     /// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping()
-    #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
+    #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[inline]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index dce7e035fc7..bc05b5b07de 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -1176,7 +1176,6 @@ pub const unsafe fn replace<T>(dst: *mut T, mut src: T) -> T {
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")]
-#[rustc_allow_const_fn_unstable(const_mut_refs, const_maybe_uninit_as_mut_ptr)]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 #[rustc_diagnostic_item = "ptr_read"]
 pub const unsafe fn read<T>(src: *const T) -> T {
@@ -1294,7 +1293,11 @@ pub const unsafe fn read<T>(src: *const T) -> T {
 #[inline]
 #[stable(feature = "ptr_unaligned", since = "1.17.0")]
 #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")]
-#[rustc_allow_const_fn_unstable(const_mut_refs, const_maybe_uninit_as_mut_ptr)]
+#[rustc_allow_const_fn_unstable(
+    const_mut_refs,
+    const_maybe_uninit_as_mut_ptr,
+    const_intrinsic_copy
+)]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 #[rustc_diagnostic_item = "ptr_read_unaligned"]
 pub const unsafe fn read_unaligned<T>(src: *const T) -> T {
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 3e47c4f440a..376673d67c1 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -1385,7 +1385,7 @@ impl<T: ?Sized> *mut T {
     /// See [`ptr::copy`] for safety concerns and examples.
     ///
     /// [`ptr::copy`]: crate::ptr::copy()
-    #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
+    #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[inline(always)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
@@ -1405,7 +1405,7 @@ impl<T: ?Sized> *mut T {
     /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples.
     ///
     /// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping()
-    #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
+    #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[inline(always)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
@@ -1425,7 +1425,7 @@ impl<T: ?Sized> *mut T {
     /// See [`ptr::copy`] for safety concerns and examples.
     ///
     /// [`ptr::copy`]: crate::ptr::copy()
-    #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
+    #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[inline(always)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
@@ -1445,7 +1445,7 @@ impl<T: ?Sized> *mut T {
     /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples.
     ///
     /// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping()
-    #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
+    #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[inline(always)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 9a3b477c2d1..15298e1c816 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -14,6 +14,7 @@
 #![feature(const_cell_into_inner)]
 #![feature(const_hash)]
 #![feature(const_heap)]
+#![feature(const_intrinsic_copy)]
 #![feature(const_maybe_uninit_as_mut_ptr)]
 #![feature(const_nonnull_new)]
 #![feature(const_pointer_is_aligned)]
diff --git a/library/core/tests/macros.rs b/library/core/tests/macros.rs
index eb886def164..09994fbcbdb 100644
--- a/library/core/tests/macros.rs
+++ b/library/core/tests/macros.rs
@@ -1,3 +1,4 @@
+#[allow(dead_code)]
 trait Trait {
     fn blah(&self);
 }
diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs
index 52a08cad911..9255c3abc8a 100644
--- a/library/proc_macro/src/bridge/client.rs
+++ b/library/proc_macro/src/bridge/client.rs
@@ -3,6 +3,7 @@
 use super::*;
 
 use std::marker::PhantomData;
+use std::sync::atomic::AtomicU32;
 
 macro_rules! define_handles {
     (
@@ -12,8 +13,8 @@ macro_rules! define_handles {
         #[repr(C)]
         #[allow(non_snake_case)]
         pub struct HandleCounters {
-            $($oty: AtomicUsize,)*
-            $($ity: AtomicUsize,)*
+            $($oty: AtomicU32,)*
+            $($ity: AtomicU32,)*
         }
 
         impl HandleCounters {
@@ -21,8 +22,8 @@ macro_rules! define_handles {
             // a wrapper `fn` pointer, once `const fn` can reference `static`s.
             extern "C" fn get() -> &'static Self {
                 static COUNTERS: HandleCounters = HandleCounters {
-                    $($oty: AtomicUsize::new(1),)*
-                    $($ity: AtomicUsize::new(1),)*
+                    $($oty: AtomicU32::new(1),)*
+                    $($ity: AtomicU32::new(1),)*
                 };
                 &COUNTERS
             }
diff --git a/library/proc_macro/src/bridge/handle.rs b/library/proc_macro/src/bridge/handle.rs
index 00954107b77..b3a76306997 100644
--- a/library/proc_macro/src/bridge/handle.rs
+++ b/library/proc_macro/src/bridge/handle.rs
@@ -4,7 +4,7 @@ use std::collections::BTreeMap;
 use std::hash::Hash;
 use std::num::NonZeroU32;
 use std::ops::{Index, IndexMut};
-use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::atomic::{AtomicU32, Ordering};
 
 use super::fxhash::FxHashMap;
 
@@ -13,12 +13,12 @@ pub(super) type Handle = NonZeroU32;
 /// A store that associates values of type `T` with numeric handles. A value can
 /// be looked up using its handle.
 pub(super) struct OwnedStore<T: 'static> {
-    counter: &'static AtomicUsize,
+    counter: &'static AtomicU32,
     data: BTreeMap<Handle, T>,
 }
 
 impl<T> OwnedStore<T> {
-    pub(super) fn new(counter: &'static AtomicUsize) -> Self {
+    pub(super) fn new(counter: &'static AtomicU32) -> Self {
         // Ensure the handle counter isn't 0, which would panic later,
         // when `NonZeroU32::new` (aka `Handle::new`) is called in `alloc`.
         assert_ne!(counter.load(Ordering::SeqCst), 0);
@@ -30,7 +30,7 @@ impl<T> OwnedStore<T> {
 impl<T> OwnedStore<T> {
     pub(super) fn alloc(&mut self, x: T) -> Handle {
         let counter = self.counter.fetch_add(1, Ordering::SeqCst);
-        let handle = Handle::new(counter as u32).expect("`proc_macro` handle counter overflowed");
+        let handle = Handle::new(counter).expect("`proc_macro` handle counter overflowed");
         assert!(self.data.insert(handle, x).is_none());
         handle
     }
@@ -60,7 +60,7 @@ pub(super) struct InternedStore<T: 'static> {
 }
 
 impl<T: Copy + Eq + Hash> InternedStore<T> {
-    pub(super) fn new(counter: &'static AtomicUsize) -> Self {
+    pub(super) fn new(counter: &'static AtomicU32) -> Self {
         InternedStore { owned: OwnedStore::new(counter), interner: FxHashMap::default() }
     }
 
diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs
index 75bf3329786..55e24b6491c 100644
--- a/library/proc_macro/src/bridge/mod.rs
+++ b/library/proc_macro/src/bridge/mod.rs
@@ -16,7 +16,6 @@ use std::mem;
 use std::ops::Bound;
 use std::ops::Range;
 use std::panic;
-use std::sync::atomic::AtomicUsize;
 use std::sync::Once;
 use std::thread;
 
diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
index 851832a377c..01f83ecb414 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -59,12 +59,14 @@ cfg_if::cfg_if! {
 
 /// A trait for viewing representations from std types
 #[doc(hidden)]
+#[allow(dead_code)] // not used on all platforms
 pub trait AsInner<Inner: ?Sized> {
     fn as_inner(&self) -> &Inner;
 }
 
 /// A trait for viewing representations from std types
 #[doc(hidden)]
+#[allow(dead_code)] // not used on all platforms
 pub trait AsInnerMut<Inner: ?Sized> {
     fn as_inner_mut(&mut self) -> &mut Inner;
 }
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index ddbe18ab838..73f29d6bb6f 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -97,6 +97,20 @@ impl Std {
             is_for_mir_opt_tests: false,
         }
     }
+
+    fn copy_extra_objects(
+        &self,
+        builder: &Builder<'_>,
+        compiler: &Compiler,
+        target: TargetSelection,
+    ) -> Vec<(PathBuf, DependencyType)> {
+        let mut deps = Vec::new();
+        if !self.is_for_mir_opt_tests {
+            deps.extend(copy_third_party_objects(builder, &compiler, target));
+            deps.extend(copy_self_contained_objects(builder, &compiler, target));
+        }
+        deps
+    }
 }
 
 impl Step for Std {
@@ -159,8 +173,7 @@ impl Step for Std {
         {
             builder.info("WARNING: Using a potentially old libstd. This may not behave well.");
 
-            copy_third_party_objects(builder, &compiler, target);
-            copy_self_contained_objects(builder, &compiler, target);
+            self.copy_extra_objects(builder, &compiler, target);
 
             builder.ensure(StdLink::from_std(self, compiler));
             return;
@@ -193,15 +206,13 @@ impl Step for Std {
 
             // Even if we're not building std this stage, the new sysroot must
             // still contain the third party objects needed by various targets.
-            copy_third_party_objects(builder, &compiler, target);
-            copy_self_contained_objects(builder, &compiler, target);
+            self.copy_extra_objects(builder, &compiler, target);
 
             builder.ensure(StdLink::from_std(self, compiler_to_use));
             return;
         }
 
-        target_deps.extend(copy_third_party_objects(builder, &compiler, target));
-        target_deps.extend(copy_self_contained_objects(builder, &compiler, target));
+        target_deps.extend(self.copy_extra_objects(builder, &compiler, target));
 
         // The LLD wrappers and `rust-lld` are self-contained linking components that can be
         // necessary to link the stdlib on some targets. We'll also need to copy these binaries to
@@ -222,10 +233,13 @@ impl Step for Std {
             }
         }
 
+        // We build a sysroot for mir-opt tests using the same trick that Miri does: A check build
+        // with -Zalways-encode-mir. This frees us from the need to have a target linker, and the
+        // fact that this is a check build integrates nicely with run_cargo.
         let mut cargo = if self.is_for_mir_opt_tests {
-            let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "rustc");
-            cargo.arg("-p").arg("std").arg("--crate-type=lib");
-            std_cargo(builder, target, compiler.stage, &mut cargo);
+            let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "check");
+            cargo.rustflag("-Zalways-encode-mir");
+            cargo.arg("--manifest-path").arg(builder.src.join("library/sysroot/Cargo.toml"));
             cargo
         } else {
             let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "build");
@@ -257,7 +271,7 @@ impl Step for Std {
             vec![],
             &libstd_stamp(builder, compiler, target),
             target_deps,
-            false,
+            self.is_for_mir_opt_tests, // is_check
             false,
         );
 
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 04728e2e00d..baf1b5a4a1a 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -25,7 +25,6 @@ use crate::core::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
 use crate::core::config::flags::get_completion;
 use crate::core::config::flags::Subcommand;
 use crate::core::config::TargetSelection;
-use crate::utils;
 use crate::utils::cache::{Interned, INTERNER};
 use crate::utils::exec::BootstrapCommand;
 use crate::utils::helpers::{
@@ -38,23 +37,6 @@ use crate::{envify, CLang, DocTests, GitRepo, Mode};
 
 const ADB_TEST_DIR: &str = "/data/local/tmp/work";
 
-// mir-opt tests have different variants depending on whether a target is 32bit or 64bit, and
-// blessing them requires blessing with each target. To aid developers, when blessing the mir-opt
-// test suite the corresponding target of the opposite pointer size is also blessed.
-//
-// This array serves as the known mappings between 32bit and 64bit targets. If you're developing on
-// a target where a target with the opposite pointer size exists, feel free to add it here.
-const MIR_OPT_BLESS_TARGET_MAPPING: &[(&str, &str)] = &[
-    // (32bit, 64bit)
-    ("i686-unknown-linux-gnu", "x86_64-unknown-linux-gnu"),
-    ("i686-unknown-linux-musl", "x86_64-unknown-linux-musl"),
-    ("i686-pc-windows-msvc", "x86_64-pc-windows-msvc"),
-    ("i686-pc-windows-gnu", "x86_64-pc-windows-gnu"),
-    // ARM Macs don't have a corresponding 32-bit target that they can (easily)
-    // build for, so there is no entry for "aarch64-apple-darwin" here.
-    // Likewise, i686 for macOS is no longer possible to build.
-];
-
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct CrateBootstrap {
     path: Interned<PathBuf>,
@@ -1487,46 +1469,18 @@ impl Step for MirOpt {
             })
         };
 
-        // We use custom logic to bless the mir-opt suite: mir-opt tests have multiple variants
-        // (32bit vs 64bit, and panic=abort vs panic=unwind), and all of them needs to be blessed.
-        // When blessing, we try best-effort to also bless the other variants, to aid developers.
         if builder.config.cmd.bless() {
-            let targets = MIR_OPT_BLESS_TARGET_MAPPING
-                .iter()
-                .filter(|(target_32bit, target_64bit)| {
-                    *target_32bit == &*self.target.triple || *target_64bit == &*self.target.triple
-                })
-                .next()
-                .map(|(target_32bit, target_64bit)| {
-                    let target_32bit = TargetSelection::from_user(target_32bit);
-                    let target_64bit = TargetSelection::from_user(target_64bit);
-
-                    // Running compiletest requires a C compiler to be available, but it might not
-                    // have been detected by bootstrap if the target we're testing wasn't in the
-                    // --target flags.
-                    if !builder.cc.borrow().contains_key(&target_32bit) {
-                        utils::cc_detect::find_target(builder, target_32bit);
-                    }
-                    if !builder.cc.borrow().contains_key(&target_64bit) {
-                        utils::cc_detect::find_target(builder, target_64bit);
-                    }
+            // All that we really need to do is cover all combinations of 32/64-bit and unwind/abort,
+            // but while we're at it we might as well flex our cross-compilation support. This
+            // selection covers all our tier 1 operating systems and architectures using only tier
+            // 1 targets.
 
-                    vec![target_32bit, target_64bit]
-                })
-                .unwrap_or_else(|| {
-                    eprintln!(
-                        "\
-Note that not all variants of mir-opt tests are going to be blessed, as no mapping between
-a 32bit and a 64bit target was found for {target}.
-You can add that mapping by changing MIR_OPT_BLESS_TARGET_MAPPING in src/bootstrap/test.rs",
-                        target = self.target,
-                    );
-                    vec![self.target]
-                });
-
-            for target in targets {
-                run(target);
+            for target in ["aarch64-unknown-linux-gnu", "i686-pc-windows-msvc"] {
+                run(TargetSelection::from_user(target));
+            }
 
+            for target in ["x86_64-apple-darwin", "i686-unknown-linux-musl"] {
+                let target = TargetSelection::from_user(target);
                 let panic_abort_target = builder.ensure(MirOptPanicAbortSyntheticTarget {
                     compiler: self.compiler,
                     base: target,
@@ -1616,27 +1570,27 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
                 .ensure(dist::DebuggerScripts { sysroot: builder.sysroot(compiler), host: target });
         }
 
-        if suite == "mir-opt" {
-            builder.ensure(compile::Std::new_for_mir_opt_tests(compiler, target));
-        } else {
-            builder.ensure(compile::Std::new(compiler, target));
-        }
+        // Also provide `rust_test_helpers` for the host.
+        builder.ensure(TestHelpers { target: compiler.host });
 
         // ensure that `libproc_macro` is available on the host.
         builder.ensure(compile::Std::new(compiler, compiler.host));
 
-        // Also provide `rust_test_helpers` for the host.
-        builder.ensure(TestHelpers { target: compiler.host });
-
         // As well as the target, except for plain wasm32, which can't build it
         if suite != "mir-opt" && !target.contains("wasm") && !target.contains("emscripten") {
             builder.ensure(TestHelpers { target });
         }
 
-        builder.ensure(RemoteCopyLibs { compiler, target });
-
         let mut cmd = builder.tool_cmd(Tool::Compiletest);
 
+        if suite == "mir-opt" {
+            builder.ensure(compile::Std::new_for_mir_opt_tests(compiler, target));
+        } else {
+            builder.ensure(compile::Std::new(compiler, target));
+        }
+
+        builder.ensure(RemoteCopyLibs { compiler, target });
+
         // compiletest currently has... a lot of arguments, so let's just pass all
         // of them!
 
@@ -1745,11 +1699,13 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
         flags.push(format!("-Cdebuginfo={}", builder.config.rust_debuginfo_level_tests));
         flags.extend(builder.config.cmd.rustc_args().iter().map(|s| s.to_string()));
 
-        if let Some(linker) = builder.linker(target) {
-            cmd.arg("--target-linker").arg(linker);
-        }
-        if let Some(linker) = builder.linker(compiler.host) {
-            cmd.arg("--host-linker").arg(linker);
+        if suite != "mir-opt" {
+            if let Some(linker) = builder.linker(target) {
+                cmd.arg("--target-linker").arg(linker);
+            }
+            if let Some(linker) = builder.linker(compiler.host) {
+                cmd.arg("--host-linker").arg(linker);
+            }
         }
 
         let mut hostflags = flags.clone();
@@ -1936,15 +1892,17 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
             cmd.arg("--remote-test-client").arg(builder.tool_exe(Tool::RemoteTestClient));
         }
 
-        // Running a C compiler on MSVC requires a few env vars to be set, to be
-        // sure to set them here.
-        //
-        // Note that if we encounter `PATH` we make sure to append to our own `PATH`
-        // rather than stomp over it.
-        if !builder.config.dry_run() && target.is_msvc() {
-            for &(ref k, ref v) in builder.cc.borrow()[&target].env() {
-                if k != "PATH" {
-                    cmd.env(k, v);
+        if suite != "mir-opt" {
+            // Running a C compiler on MSVC requires a few env vars to be set, to be
+            // sure to set them here.
+            //
+            // Note that if we encounter `PATH` we make sure to append to our own `PATH`
+            // rather than stomp over it.
+            if !builder.config.dry_run() && target.is_msvc() {
+                for &(ref k, ref v) in builder.cc.borrow()[&target].env() {
+                    if k != "PATH" {
+                        cmd.env(k, v);
+                    }
                 }
             }
         }
diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs
index dac8393de6b..4bb8ed2fa67 100644
--- a/src/bootstrap/src/core/builder.rs
+++ b/src/bootstrap/src/core/builder.rs
@@ -1646,76 +1646,12 @@ impl<'a> Builder<'a> {
             cargo.env("RUSTC_WRAPPER_REAL", existing_wrapper);
         }
 
-        // Dealing with rpath here is a little special, so let's go into some
-        // detail. First off, `-rpath` is a linker option on Unix platforms
-        // which adds to the runtime dynamic loader path when looking for
-        // dynamic libraries. We use this by default on Unix platforms to ensure
-        // that our nightlies behave the same on Windows, that is they work out
-        // of the box. This can be disabled by setting `rpath = false` in `[rust]`
-        // table of `config.toml`
-        //
-        // Ok, so the astute might be wondering "why isn't `-C rpath` used
-        // here?" and that is indeed a good question to ask. This codegen
-        // option is the compiler's current interface to generating an rpath.
-        // Unfortunately it doesn't quite suffice for us. The flag currently
-        // takes no value as an argument, so the compiler calculates what it
-        // should pass to the linker as `-rpath`. This unfortunately is based on
-        // the **compile time** directory structure which when building with
-        // Cargo will be very different than the runtime directory structure.
-        //
-        // All that's a really long winded way of saying that if we use
-        // `-Crpath` then the executables generated have the wrong rpath of
-        // something like `$ORIGIN/deps` when in fact the way we distribute
-        // rustc requires the rpath to be `$ORIGIN/../lib`.
-        //
-        // So, all in all, to set up the correct rpath we pass the linker
-        // argument manually via `-C link-args=-Wl,-rpath,...`. Plus isn't it
-        // fun to pass a flag to a tool to pass a flag to pass a flag to a tool
-        // to change a flag in a binary?
-        if self.config.rpath_enabled(target) && helpers::use_host_linker(target) {
-            let libdir = self.sysroot_libdir_relative(compiler).to_str().unwrap();
-            let rpath = if target.contains("apple") {
-                // Note that we need to take one extra step on macOS to also pass
-                // `-Wl,-instal_name,@rpath/...` to get things to work right. To
-                // do that we pass a weird flag to the compiler to get it to do
-                // so. Note that this is definitely a hack, and we should likely
-                // flesh out rpath support more fully in the future.
-                rustflags.arg("-Zosx-rpath-install-name");
-                Some(format!("-Wl,-rpath,@loader_path/../{libdir}"))
-            } else if !target.is_windows() && !target.contains("aix") && !target.contains("xous") {
-                rustflags.arg("-Clink-args=-Wl,-z,origin");
-                Some(format!("-Wl,-rpath,$ORIGIN/../{libdir}"))
-            } else {
-                None
-            };
-            if let Some(rpath) = rpath {
-                rustflags.arg(&format!("-Clink-args={rpath}"));
-            }
-        }
-
         cargo.env(profile_var("STRIP"), self.config.rust_strip.to_string());
 
         if let Some(stack_protector) = &self.config.rust_stack_protector {
             rustflags.arg(&format!("-Zstack-protector={stack_protector}"));
         }
 
-        for arg in linker_args(self, compiler.host, LldThreads::Yes) {
-            hostflags.arg(&arg);
-        }
-
-        if let Some(target_linker) = self.linker(target) {
-            let target = crate::envify(&target.triple);
-            cargo.env(&format!("CARGO_TARGET_{target}_LINKER"), target_linker);
-        }
-        // We want to set -Clinker using Cargo, therefore we only call `linker_flags` and not
-        // `linker_args` here.
-        for flag in linker_flags(self, target, LldThreads::Yes) {
-            rustflags.arg(&flag);
-        }
-        for arg in linker_args(self, target, LldThreads::Yes) {
-            rustdocflags.arg(&arg);
-        }
-
         if !(["build", "check", "clippy", "fix", "rustc"].contains(&cmd)) && want_rustdoc {
             cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(compiler));
         }
@@ -1731,10 +1667,6 @@ impl<'a> Builder<'a> {
         if let Some(opt_level) = &self.config.rust_optimize.get_opt_level() {
             cargo.env(profile_var("OPT_LEVEL"), opt_level);
         }
-        if !self.config.dry_run() && self.cc.borrow()[&target].args().iter().any(|arg| arg == "-gz")
-        {
-            rustflags.arg("-Clink-arg=-gz");
-        }
         cargo.env(
             profile_var("DEBUG_ASSERTIONS"),
             if mode == Mode::Std {
@@ -1940,55 +1872,15 @@ impl<'a> Builder<'a> {
             rustflags.arg("-Wrustc::internal");
         }
 
-        // Throughout the build Cargo can execute a number of build scripts
-        // compiling C/C++ code and we need to pass compilers, archivers, flags, etc
-        // obtained previously to those build scripts.
-        // Build scripts use either the `cc` crate or `configure/make` so we pass
-        // the options through environment variables that are fetched and understood by both.
-        //
-        // FIXME: the guard against msvc shouldn't need to be here
-        if target.is_msvc() {
-            if let Some(ref cl) = self.config.llvm_clang_cl {
-                cargo.env("CC", cl).env("CXX", cl);
-            }
-        } else {
-            let ccache = self.config.ccache.as_ref();
-            let ccacheify = |s: &Path| {
-                let ccache = match ccache {
-                    Some(ref s) => s,
-                    None => return s.display().to_string(),
-                };
-                // FIXME: the cc-rs crate only recognizes the literal strings
-                // `ccache` and `sccache` when doing caching compilations, so we
-                // mirror that here. It should probably be fixed upstream to
-                // accept a new env var or otherwise work with custom ccache
-                // vars.
-                match &ccache[..] {
-                    "ccache" | "sccache" => format!("{} {}", ccache, s.display()),
-                    _ => s.display().to_string(),
-                }
-            };
-            let triple_underscored = target.triple.replace("-", "_");
-            let cc = ccacheify(&self.cc(target));
-            cargo.env(format!("CC_{triple_underscored}"), &cc);
-
-            let cflags = self.cflags(target, GitRepo::Rustc, CLang::C).join(" ");
-            cargo.env(format!("CFLAGS_{triple_underscored}"), &cflags);
-
-            if let Some(ar) = self.ar(target) {
-                let ranlib = format!("{} s", ar.display());
-                cargo
-                    .env(format!("AR_{triple_underscored}"), ar)
-                    .env(format!("RANLIB_{triple_underscored}"), ranlib);
-            }
-
-            if let Ok(cxx) = self.cxx(target) {
-                let cxx = ccacheify(&cxx);
-                let cxxflags = self.cflags(target, GitRepo::Rustc, CLang::Cxx).join(" ");
-                cargo
-                    .env(format!("CXX_{triple_underscored}"), &cxx)
-                    .env(format!("CXXFLAGS_{triple_underscored}"), cxxflags);
-            }
+        if cmd != "check" {
+            self.configure_linker(
+                compiler,
+                target,
+                &mut cargo,
+                &mut rustflags,
+                &mut rustdocflags,
+                &mut hostflags,
+            );
         }
 
         // If Control Flow Guard is enabled, pass the `control-flow-guard` flag to rustc
@@ -2142,6 +2034,136 @@ impl<'a> Builder<'a> {
         Cargo { command: cargo, rustflags, rustdocflags, hostflags, allow_features }
     }
 
+    fn configure_linker(
+        &self,
+        compiler: Compiler,
+        target: TargetSelection,
+        cargo: &mut Command,
+        rustflags: &mut Rustflags,
+        rustdocflags: &mut Rustflags,
+        hostflags: &mut HostFlags,
+    ) {
+        // Dealing with rpath here is a little special, so let's go into some
+        // detail. First off, `-rpath` is a linker option on Unix platforms
+        // which adds to the runtime dynamic loader path when looking for
+        // dynamic libraries. We use this by default on Unix platforms to ensure
+        // that our nightlies behave the same on Windows, that is they work out
+        // of the box. This can be disabled by setting `rpath = false` in `[rust]`
+        // table of `config.toml`
+        //
+        // Ok, so the astute might be wondering "why isn't `-C rpath` used
+        // here?" and that is indeed a good question to ask. This codegen
+        // option is the compiler's current interface to generating an rpath.
+        // Unfortunately it doesn't quite suffice for us. The flag currently
+        // takes no value as an argument, so the compiler calculates what it
+        // should pass to the linker as `-rpath`. This unfortunately is based on
+        // the **compile time** directory structure which when building with
+        // Cargo will be very different than the runtime directory structure.
+        //
+        // All that's a really long winded way of saying that if we use
+        // `-Crpath` then the executables generated have the wrong rpath of
+        // something like `$ORIGIN/deps` when in fact the way we distribute
+        // rustc requires the rpath to be `$ORIGIN/../lib`.
+        //
+        // So, all in all, to set up the correct rpath we pass the linker
+        // argument manually via `-C link-args=-Wl,-rpath,...`. Plus isn't it
+        // fun to pass a flag to a tool to pass a flag to pass a flag to a tool
+        // to change a flag in a binary?
+        if self.config.rpath_enabled(target) && helpers::use_host_linker(target) {
+            let libdir = self.sysroot_libdir_relative(compiler).to_str().unwrap();
+            let rpath = if target.contains("apple") {
+                // Note that we need to take one extra step on macOS to also pass
+                // `-Wl,-instal_name,@rpath/...` to get things to work right. To
+                // do that we pass a weird flag to the compiler to get it to do
+                // so. Note that this is definitely a hack, and we should likely
+                // flesh out rpath support more fully in the future.
+                rustflags.arg("-Zosx-rpath-install-name");
+                Some(format!("-Wl,-rpath,@loader_path/../{libdir}"))
+            } else if !target.is_windows() && !target.contains("aix") && !target.contains("xous") {
+                rustflags.arg("-Clink-args=-Wl,-z,origin");
+                Some(format!("-Wl,-rpath,$ORIGIN/../{libdir}"))
+            } else {
+                None
+            };
+            if let Some(rpath) = rpath {
+                rustflags.arg(&format!("-Clink-args={rpath}"));
+            }
+        }
+
+        for arg in linker_args(self, compiler.host, LldThreads::Yes) {
+            hostflags.arg(&arg);
+        }
+
+        if let Some(target_linker) = self.linker(target) {
+            let target = crate::envify(&target.triple);
+            cargo.env(&format!("CARGO_TARGET_{target}_LINKER"), target_linker);
+        }
+        // We want to set -Clinker using Cargo, therefore we only call `linker_flags` and not
+        // `linker_args` here.
+        for flag in linker_flags(self, target, LldThreads::Yes) {
+            rustflags.arg(&flag);
+        }
+        for arg in linker_args(self, target, LldThreads::Yes) {
+            rustdocflags.arg(&arg);
+        }
+
+        if !self.config.dry_run() && self.cc.borrow()[&target].args().iter().any(|arg| arg == "-gz")
+        {
+            rustflags.arg("-Clink-arg=-gz");
+        }
+
+        // Throughout the build Cargo can execute a number of build scripts
+        // compiling C/C++ code and we need to pass compilers, archivers, flags, etc
+        // obtained previously to those build scripts.
+        // Build scripts use either the `cc` crate or `configure/make` so we pass
+        // the options through environment variables that are fetched and understood by both.
+        //
+        // FIXME: the guard against msvc shouldn't need to be here
+        if target.is_msvc() {
+            if let Some(ref cl) = self.config.llvm_clang_cl {
+                cargo.env("CC", cl).env("CXX", cl);
+            }
+        } else {
+            let ccache = self.config.ccache.as_ref();
+            let ccacheify = |s: &Path| {
+                let ccache = match ccache {
+                    Some(ref s) => s,
+                    None => return s.display().to_string(),
+                };
+                // FIXME: the cc-rs crate only recognizes the literal strings
+                // `ccache` and `sccache` when doing caching compilations, so we
+                // mirror that here. It should probably be fixed upstream to
+                // accept a new env var or otherwise work with custom ccache
+                // vars.
+                match &ccache[..] {
+                    "ccache" | "sccache" => format!("{} {}", ccache, s.display()),
+                    _ => s.display().to_string(),
+                }
+            };
+            let triple_underscored = target.triple.replace("-", "_");
+            let cc = ccacheify(&self.cc(target));
+            cargo.env(format!("CC_{triple_underscored}"), &cc);
+
+            let cflags = self.cflags(target, GitRepo::Rustc, CLang::C).join(" ");
+            cargo.env(format!("CFLAGS_{triple_underscored}"), &cflags);
+
+            if let Some(ar) = self.ar(target) {
+                let ranlib = format!("{} s", ar.display());
+                cargo
+                    .env(format!("AR_{triple_underscored}"), ar)
+                    .env(format!("RANLIB_{triple_underscored}"), ranlib);
+            }
+
+            if let Ok(cxx) = self.cxx(target) {
+                let cxx = ccacheify(&cxx);
+                let cxxflags = self.cflags(target, GitRepo::Rustc, CLang::Cxx).join(" ");
+                cargo
+                    .env(format!("CXX_{triple_underscored}"), &cxx)
+                    .env(format!("CXXFLAGS_{triple_underscored}"), cxxflags);
+            }
+        }
+    }
+
     /// Ensure that a given step is built, returning its output. This will
     /// cache the step, so it is safe (and good!) to call this as often as
     /// needed to ensure that all dependencies are built.
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh
index cc0c658aabd..f5c426a717f 100755
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh
@@ -30,7 +30,7 @@ python3 "$X_PY" test --stage 2 src/tools/rustfmt
 # We set the GC interval to the shortest possible value (0 would be off) to increase the chance
 # that bugs which only surface when the GC runs at a specific time are more likely to cause CI to fail.
 # This significantly increases the runtime of our test suite, or we'd do this in PR CI too.
-if [[ -z "${PR_CI_JOB:-}" ]]; then
+if [ -z "${PR_CI_JOB:-}" ]; then
     MIRIFLAGS=-Zmiri-provenance-gc=1 python3 "$X_PY" test --stage 2 src/tools/miri
 else
     python3 "$X_PY" test --stage 2 src/tools/miri
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index 1998b008dc8..1f9307203bc 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -26,6 +26,7 @@
     - [armv4t-none-eabi](platform-support/armv4t-none-eabi.md)
     - [armv5te-none-eabi](platform-support/armv5te-none-eabi.md)
     - [armv7r-none-eabi](platform-support/armv7r-none-eabi.md)
+    - [armv8r-none-eabihf](platform-support/armv8r-none-eabihf.md)
     - [armv6k-nintendo-3ds](platform-support/armv6k-nintendo-3ds.md)
     - [armv7-sony-vita-newlibeabihf](platform-support/armv7-sony-vita-newlibeabihf.md)
     - [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index f648a60b6c4..80d9dc85f16 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -280,6 +280,7 @@ target | std | host | notes
 [`armv7a-none-eabihf`](platform-support/arm-none-eabi.md) | * |  | Bare ARMv7-A, hardfloat
 [`armv7k-apple-watchos`](platform-support/apple-watchos.md) | ✓ |  | ARMv7-A Apple WatchOS
 `armv7s-apple-ios` | ✓ |  | ARMv7-A Apple-A6 Apple iOS
+[`armv8r-none-eabihf`](platform-support/armv8r-none-eabihf.md) | * |  | Bare ARMv8-R, hardfloat
 `avr-unknown-gnu-atmega328` | * |  | AVR. Requires `-Z build-std=core`
 `bpfeb-unknown-none` | * |  | BPF (big endian)
 `bpfel-unknown-none` | * |  | BPF (little endian)
diff --git a/src/doc/rustc/src/platform-support/arm-none-eabi.md b/src/doc/rustc/src/platform-support/arm-none-eabi.md
index 4f76d0d7bbc..6335a6405a1 100644
--- a/src/doc/rustc/src/platform-support/arm-none-eabi.md
+++ b/src/doc/rustc/src/platform-support/arm-none-eabi.md
@@ -13,6 +13,7 @@
 - [{arm,thumb}v4t-none-eabi](armv4t-none-eabi.md)
 - [{arm,thumb}v5te-none-eabi](armv5te-none-eabi.md)
 - armv7a-none-eabihf
+- [armv8r-none-eabihf](armv8r-none-eabihf.md)
 
 Bare-metal target for 32-bit ARM CPUs.
 
diff --git a/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md b/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md
new file mode 100644
index 00000000000..588e5d7c994
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md
@@ -0,0 +1,40 @@
+# `armv8r-none-eabihf`
+
+**Tier: 3**
+
+Bare-metal target for CPUs in the ARMv8-R architecture family, supporting
+dual ARM/Thumb mode, with ARM mode as the default.
+
+Processors in this family include the Arm [Cortex-R52][cortex-r52]
+and [Cortex-R52+][cortex-r52-plus].
+
+See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
+`arm-none-eabi` targets.
+
+[cortex-r52]: https://www.arm.com/products/silicon-ip-cpu/cortex-r/cortex-r52
+[cortex-r52-plus]: https://www.arm.com/products/silicon-ip-cpu/cortex-r/cortex-r52-plus
+
+## Target maintainers
+
+- [Chris Copeland](https://github.com/chrisnc), `chris@chrisnc.net`
+
+## Requirements
+
+The Cortex-R52 family always includes a floating-point unit, so there is no
+non-`hf` version of this target. The floating-point features assumed by this
+target are those of the single-precision-only config of the Cortex-R52, which
+has 16 double-precision registers, accessible as 32 single-precision registers.
+The other variant of Cortex-R52 includes double-precision, 32 double-precision
+registers, and Advanced SIMD (Neon).
+
+The manual refers to this as the "Full Advanced SIMD config". To compile code
+for this variant, use: `-C target-feature=+fp64,+d32,+neon`. See the [Advanced
+SIMD and floating-point support][fpu] section of the Cortex-R52 Processor
+Technical Reference Manual for more details.
+
+[fpu]: https://developer.arm.com/documentation/100026/0104/Advanced-SIMD-and-floating-point-support/About-the-Advanced-SIMD-and-floating-point-support
+
+## Cross-compilation toolchains and C code
+
+This target supports C code compiled with the `arm-none-eabi` target triple and
+`-march=armv8-r` or a suitable `-mcpu` flag.
diff --git a/src/doc/unstable-book/src/compiler-flags/direct-access-external-data.md b/src/doc/unstable-book/src/compiler-flags/direct-access-external-data.md
new file mode 100644
index 00000000000..c72df437960
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/direct-access-external-data.md
@@ -0,0 +1,16 @@
+# `direct_access_external_data`
+
+The tracking issue for this feature is: https://github.com/rust-lang/compiler-team/issues/707
+
+------------------------
+
+Option `-Z direct-access-external-data` controls how to access symbols of
+external data.
+
+Supported values for this option are:
+
+- `yes` - Don't use GOT indirection to reference external data symbols.
+- `no` - Use GOT indirection to reference external data symbols.
+
+If the option is not explicitly specified, different targets have different
+default values.
diff --git a/src/doc/unstable-book/src/library-features/async-fn-traits.md b/src/doc/unstable-book/src/library-features/async-fn-traits.md
new file mode 100644
index 00000000000..e1c3f067e5b
--- /dev/null
+++ b/src/doc/unstable-book/src/library-features/async-fn-traits.md
@@ -0,0 +1,13 @@
+# `async_fn_traits`
+
+See Also: [`fn_traits`](../library-features/fn-traits.md)
+
+----
+
+The `async_fn_traits` feature allows for implementation of the [`AsyncFn*`] traits
+for creating custom closure-like types that return futures.
+
+[`AsyncFn*`]: ../../std/ops/trait.AsyncFn.html
+
+The main difference to the `Fn*` family of traits is that `AsyncFn` can return a future
+that borrows from itself (`FnOnce::Output` has no lifetime parameters, while `AsyncFn::CallFuture` does).
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index bd1d68e7074..3bac71dbc24 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2286,6 +2286,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
         }
 
         ty::Closure(..) => panic!("Closure"),
+        ty::CoroutineClosure(..) => panic!("CoroutineClosure"),
         ty::Coroutine(..) => panic!("Coroutine"),
         ty::Placeholder(..) => panic!("Placeholder"),
         ty::CoroutineWitness(..) => panic!("CoroutineWitness"),
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index a75d9bee304..fe02611b5d4 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -503,6 +503,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
             }
             ty::Alias(..)
             | ty::Closure(..)
+            | ty::CoroutineClosure(..)
             | ty::Coroutine(..)
             | ty::CoroutineWitness(..)
             | ty::Dynamic(..)
diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs
index e73649c7224..6649894f9c2 100644
--- a/src/librustdoc/passes/lint/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs
@@ -156,7 +156,7 @@ impl Translate for BufferEmitter {
 }
 
 impl Emitter for BufferEmitter {
-    fn emit_diagnostic(&mut self, diag: &Diagnostic) {
+    fn emit_diagnostic(&mut self, diag: Diagnostic) {
         let mut buffer = self.buffer.borrow_mut();
 
         let fluent_args = to_fluent_args(diag.args());
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index 1ef8cf7de3c..808fb0c07ea 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -83,6 +83,7 @@ static TARGETS: &[&str] = &[
     "armebv7r-none-eabihf",
     "armv7r-none-eabi",
     "armv7r-none-eabihf",
+    "armv8r-none-eabihf",
     "armv7s-apple-ios",
     "bpfeb-unknown-none",
     "bpfel-unknown-none",
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 8ff54dfcfa0..194cf69ea7e 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -881,6 +881,7 @@ impl TyCoercionStability {
                 | ty::Coroutine(..)
                 | ty::CoroutineWitness(..)
                 | ty::Closure(..)
+                | ty::CoroutineClosure(..)
                 | ty::Never
                 | ty::Tuple(_)
                 | ty::Alias(ty::Projection, _) => Self::Deref,
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index b26ebe5cee3..288df0fd663 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -490,6 +490,9 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                             format!("ClosureKind::Coroutine(CoroutineKind::Coroutine(Movability::{movability:?})")
                         },
                     },
+                    ClosureKind::CoroutineClosure(desugaring) => format!(
+                        "ClosureKind::CoroutineClosure(CoroutineDesugaring::{desugaring:?})"
+                    ),
                 };
 
                 let ret_ty = match fn_decl.output {
diff --git a/src/tools/clippy/tests/ui/author/blocks.stdout b/src/tools/clippy/tests/ui/author/blocks.stdout
index 8c4d71e68f8..579f137f861 100644
--- a/src/tools/clippy/tests/ui/author/blocks.stdout
+++ b/src/tools/clippy/tests/ui/author/blocks.stdout
@@ -40,10 +40,10 @@ if let ExprKind::Block(block, None) = expr.kind
 {
     // report your lint here
 }
-if let ExprKind::Closure { capture_clause: CaptureBy::Value { .. }, fn_decl: fn_decl, body: body_id, closure_kind: ClosureKind::Closure, .. } = expr.kind
+if let ExprKind::Closure { capture_clause: CaptureBy::Value { .. }, fn_decl: fn_decl, body: body_id, closure_kind: ClosureKind::CoroutineClosure(CoroutineDesugaring::Async), .. } = expr.kind
     && let FnRetTy::DefaultReturn(_) = fn_decl.output
     && expr1 = &cx.tcx.hir().body(body_id).value
-    && let ExprKind::Closure { capture_clause: CaptureBy::Value { .. }, fn_decl: fn_decl1, body: body_id1, closure_kind: ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure)), .. } = expr1.kind
+    && let ExprKind::Closure { capture_clause: CaptureBy::Ref, fn_decl: fn_decl1, body: body_id1, closure_kind: ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure)), .. } = expr1.kind
     && let FnRetTy::DefaultReturn(_) = fn_decl1.output
     && expr2 = &cx.tcx.hir().body(body_id1).value
     && let ExprKind::Block(block, None) = expr2.kind
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 8be4def15de..ed1c559e1f6 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -2467,6 +2467,7 @@ impl<'test> TestCx<'test> {
                     "-Zvalidate-mir",
                     "-Zlint-mir",
                     "-Zdump-mir-exclude-pass-number",
+                    "--crate-type=rlib",
                 ]);
                 if let Some(pass) = &self.props.mir_unit_test {
                     rustc.args(&["-Zmir-opt-level=0", &format!("-Zmir-enable-passes=+{}", pass)]);
diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs
index 74ff6ed4e0a..46f96a715f1 100644
--- a/src/tools/miri/src/borrow_tracker/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/mod.rs
@@ -383,7 +383,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             // will never cause UB on the pointer itself.
             let (_, _, kind) = this.get_alloc_info(*alloc_id);
             if matches!(kind, AllocKind::LiveData) {
-                let alloc_extra = this.get_alloc_extra(*alloc_id).unwrap();
+                let alloc_extra = this.get_alloc_extra(*alloc_id)?; // can still fail for `extern static`
                 let alloc_borrow_tracker = &alloc_extra.borrow_tracker.as_ref().unwrap();
                 alloc_borrow_tracker.release_protector(&this.machine, borrow_tracker, *tag)?;
             }
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 946887637ff..40d041c8fdb 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -2,7 +2,7 @@
 //! `Machine` trait.
 
 use std::borrow::Cow;
-use std::cell::{Cell, RefCell};
+use std::cell::RefCell;
 use std::collections::hash_map::Entry;
 use std::fmt;
 use std::path::Path;
@@ -336,20 +336,11 @@ pub struct AllocExtra<'tcx> {
     /// if this allocation is leakable. The backtrace is not
     /// pruned yet; that should be done before printing it.
     pub backtrace: Option<Vec<FrameInfo<'tcx>>>,
-    /// An offset inside this allocation that was deemed aligned even for symbolic alignment checks.
-    /// Invariant: the promised alignment will never be less than the native alignment of this allocation.
-    pub symbolic_alignment: Cell<Option<(Size, Align)>>,
 }
 
 impl VisitProvenance for AllocExtra<'_> {
     fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
-        let AllocExtra {
-            borrow_tracker,
-            data_race,
-            weak_memory,
-            backtrace: _,
-            symbolic_alignment: _,
-        } = self;
+        let AllocExtra { borrow_tracker, data_race, weak_memory, backtrace: _ } = self;
 
         borrow_tracker.visit_provenance(visit);
         data_race.visit_provenance(visit);
@@ -572,6 +563,14 @@ pub struct MiriMachine<'mir, 'tcx> {
     /// that is fixed per stack frame; this lets us have sometimes different results for the
     /// same const while ensuring consistent results within a single call.
     const_cache: RefCell<FxHashMap<(mir::Const<'tcx>, usize), OpTy<'tcx, Provenance>>>,
+
+    /// For each allocation, an offset inside that allocation that was deemed aligned even for
+    /// symbolic alignment checks. This cannot be stored in `AllocExtra` since it needs to be
+    /// tracked for vtables and function allocations as well as regular allocations.
+    ///
+    /// Invariant: the promised alignment will never be less than the native alignment of the
+    /// allocation.
+    pub(crate) symbolic_alignment: RefCell<FxHashMap<AllocId, (Size, Align)>>,
 }
 
 impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
@@ -698,6 +697,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
             collect_leak_backtraces: config.collect_leak_backtraces,
             allocation_spans: RefCell::new(FxHashMap::default()),
             const_cache: RefCell::new(FxHashMap::default()),
+            symbolic_alignment: RefCell::new(FxHashMap::default()),
         }
     }
 
@@ -810,6 +810,7 @@ impl VisitProvenance for MiriMachine<'_, '_> {
             collect_leak_backtraces: _,
             allocation_spans: _,
             const_cache: _,
+            symbolic_alignment: _,
         } = self;
 
         threads.visit_provenance(visit);
@@ -893,9 +894,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
             return None;
         }
         // Let's see which alignment we have been promised for this allocation.
-        let alloc_info = ecx.get_alloc_extra(alloc_id).unwrap(); // cannot fail since the allocation is live
-        let (promised_offset, promised_align) =
-            alloc_info.symbolic_alignment.get().unwrap_or((Size::ZERO, alloc_align));
+        let (promised_offset, promised_align) = ecx
+            .machine
+            .symbolic_alignment
+            .borrow()
+            .get(&alloc_id)
+            .copied()
+            .unwrap_or((Size::ZERO, alloc_align));
         if promised_align < align {
             // Definitely not enough.
             Some(Misalignment { has: promised_align, required: align })
@@ -1132,7 +1137,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
                 data_race: race_alloc,
                 weak_memory: buffer_alloc,
                 backtrace,
-                symbolic_alignment: Cell::new(None),
             },
             |ptr| ecx.global_base_pointer(ptr),
         )?;
diff --git a/src/tools/miri/src/provenance_gc.rs b/src/tools/miri/src/provenance_gc.rs
index ab178f82d9f..347951ce372 100644
--- a/src/tools/miri/src/provenance_gc.rs
+++ b/src/tools/miri/src/provenance_gc.rs
@@ -196,6 +196,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
         let this = self.eval_context_mut();
         let allocs = LiveAllocs { ecx: this, collected: allocs };
         this.machine.allocation_spans.borrow_mut().retain(|id, _| allocs.is_live(*id));
+        this.machine.symbolic_alignment.borrow_mut().retain(|id, _| allocs.is_live(*id));
         this.machine.intptrcast.borrow_mut().remove_unreachable_allocs(&allocs);
         if let Some(borrow_tracker) = &this.machine.borrow_tracker {
             borrow_tracker.borrow_mut().remove_unreachable_allocs(&allocs);
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index a002f2aad05..25654248db4 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -585,17 +585,17 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 }
                 if let Ok((alloc_id, offset, ..)) = this.ptr_try_get_alloc_id(ptr) {
                     let (_size, alloc_align, _kind) = this.get_alloc_info(alloc_id);
-                    // Not `get_alloc_extra_mut`, need to handle read-only allocations!
-                    let alloc_extra = this.get_alloc_extra(alloc_id)?;
                     // If the newly promised alignment is bigger than the native alignment of this
                     // allocation, and bigger than the previously promised alignment, then set it.
                     if align > alloc_align
-                        && !alloc_extra
+                        && !this
+                            .machine
                             .symbolic_alignment
-                            .get()
-                            .is_some_and(|(_, old_align)| align <= old_align)
+                            .get_mut()
+                            .get(&alloc_id)
+                            .is_some_and(|&(_, old_align)| align <= old_align)
                     {
-                        alloc_extra.symbolic_alignment.set(Some((offset, align)));
+                        this.machine.symbolic_alignment.get_mut().insert(alloc_id, (offset, align));
                     }
                 }
             }
diff --git a/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs b/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs
index 0e7c3dbcc04..13f913454dc 100644
--- a/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs
+++ b/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs
@@ -1,4 +1,5 @@
 trait T1 {
+    #[allow(dead_code)]
     fn method1(self: Box<Self>);
 }
 trait T2 {
diff --git a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs
index 648ac07c43e..982f33b0a31 100644
--- a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs
+++ b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs
@@ -2,30 +2,36 @@
 #![allow(incomplete_features)]
 
 trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
+    #[allow(dead_code)]
     fn a(&self) -> i32 {
         10
     }
 
+    #[allow(dead_code)]
     fn z(&self) -> i32 {
         11
     }
 
+    #[allow(dead_code)]
     fn y(&self) -> i32 {
         12
     }
 }
 
 trait Bar: Foo {
+    #[allow(dead_code)]
     fn b(&self) -> i32 {
         20
     }
 
+    #[allow(dead_code)]
     fn w(&self) -> i32 {
         21
     }
 }
 
 trait Baz: Bar {
+    #[allow(dead_code)]
     fn c(&self) -> i32 {
         30
     }
diff --git a/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.rs b/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.rs
new file mode 100644
index 00000000000..44604074982
--- /dev/null
+++ b/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.rs
@@ -0,0 +1,12 @@
+//@compile-flags: -Zmiri-symbolic-alignment-check
+
+extern "C" {
+    static _dispatch_queue_attr_concurrent: [u8; 0];
+}
+
+static DISPATCH_QUEUE_CONCURRENT: &'static [u8; 0] =
+    unsafe { &_dispatch_queue_attr_concurrent };
+
+fn main() {
+    let _val = *DISPATCH_QUEUE_CONCURRENT; //~ERROR: is not supported
+}
diff --git a/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.stderr b/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.stderr
new file mode 100644
index 00000000000..a4249d2e881
--- /dev/null
+++ b/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.stderr
@@ -0,0 +1,14 @@
+error: unsupported operation: `extern` static `_dispatch_queue_attr_concurrent` from crate `issue_miri_3288_ice_symbolic_alignment_extern_static` is not supported by Miri
+  --> $DIR/issue-miri-3288-ice-symbolic-alignment-extern-static.rs:LL:CC
+   |
+LL |     let _val = *DISPATCH_QUEUE_CONCURRENT;
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^ `extern` static `_dispatch_queue_attr_concurrent` from crate `issue_miri_3288_ice_symbolic_alignment_extern_static` is not supported by Miri
+   |
+   = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/issue-miri-3288-ice-symbolic-alignment-extern-static.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/pass/align_offset_symbolic.rs b/src/tools/miri/tests/pass/align_offset_symbolic.rs
index 4df364bac7a..e96f11b1efa 100644
--- a/src/tools/miri/tests/pass/align_offset_symbolic.rs
+++ b/src/tools/miri/tests/pass/align_offset_symbolic.rs
@@ -1,6 +1,8 @@
 //@compile-flags: -Zmiri-symbolic-alignment-check
 #![feature(strict_provenance)]
 
+use std::mem;
+
 fn test_align_to() {
     const N: usize = 4;
     let d = Box::new([0u32; N]);
@@ -68,7 +70,7 @@ fn test_u64_array() {
     #[repr(align(8))]
     struct AlignToU64<T>(T);
 
-    const BYTE_LEN: usize = std::mem::size_of::<[u64; 4]>();
+    const BYTE_LEN: usize = mem::size_of::<[u64; 4]>();
     type Data = AlignToU64<[u8; BYTE_LEN]>;
 
     fn example(data: &Data) {
@@ -101,10 +103,29 @@ fn huge_align() {
     let _ = std::ptr::invalid::<HugeSize>(SIZE).align_offset(SIZE);
 }
 
+// This shows that we cannot store the promised alignment info in `AllocExtra`,
+// since vtables do not have an `AllocExtra`.
+fn vtable() {
+    #[cfg(target_pointer_width = "64")]
+    type TWOPTR = u128;
+    #[cfg(target_pointer_width = "32")]
+    type TWOPTR = u64;
+
+    let ptr: &dyn Send = &0;
+    let parts: (*const (), *const u8) = unsafe { mem::transmute(ptr) };
+    let vtable = parts.1 ;
+    let offset = vtable.align_offset(mem::align_of::<TWOPTR>());
+    let _vtable_aligned = vtable.wrapping_add(offset) as *const [TWOPTR; 0];
+    // FIXME: we can't actually do the access since vtable pointers act like zero-sized allocations.
+    // Enable the next line once https://github.com/rust-lang/rust/issues/117945 is implemented.
+    //let _place = unsafe { &*vtable_aligned };
+}
+
 fn main() {
     test_align_to();
     test_from_utf8();
     test_u64_array();
     test_cstr();
     huge_align();
+    vtable();
 }
diff --git a/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs b/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs
index ccf96b99672..2491bda0917 100644
--- a/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs
+++ b/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs
@@ -9,6 +9,7 @@ trait Foo<T> {
     }
 }
 
+#[allow(dead_code)]
 trait Bar {
     fn bar(&self) {
         println!("Bar!");
diff --git a/src/tools/miri/tests/pass/dyn-upcast.rs b/src/tools/miri/tests/pass/dyn-upcast.rs
index 8432012a9ba..529b9c471d4 100644
--- a/src/tools/miri/tests/pass/dyn-upcast.rs
+++ b/src/tools/miri/tests/pass/dyn-upcast.rs
@@ -383,14 +383,17 @@ fn struct_() {
 
 fn replace_vptr() {
     trait A {
+        #[allow(dead_code)]
         fn foo_a(&self);
     }
 
     trait B {
+        #[allow(dead_code)]
         fn foo_b(&self);
     }
 
     trait C: A + B {
+        #[allow(dead_code)]
         fn foo_c(&self);
     }
 
diff --git a/src/tools/miri/tests/pass/weak_memory/weak.rs b/src/tools/miri/tests/pass/weak_memory/weak.rs
index 4c3be6b3559..e10ccc277f6 100644
--- a/src/tools/miri/tests/pass/weak_memory/weak.rs
+++ b/src/tools/miri/tests/pass/weak_memory/weak.rs
@@ -11,6 +11,7 @@ use std::sync::atomic::Ordering::*;
 use std::sync::atomic::{fence, AtomicUsize};
 use std::thread::spawn;
 
+#[allow(dead_code)]
 #[derive(Copy, Clone)]
 struct EvilSend<T>(pub T);
 
diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs
index 6dc3eac44d4..f0af401d3da 100644
--- a/src/tools/rustfmt/src/parse/session.rs
+++ b/src/tools/rustfmt/src/parse/session.rs
@@ -47,7 +47,7 @@ impl Emitter for SilentEmitter {
         None
     }
 
-    fn emit_diagnostic(&mut self, _db: &Diagnostic) {}
+    fn emit_diagnostic(&mut self, _db: Diagnostic) {}
 }
 
 fn silent_emitter() -> Box<DynEmitter> {
@@ -64,7 +64,7 @@ struct SilentOnIgnoredFilesEmitter {
 }
 
 impl SilentOnIgnoredFilesEmitter {
-    fn handle_non_ignoreable_error(&mut self, db: &Diagnostic) {
+    fn handle_non_ignoreable_error(&mut self, db: Diagnostic) {
         self.has_non_ignorable_parser_errors = true;
         self.can_reset.store(false, Ordering::Release);
         self.emitter.emit_diagnostic(db);
@@ -86,7 +86,7 @@ impl Emitter for SilentOnIgnoredFilesEmitter {
         None
     }
 
-    fn emit_diagnostic(&mut self, db: &Diagnostic) {
+    fn emit_diagnostic(&mut self, db: Diagnostic) {
         if db.level() == DiagnosticLevel::Fatal {
             return self.handle_non_ignoreable_error(db);
         }
@@ -365,7 +365,7 @@ mod tests {
                 None
             }
 
-            fn emit_diagnostic(&mut self, _db: &Diagnostic) {
+            fn emit_diagnostic(&mut self, _db: Diagnostic) {
                 self.num_emitted_errors.fetch_add(1, Ordering::Release);
             }
         }
@@ -424,7 +424,7 @@ mod tests {
             );
             let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
             let fatal_diagnostic = build_diagnostic(DiagnosticLevel::Fatal, Some(span));
-            emitter.emit_diagnostic(&fatal_diagnostic);
+            emitter.emit_diagnostic(fatal_diagnostic);
             assert_eq!(num_emitted_errors.load(Ordering::Acquire), 1);
             assert_eq!(can_reset_errors.load(Ordering::Acquire), false);
         }
@@ -449,7 +449,7 @@ mod tests {
             );
             let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
             let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(span));
-            emitter.emit_diagnostic(&non_fatal_diagnostic);
+            emitter.emit_diagnostic(non_fatal_diagnostic);
             assert_eq!(num_emitted_errors.load(Ordering::Acquire), 0);
             assert_eq!(can_reset_errors.load(Ordering::Acquire), true);
         }
@@ -473,7 +473,7 @@ mod tests {
             );
             let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
             let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(span));
-            emitter.emit_diagnostic(&non_fatal_diagnostic);
+            emitter.emit_diagnostic(non_fatal_diagnostic);
             assert_eq!(num_emitted_errors.load(Ordering::Acquire), 1);
             assert_eq!(can_reset_errors.load(Ordering::Acquire), false);
         }
@@ -512,9 +512,9 @@ mod tests {
             let bar_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(bar_span));
             let foo_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(foo_span));
             let fatal_diagnostic = build_diagnostic(DiagnosticLevel::Fatal, None);
-            emitter.emit_diagnostic(&bar_diagnostic);
-            emitter.emit_diagnostic(&foo_diagnostic);
-            emitter.emit_diagnostic(&fatal_diagnostic);
+            emitter.emit_diagnostic(bar_diagnostic);
+            emitter.emit_diagnostic(foo_diagnostic);
+            emitter.emit_diagnostic(fatal_diagnostic);
             assert_eq!(num_emitted_errors.load(Ordering::Acquire), 2);
             assert_eq!(can_reset_errors.load(Ordering::Acquire), false);
         }
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 451276b5ac1..4a44c40debd 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -13,8 +13,9 @@ use std::path::{Path, PathBuf};
 // desirable, because large numbers of files are unwieldy in general. See issue
 // #73494.
 const ENTRY_LIMIT: usize = 900;
-const ISSUES_ENTRY_LIMIT: usize = 1807;
-const ROOT_ENTRY_LIMIT: usize = 870;
+// FIXME: The following limits should be reduced eventually.
+const ISSUES_ENTRY_LIMIT: usize = 1819;
+const ROOT_ENTRY_LIMIT: usize = 871;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
     "rs",     // test source files
diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs
index 41f5df0fba0..6105ea430dd 100644
--- a/tests/assembly/targets/targets-elf.rs
+++ b/tests/assembly/targets/targets-elf.rs
@@ -174,6 +174,9 @@
 // revisions: armv7r_none_eabihf
 // [armv7r_none_eabihf] compile-flags: --target armv7r-none-eabihf
 // [armv7r_none_eabihf] needs-llvm-components: arm
+// revisions: armv8r_none_eabihf
+// [armv8r_none_eabihf] compile-flags: --target armv8r-none-eabihf
+// [armv8r_none_eabihf] needs-llvm-components: arm
 // FIXME: disabled since it fails on CI saying the csky component is missing
 /*
     revisions: csky_unknown_linux_gnuabiv2
diff --git a/tests/codegen-units/item-collection/instantiation-through-vtable.rs b/tests/codegen-units/item-collection/instantiation-through-vtable.rs
index e78226d4083..41edab7f879 100644
--- a/tests/codegen-units/item-collection/instantiation-through-vtable.rs
+++ b/tests/codegen-units/item-collection/instantiation-through-vtable.rs
@@ -26,7 +26,9 @@ fn start(_: isize, _: *const *const u8) -> isize {
     //~ MONO_ITEM fn std::ptr::drop_in_place::<Struct<u32>> - shim(None) @@ instantiation_through_vtable-cgu.0[Internal]
     //~ MONO_ITEM fn <Struct<u32> as Trait>::foo
     //~ MONO_ITEM fn <Struct<u32> as Trait>::bar
-    let _ = &s1 as &Trait;
+    let r1 = &s1 as &Trait;
+    r1.foo();
+    r1.bar();
 
     let s1 = Struct { _a: 0u64 };
     //~ MONO_ITEM fn std::ptr::drop_in_place::<Struct<u64>> - shim(None) @@ instantiation_through_vtable-cgu.0[Internal]
diff --git a/tests/codegen-units/item-collection/trait-method-default-impl.rs b/tests/codegen-units/item-collection/trait-method-default-impl.rs
index d953582cce9..c8a4552b11a 100644
--- a/tests/codegen-units/item-collection/trait-method-default-impl.rs
+++ b/tests/codegen-units/item-collection/trait-method-default-impl.rs
@@ -57,5 +57,8 @@ fn start(_: isize, _: *const *const u8) -> isize {
     //~ MONO_ITEM fn <u32 as SomeGenericTrait<i16>>::bar::<()>
     0u32.bar(0i16, ());
 
+    0i8.foo();
+    0i32.foo();
+
     0
 }
diff --git a/tests/codegen-units/item-collection/unsizing.rs b/tests/codegen-units/item-collection/unsizing.rs
index 34f52ce4e61..f578b00f276 100644
--- a/tests/codegen-units/item-collection/unsizing.rs
+++ b/tests/codegen-units/item-collection/unsizing.rs
@@ -75,5 +75,7 @@ fn start(_: isize, _: *const *const u8) -> isize {
     //~ MONO_ITEM fn <u32 as Trait>::foo
     let _wrapper_sized = wrapper_sized as Wrapper<Trait>;
 
+    false.foo();
+
     0
 }
diff --git a/tests/codegen/cffi/ffi-returns-twice.rs b/tests/codegen/cffi/ffi-returns-twice.rs
deleted file mode 100644
index 0fbe03f0bb6..00000000000
--- a/tests/codegen/cffi/ffi-returns-twice.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-// compile-flags: -C no-prepopulate-passes
-#![crate_type = "lib"]
-#![feature(ffi_returns_twice)]
-
-pub fn bar() { unsafe { foo() } }
-
-extern "C" {
-    // CHECK: declare{{( dso_local)?}} void @foo(){{.*}}[[ATTRS:#[0-9]+]]
-    // CHECK: attributes [[ATTRS]] = { {{.*}}returns_twice{{.*}} }
-    #[ffi_returns_twice] pub fn foo();
-}
diff --git a/tests/codegen/direct-access-external-data.rs b/tests/codegen/direct-access-external-data.rs
new file mode 100644
index 00000000000..ec4bfc33518
--- /dev/null
+++ b/tests/codegen/direct-access-external-data.rs
@@ -0,0 +1,21 @@
+// only-loongarch64-unknown-linux-gnu
+
+// revisions: DEFAULT DIRECT INDIRECT
+// [DEFAULT] compile-flags: -C relocation-model=static
+// [DIRECT] compile-flags: -C relocation-model=static -Z direct-access-external-data=yes
+// [INDIRECT] compile-flags: -C relocation-model=static -Z direct-access-external-data=no
+
+#![crate_type = "rlib"]
+
+// DEFAULT: @VAR = external {{.*}} global i32
+// DIRECT: @VAR = external dso_local {{.*}} global i32
+// INDIRECT: @VAR = external {{.*}} global i32
+
+extern "C" {
+    static VAR: i32;
+}
+
+#[no_mangle]
+pub fn get() -> i32 {
+    unsafe { VAR }
+}
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-abort.mir
new file mode 100644
index 00000000000..1fae40c5f40
--- /dev/null
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-abort.mir
@@ -0,0 +1,47 @@
+// MIR for `main::{closure#0}::{closure#0}::{closure#0}` 0 coroutine_by_move
+
+fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}, _2: ResumeTy) -> ()
+yields ()
+ {
+    debug _task_context => _2;
+    debug a => (_1.0: i32);
+    debug b => (_1.1: i32);
+    let mut _0: ();
+    let _3: i32;
+    scope 1 {
+        debug a => _3;
+        let _4: &i32;
+        scope 2 {
+            debug a => _4;
+            let _5: &i32;
+            scope 3 {
+                debug b => _5;
+            }
+        }
+    }
+
+    bb0: {
+        StorageLive(_3);
+        _3 = (_1.0: i32);
+        FakeRead(ForLet(None), _3);
+        StorageLive(_4);
+        _4 = &_3;
+        FakeRead(ForLet(None), _4);
+        StorageLive(_5);
+        _5 = &(_1.1: i32);
+        FakeRead(ForLet(None), _5);
+        _0 = const ();
+        StorageDead(_5);
+        StorageDead(_4);
+        StorageDead(_3);
+        drop(_1) -> [return: bb1, unwind: bb2];
+    }
+
+    bb1: {
+        return;
+    }
+
+    bb2 (cleanup): {
+        resume;
+    }
+}
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-unwind.mir
new file mode 100644
index 00000000000..1fae40c5f40
--- /dev/null
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-unwind.mir
@@ -0,0 +1,47 @@
+// MIR for `main::{closure#0}::{closure#0}::{closure#0}` 0 coroutine_by_move
+
+fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}, _2: ResumeTy) -> ()
+yields ()
+ {
+    debug _task_context => _2;
+    debug a => (_1.0: i32);
+    debug b => (_1.1: i32);
+    let mut _0: ();
+    let _3: i32;
+    scope 1 {
+        debug a => _3;
+        let _4: &i32;
+        scope 2 {
+            debug a => _4;
+            let _5: &i32;
+            scope 3 {
+                debug b => _5;
+            }
+        }
+    }
+
+    bb0: {
+        StorageLive(_3);
+        _3 = (_1.0: i32);
+        FakeRead(ForLet(None), _3);
+        StorageLive(_4);
+        _4 = &_3;
+        FakeRead(ForLet(None), _4);
+        StorageLive(_5);
+        _5 = &(_1.1: i32);
+        FakeRead(ForLet(None), _5);
+        _0 = const ();
+        StorageDead(_5);
+        StorageDead(_4);
+        StorageDead(_3);
+        drop(_1) -> [return: bb1, unwind: bb2];
+    }
+
+    bb1: {
+        return;
+    }
+
+    bb2 (cleanup): {
+        resume;
+    }
+}
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-abort.mir
new file mode 100644
index 00000000000..9886d6f68a4
--- /dev/null
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-abort.mir
@@ -0,0 +1,47 @@
+// MIR for `main::{closure#0}::{closure#0}::{closure#0}` 0 coroutine_by_mut
+
+fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}, _2: ResumeTy) -> ()
+yields ()
+ {
+    debug _task_context => _2;
+    debug a => (_1.0: i32);
+    debug b => (*(_1.1: &i32));
+    let mut _0: ();
+    let _3: i32;
+    scope 1 {
+        debug a => _3;
+        let _4: &i32;
+        scope 2 {
+            debug a => _4;
+            let _5: &i32;
+            scope 3 {
+                debug b => _5;
+            }
+        }
+    }
+
+    bb0: {
+        StorageLive(_3);
+        _3 = (_1.0: i32);
+        FakeRead(ForLet(None), _3);
+        StorageLive(_4);
+        _4 = &_3;
+        FakeRead(ForLet(None), _4);
+        StorageLive(_5);
+        _5 = &(*(_1.1: &i32));
+        FakeRead(ForLet(None), _5);
+        _0 = const ();
+        StorageDead(_5);
+        StorageDead(_4);
+        StorageDead(_3);
+        drop(_1) -> [return: bb1, unwind: bb2];
+    }
+
+    bb1: {
+        return;
+    }
+
+    bb2 (cleanup): {
+        resume;
+    }
+}
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-unwind.mir
new file mode 100644
index 00000000000..9886d6f68a4
--- /dev/null
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-unwind.mir
@@ -0,0 +1,47 @@
+// MIR for `main::{closure#0}::{closure#0}::{closure#0}` 0 coroutine_by_mut
+
+fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}, _2: ResumeTy) -> ()
+yields ()
+ {
+    debug _task_context => _2;
+    debug a => (_1.0: i32);
+    debug b => (*(_1.1: &i32));
+    let mut _0: ();
+    let _3: i32;
+    scope 1 {
+        debug a => _3;
+        let _4: &i32;
+        scope 2 {
+            debug a => _4;
+            let _5: &i32;
+            scope 3 {
+                debug b => _5;
+            }
+        }
+    }
+
+    bb0: {
+        StorageLive(_3);
+        _3 = (_1.0: i32);
+        FakeRead(ForLet(None), _3);
+        StorageLive(_4);
+        _4 = &_3;
+        FakeRead(ForLet(None), _4);
+        StorageLive(_5);
+        _5 = &(*(_1.1: &i32));
+        FakeRead(ForLet(None), _5);
+        _0 = const ();
+        StorageDead(_5);
+        StorageDead(_4);
+        StorageDead(_3);
+        drop(_1) -> [return: bb1, unwind: bb2];
+    }
+
+    bb1: {
+        return;
+    }
+
+    bb2 (cleanup): {
+        resume;
+    }
+}
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir
new file mode 100644
index 00000000000..7df4eb49260
--- /dev/null
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir
@@ -0,0 +1,10 @@
+// MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_move
+
+fn main::{closure#0}::{closure#0}(_1: {coroutine-closure@$DIR/async_closure_shims.rs:39:33: 39:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10} {
+    let mut _0: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10};
+
+    bb0: {
+        _0 = {coroutine@$DIR/async_closure_shims.rs:39:53: 42:10 (#0)} { a: move _2, b: move (_1.0: i32) };
+        return;
+    }
+}
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir
new file mode 100644
index 00000000000..7df4eb49260
--- /dev/null
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir
@@ -0,0 +1,10 @@
+// MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_move
+
+fn main::{closure#0}::{closure#0}(_1: {coroutine-closure@$DIR/async_closure_shims.rs:39:33: 39:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10} {
+    let mut _0: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10};
+
+    bb0: {
+        _0 = {coroutine@$DIR/async_closure_shims.rs:39:53: 42:10 (#0)} { a: move _2, b: move (_1.0: i32) };
+        return;
+    }
+}
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-abort.mir
new file mode 100644
index 00000000000..517b8d0dd88
--- /dev/null
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-abort.mir
@@ -0,0 +1,16 @@
+// MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_mut
+
+fn main::{closure#0}::{closure#0}(_1: &mut {coroutine-closure@$DIR/async_closure_shims.rs:39:33: 39:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10} {
+    debug a => _2;
+    debug b => ((*_1).0: i32);
+    let mut _0: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10};
+    let mut _3: &i32;
+
+    bb0: {
+        StorageLive(_3);
+        _3 = &((*_1).0: i32);
+        _0 = {coroutine@$DIR/async_closure_shims.rs:39:53: 42:10 (#0)} { a: _2, b: move _3 };
+        StorageDead(_3);
+        return;
+    }
+}
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-unwind.mir
new file mode 100644
index 00000000000..517b8d0dd88
--- /dev/null
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-unwind.mir
@@ -0,0 +1,16 @@
+// MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_mut
+
+fn main::{closure#0}::{closure#0}(_1: &mut {coroutine-closure@$DIR/async_closure_shims.rs:39:33: 39:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10} {
+    debug a => _2;
+    debug b => ((*_1).0: i32);
+    let mut _0: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10};
+    let mut _3: &i32;
+
+    bb0: {
+        StorageLive(_3);
+        _3 = &((*_1).0: i32);
+        _0 = {coroutine@$DIR/async_closure_shims.rs:39:53: 42:10 (#0)} { a: _2, b: move _3 };
+        StorageDead(_3);
+        return;
+    }
+}
diff --git a/tests/mir-opt/async_closure_shims.rs b/tests/mir-opt/async_closure_shims.rs
new file mode 100644
index 00000000000..2c99a2dad37
--- /dev/null
+++ b/tests/mir-opt/async_closure_shims.rs
@@ -0,0 +1,46 @@
+// edition:2021
+// skip-filecheck
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+
+#![feature(async_closure, noop_waker, async_fn_traits)]
+
+use std::future::Future;
+use std::ops::{AsyncFnMut, AsyncFnOnce};
+use std::pin::pin;
+use std::task::*;
+
+pub fn block_on<T>(fut: impl Future<Output = T>) -> T {
+    let mut fut = pin!(fut);
+    let ctx = &mut Context::from_waker(Waker::noop());
+
+    loop {
+        match fut.as_mut().poll(ctx) {
+            Poll::Pending => {}
+            Poll::Ready(t) => break t,
+        }
+    }
+}
+
+async fn call_mut(f: &mut impl AsyncFnMut(i32)) {
+    f(0).await;
+}
+
+async fn call_once(f: impl AsyncFnOnce(i32)) {
+    f(1).await;
+}
+
+// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.mir
+// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.mir
+// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.mir
+// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.mir
+pub fn main() {
+    block_on(async {
+        let b = 2i32;
+        let mut async_closure = async move |a: i32| {
+            let a = &a;
+            let b = &b;
+        };
+        call_mut(&mut async_closure).await;
+        call_once(async_closure).await;
+    });
+}
diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir
index 3c0d4008c90..9c8cf8763fd 100644
--- a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir
+++ b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir
@@ -5,6 +5,7 @@
             ty: Coroutine(
                 DefId(0:4 ~ async_await[ccf8]::a::{closure#0}),
                 [
+                (),
                 std::future::ResumeTy,
                 (),
                 (),
@@ -22,6 +23,7 @@
             ty: Coroutine(
                 DefId(0:4 ~ async_await[ccf8]::a::{closure#0}),
                 [
+                (),
                 std::future::ResumeTy,
                 (),
                 (),
diff --git a/tests/mir-opt/fn_ptr_shim.rs b/tests/mir-opt/fn_ptr_shim.rs
index c82260baefe..2650cbf9704 100644
--- a/tests/mir-opt/fn_ptr_shim.rs
+++ b/tests/mir-opt/fn_ptr_shim.rs
@@ -5,7 +5,7 @@
 // (as only `FnDef` and `FnPtr` callees are allowed in MIR).
 
 // EMIT_MIR core.ops-function-Fn-call.AddMovesForPackedDrops.before.mir
-fn main() {
+pub fn main() {
     call(noop as fn());
 }
 
diff --git a/tests/mir-opt/inline/cycle.g.Inline.panic-abort.diff b/tests/mir-opt/inline/cycle.g.Inline.panic-abort.diff
index 8f2baf4a3b6..1be0a4f2d29 100644
--- a/tests/mir-opt/inline/cycle.g.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/cycle.g.Inline.panic-abort.diff
@@ -4,35 +4,16 @@
   fn g() -> () {
       let mut _0: ();
       let _1: ();
-+     let mut _2: fn() {main};
-+     scope 1 (inlined f::<fn() {main}>) {
-+         debug g => _2;
-+         let mut _3: &fn() {main};
-+         let _4: ();
-+     }
   
       bb0: {
           StorageLive(_1);
--         _1 = f::<fn() {main}>(main) -> [return: bb1, unwind unreachable];
-+         StorageLive(_2);
-+         _2 = main;
-+         StorageLive(_4);
-+         StorageLive(_3);
-+         _3 = &_2;
-+         _4 = <fn() {main} as Fn<()>>::call(move _3, const ()) -> [return: bb2, unwind unreachable];
+          _1 = f::<fn() {main}>(main) -> [return: bb1, unwind unreachable];
       }
   
       bb1: {
-+         StorageDead(_4);
-+         StorageDead(_2);
           StorageDead(_1);
           _0 = const ();
           return;
-+     }
-+ 
-+     bb2: {
-+         StorageDead(_3);
-+         drop(_2) -> [return: bb1, unwind unreachable];
       }
   }
   
diff --git a/tests/mir-opt/inline/cycle.g.Inline.panic-unwind.diff b/tests/mir-opt/inline/cycle.g.Inline.panic-unwind.diff
index 1fd1014ba1d..da516220d50 100644
--- a/tests/mir-opt/inline/cycle.g.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/cycle.g.Inline.panic-unwind.diff
@@ -4,43 +4,16 @@
   fn g() -> () {
       let mut _0: ();
       let _1: ();
-+     let mut _2: fn() {main};
-+     scope 1 (inlined f::<fn() {main}>) {
-+         debug g => _2;
-+         let mut _3: &fn() {main};
-+         let _4: ();
-+     }
   
       bb0: {
           StorageLive(_1);
--         _1 = f::<fn() {main}>(main) -> [return: bb1, unwind continue];
-+         StorageLive(_2);
-+         _2 = main;
-+         StorageLive(_4);
-+         StorageLive(_3);
-+         _3 = &_2;
-+         _4 = <fn() {main} as Fn<()>>::call(move _3, const ()) -> [return: bb2, unwind: bb3];
+          _1 = f::<fn() {main}>(main) -> [return: bb1, unwind continue];
       }
   
       bb1: {
-+         StorageDead(_4);
-+         StorageDead(_2);
           StorageDead(_1);
           _0 = const ();
           return;
-+     }
-+ 
-+     bb2: {
-+         StorageDead(_3);
-+         drop(_2) -> [return: bb1, unwind continue];
-+     }
-+ 
-+     bb3 (cleanup): {
-+         drop(_2) -> [return: bb4, unwind terminate(cleanup)];
-+     }
-+ 
-+     bb4 (cleanup): {
-+         resume;
       }
   }
   
diff --git a/tests/mir-opt/inline/cycle.rs b/tests/mir-opt/inline/cycle.rs
index 350724235ba..c251226673d 100644
--- a/tests/mir-opt/inline/cycle.rs
+++ b/tests/mir-opt/inline/cycle.rs
@@ -13,9 +13,7 @@ fn f(g: impl Fn()) {
 #[inline(always)]
 fn g() {
     // CHECK-LABEL: fn g(
-    // CHECK-NOT: inlined
-    // CHECK: (inlined f::<fn() {main}>)
-    // CHECK-NOT: inlined
+    // CHECK-NOT: (inlined f::<fn() {main}>)
     f(main);
 }
 
diff --git a/tests/mir-opt/inline/inline_cycle_generic.main.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_cycle_generic.main.Inline.panic-abort.diff
index d437dbf5763..142b9c56598 100644
--- a/tests/mir-opt/inline/inline_cycle_generic.main.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/inline_cycle_generic.main.Inline.panic-abort.diff
@@ -7,6 +7,10 @@
 +     scope 1 (inlined <C as Call>::call) {
 +         scope 2 (inlined <B<A> as Call>::call) {
 +             scope 3 (inlined <A as Call>::call) {
++                 scope 4 (inlined <B<C> as Call>::call) {
++                     scope 5 (inlined <C as Call>::call) {
++                     }
++                 }
 +             }
 +         }
 +     }
@@ -14,7 +18,7 @@
       bb0: {
           StorageLive(_1);
 -         _1 = <C as Call>::call() -> [return: bb1, unwind unreachable];
-+         _1 = <B<C> as Call>::call() -> [return: bb1, unwind unreachable];
++         _1 = <B<A> as Call>::call() -> [return: bb1, unwind unreachable];
       }
   
       bb1: {
diff --git a/tests/mir-opt/inline/inline_cycle_generic.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_cycle_generic.main.Inline.panic-unwind.diff
index 8314526ee04..193ada05f02 100644
--- a/tests/mir-opt/inline/inline_cycle_generic.main.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/inline_cycle_generic.main.Inline.panic-unwind.diff
@@ -7,6 +7,10 @@
 +     scope 1 (inlined <C as Call>::call) {
 +         scope 2 (inlined <B<A> as Call>::call) {
 +             scope 3 (inlined <A as Call>::call) {
++                 scope 4 (inlined <B<C> as Call>::call) {
++                     scope 5 (inlined <C as Call>::call) {
++                     }
++                 }
 +             }
 +         }
 +     }
@@ -14,7 +18,7 @@
       bb0: {
           StorageLive(_1);
 -         _1 = <C as Call>::call() -> [return: bb1, unwind continue];
-+         _1 = <B<C> as Call>::call() -> [return: bb1, unwind continue];
++         _1 = <B<A> as Call>::call() -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/issue_99325.main.built.after.32bit.mir b/tests/mir-opt/issue_99325.main.built.after.32bit.mir
index ffb1aedd2ea..a10061ed941 100644
--- a/tests/mir-opt/issue_99325.main.built.after.32bit.mir
+++ b/tests/mir-opt/issue_99325.main.built.after.32bit.mir
@@ -1,8 +1,8 @@
 // MIR for `main` after built
 
 | User Type Annotations
-| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
-| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[22bb]::main::{constant#1}), args: [] }: &ReStatic [u8; 4_usize]], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}), args: [] }: &ReStatic [u8; 4_usize]], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
 |
 fn main() -> () {
     let mut _0: ();
diff --git a/tests/mir-opt/issue_99325.main.built.after.64bit.mir b/tests/mir-opt/issue_99325.main.built.after.64bit.mir
index ffb1aedd2ea..a10061ed941 100644
--- a/tests/mir-opt/issue_99325.main.built.after.64bit.mir
+++ b/tests/mir-opt/issue_99325.main.built.after.64bit.mir
@@ -1,8 +1,8 @@
 // MIR for `main` after built
 
 | User Type Annotations
-| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
-| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[22bb]::main::{constant#1}), args: [] }: &ReStatic [u8; 4_usize]], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}), args: [] }: &ReStatic [u8; 4_usize]], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
 |
 fn main() -> () {
     let mut _0: ();
diff --git a/tests/mir-opt/remove_storage_markers.rs b/tests/mir-opt/remove_storage_markers.rs
index 6666ff3b726..27661ab3254 100644
--- a/tests/mir-opt/remove_storage_markers.rs
+++ b/tests/mir-opt/remove_storage_markers.rs
@@ -1,4 +1,3 @@
-// skip-filecheck
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 // unit-test: RemoveStorageMarkers
 
@@ -8,6 +7,10 @@
 
 // EMIT_MIR remove_storage_markers.main.RemoveStorageMarkers.diff
 fn main() {
+    // CHECK-LABEL: fn main(
+
+    // CHECK-NOT: StorageDead
+    // CHECK-NOT: StorageLive
     let mut sum = 0;
     for i in 0..10 {
         sum += i;
diff --git a/tests/mir-opt/retag.rs b/tests/mir-opt/retag.rs
index 1e4b017dad5..554b8ece90f 100644
--- a/tests/mir-opt/retag.rs
+++ b/tests/mir-opt/retag.rs
@@ -28,7 +28,7 @@ impl Drop for Test {
 
 // EMIT_MIR retag.main.SimplifyCfg-elaborate-drops.after.mir
 // EMIT_MIR retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir
-fn main() {
+pub fn main() {
     let mut x = 0;
     {
         let v = Test(0).foo(&mut x); // just making sure we do not panic when there is a tuple struct ctor
diff --git a/tests/mir-opt/simplify_if.rs b/tests/mir-opt/simplify_if.rs
index 19b5806f720..f600c059581 100644
--- a/tests/mir-opt/simplify_if.rs
+++ b/tests/mir-opt/simplify_if.rs
@@ -1,10 +1,13 @@
-// skip-filecheck
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 #[inline(never)]
 fn noop() {}
 
 // EMIT_MIR simplify_if.main.SimplifyConstCondition-after-const-prop.diff
 fn main() {
+    // CHECK-LABEL: fn main(
+
+    // CHECK: bb0: {
+    // CHECK-NEXT: return;
     if false {
         noop();
     }
diff --git a/tests/mir-opt/slice_drop_shim.rs b/tests/mir-opt/slice_drop_shim.rs
index cac0a349128..037e048b3b7 100644
--- a/tests/mir-opt/slice_drop_shim.rs
+++ b/tests/mir-opt/slice_drop_shim.rs
@@ -1,6 +1,8 @@
 // skip-filecheck
-// compile-flags: -Zmir-opt-level=0
-
+// compile-flags: -Zmir-opt-level=0 -Clink-dead-code
+// mir-opt tests are always built as rlibs so that they seamlessly cross-compile,
+// so this test only produces MIR for the drop_in_place we're looking for
+// if we use -Clink-dead-code.
 
 // EMIT_MIR core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir
 fn main() {
diff --git a/tests/mir-opt/sroa/lifetimes.rs b/tests/mir-opt/sroa/lifetimes.rs
index cc5c0c9bbcd..ea04fac1571 100644
--- a/tests/mir-opt/sroa/lifetimes.rs
+++ b/tests/mir-opt/sroa/lifetimes.rs
@@ -1,4 +1,3 @@
-// skip-filecheck
 // unit-test: ScalarReplacementOfAggregates
 // compile-flags: -Cpanic=abort
 // no-prefer-dynamic
@@ -16,6 +15,10 @@ struct Foo<T: Err> {
 
 // EMIT_MIR lifetimes.foo.ScalarReplacementOfAggregates.diff
 fn foo<T: Err>() {
+    // CHECK-LABEL: fn foo(
+
+    // CHECK-NOT: [foo:_.*]: Foo
+    // CHECK-NOT: Box<dyn std::fmt::Display + 'static>
     let foo: Foo<T> = Foo {
         x: Ok(Box::new(5_u32)),
         y: 7_u32,
diff --git a/tests/mir-opt/sroa/structs.rs b/tests/mir-opt/sroa/structs.rs
index 73563e12c94..5ea3795b86e 100644
--- a/tests/mir-opt/sroa/structs.rs
+++ b/tests/mir-opt/sroa/structs.rs
@@ -1,4 +1,3 @@
-// skip-filecheck
 // unit-test: ScalarReplacementOfAggregates
 // compile-flags: -Cpanic=abort
 // no-prefer-dynamic
@@ -13,28 +12,68 @@ impl Drop for Tag {
     fn drop(&mut self) {}
 }
 
+/// Check that SROA excludes structs with a `Drop` implementation.
 pub fn dropping() {
+    // CHECK-LABEL: fn dropping(
+
+    // CHECK: [[aggregate:_[0-9]+]]: S;
+
+    // CHECK: bb0: {
+    // CHECK: [[aggregate]] = S
     S(Tag(0), Tag(1), Tag(2)).1;
 }
 
+/// Check that SROA excludes enums.
 pub fn enums(a: usize) -> usize {
+    // CHECK-LABEL: fn enums(
+
+    // CHECK: [[enum:_[0-9]+]]: std::option::Option<usize>;
+
+    // CHECK: bb0: {
+    // CHECK: [[enum]] = Option::<usize>::Some
+    // CHECK: _5 = (([[enum]] as Some).0: usize)
+    // CHECK: _0 = _5
     if let Some(a) = Some(a) { a } else { 0 }
 }
 
+/// Check that SROA destructures `U`.
 pub fn structs(a: f32) -> f32 {
+    // CHECK-LABEL: fn structs(
     struct U {
         _foo: usize,
         a: f32,
     }
-
+    // CHECK: [[ret:_0]]: f32;
+    // CHECK: [[struct:_[0-9]+]]: structs::U;
+    // CHECK: [[a_tmp:_[0-9]+]]: f32;
+    // CHECK: [[foo:_[0-9]+]]: usize;
+    // CHECK: [[a_ret:_[0-9]+]]: f32;
+
+    // CHECK: bb0: {
+    // CHECK-NOT: [[struct]]
+    // CHECK: [[a_tmp]] = _1;
+    // CHECK-NOT: [[struct]]
+    // CHECK: [[foo]] = const 0_usize;
+    // CHECK-NOT: [[struct]]
+    // CHECK: [[a_ret]] = move [[a_tmp]];
+    // CHECK-NOT: [[struct]]
+    // CHECK: _0 = [[a_ret]];
+    // CHECK-NOT: [[struct]]
     U { _foo: 0, a }.a
 }
 
+/// Check that SROA excludes unions.
 pub fn unions(a: f32) -> u32 {
+    // CHECK-LABEL: fn unions(
     union Repr {
         f: f32,
         u: u32,
     }
+    // CHECK: [[union:_[0-9]+]]: unions::Repr;
+
+    // CHECK: bb0: {
+    // CHECK: [[union]] = Repr {
+    // CHECK: _0 = ([[union]].1: u32)
     unsafe { Repr { f: a }.u }
 }
 
@@ -46,11 +85,21 @@ struct Foo {
     d: Option<isize>,
 }
 
-fn g() -> u32 {
-    3
-}
-
+/// Check that non-escaping uses of a struct are destructured.
 pub fn flat() {
+    // CHECK-LABEL: fn flat(
+
+    // CHECK: [[struct:_[0-9]+]]: Foo;
+
+    // CHECK: bb0: {
+    // CHECK: [[init_unit:_[0-9]+]] = ();
+    // CHECK: [[init_opt_isize:_[0-9]+]] = Option::<isize>::Some
+
+    // CHECK: [[destr_five:_[0-9]+]] = const 5_u8;
+    // CHECK: [[destr_unit:_[0-9]+]] = move [[init_unit]];
+    // CHECK: [[destr_a:_[0-9]+]] = const "a";
+    // CHECK: [[destr_opt_isize:_[0-9]+]] = move [[init_opt_isize]];
+
     let Foo { a, b, c, d } = Foo { a: 5, b: (), c: "a", d: Some(-4) };
     let _ = a;
     let _ = b;
@@ -65,6 +114,10 @@ struct Escaping {
     c: u32,
 }
 
+fn g() -> u32 {
+    3
+}
+
 fn f(a: *const u32) {
     println!("{}", unsafe { *a.add(2) });
 }
@@ -76,10 +129,38 @@ fn f(a: *const u32) {
 // of them to `f`. However, this would lead to a miscompilation because `b` and `c`
 // might no longer appear right after `a` in memory.
 pub fn escaping() {
+    // CHECK-LABEL: fn escaping(
+
+    // CHECK: [[ptr:_[0-9]+]]: *const u32;
+    // CHECK: [[ref:_[0-9]+]]: &u32;
+    // CHECK: [[struct:_[0-9]+]]: Escaping;
+    // CHECK: [[a:_[0-9]+]]: u32;
+
+    // CHECK: bb0: {
+    // CHECK: [[struct]] = Escaping {
+    // CHECK: [[ref]] = &([[struct]].0
+    // CHECK: [[ptr]] = &raw const (*[[ref]]);
     f(&Escaping { a: 1, b: 2, c: g() }.a);
 }
 
+/// Check that copies from an internal struct are destructured and reassigned to
+/// the original struct.
 fn copies(x: Foo) {
+    // CHECK-LABEL: fn copies(
+
+    // CHECK: [[external:_[0-9]+]]: Foo) ->
+    // CHECK: [[internal:_[0-9]+]]: Foo;
+    // CHECK: [[byte:_[0-9]+]]: u8;
+    // CHECK: [[unit:_[0-9]+]]: ();
+    // CHECK: [[str:_[0-9]+]]: &str;
+    // CHECK: [[opt_isize:_[0-9]+]]: std::option::Option<isize>;
+
+    // CHECK: bb0: {
+    // CHECK: [[byte]] = ([[external]].0
+    // CHECK: [[unit]] = ([[external]].1
+    // CHECK: [[str]] = ([[external]].2
+    // CHECK: [[opt_isize]] = ([[external]].3
+
     let y = x;
     let t = y.a;
     let u = y.c;
@@ -87,13 +168,44 @@ fn copies(x: Foo) {
     let a = z.b;
 }
 
+/// Check that copies from an internal struct are destructured and reassigned to
+/// the original struct.
 fn ref_copies(x: &Foo) {
+    // CHECK-LABEL: fn ref_copies(
+
+    // CHECK: [[external:_[0-9]+]]: &Foo) ->
+    // CHECK: [[internal:_[0-9]+]]: Foo;
+    // CHECK: [[byte:_[0-9]+]]: u8;
+    // CHECK: [[unit:_[0-9]+]]: ();
+    // CHECK: [[str:_[0-9]+]]: &str;
+    // CHECK: [[opt_isize:_[0-9]+]]: std::option::Option<isize>;
+
+    // CHECK: bb0: {
+    // CHECK: [[byte]] = ((*[[external]]).0
+    // CHECK: [[unit]] = ((*[[external]]).1
+    // CHECK: [[str]] = ((*[[external]]).2
+    // CHECK: [[opt_isize]] = ((*[[external]]).3
+
     let y = *x;
     let t = y.a;
     let u = y.c;
 }
 
+/// Check that deaggregated assignments from constants are placed after the constant's
+/// assignment. Also check that copying field accesses from the copy of the constant are
+/// reassigned to copy from the constant.
 fn constant() {
+    // CHECK-LABEL: constant(
+
+    // CHECK: [[constant:_[0-9]+]]: (usize, u8);
+    // CHECK: [[t:_[0-9]+]]: usize;
+    // CHECK: [[u:_[0-9]+]]: u8;
+
+    // CHECK: bb0: {
+    // CHECK-NOT: [[constant]]
+    // CHECK: [[constant]] = const
+    // CHECK: [[t]] = move ([[constant]].0: usize)
+    // CHECK: [[u]] = move ([[constant]].1: u8)
     const U: (usize, u8) = (5, 9);
     let y = U;
     let t = y.0;
@@ -101,6 +213,7 @@ fn constant() {
 }
 
 fn main() {
+    // CHECK-LABEL: fn main(
     dropping();
     enums(5);
     structs(5.);
diff --git a/tests/mir-opt/unusual_item_types.rs b/tests/mir-opt/unusual_item_types.rs
index 49b663b4f82..fa6ba515473 100644
--- a/tests/mir-opt/unusual_item_types.rs
+++ b/tests/mir-opt/unusual_item_types.rs
@@ -23,7 +23,7 @@ enum E {
     V = 5,
 }
 
-fn main() {
+pub fn main() {
     let f = Test::X as fn(usize) -> Test;
 // EMIT_MIR core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir
     let v = Vec::<i32>::new();
diff --git a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs
index ae7f341fe4e..cce223c77bb 100644
--- a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs
+++ b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs
@@ -29,6 +29,7 @@ fn main() {
         TyKind::FnPtr(..) => (),            //~ ERROR usage of `ty::TyKind::<kind>`
         TyKind::Dynamic(..) => (),          //~ ERROR usage of `ty::TyKind::<kind>`
         TyKind::Closure(..) => (),          //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::CoroutineClosure(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
         TyKind::Coroutine(..) => (),        //~ ERROR usage of `ty::TyKind::<kind>`
         TyKind::CoroutineWitness(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
         TyKind::Never => (),                //~ ERROR usage of `ty::TyKind::<kind>`
diff --git a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr
index 45b7c26faad..2ff5aad95dd 100644
--- a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr
+++ b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr
@@ -109,71 +109,77 @@ LL |         TyKind::Closure(..) => (),
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:32:9
    |
-LL |         TyKind::Coroutine(..) => (),
+LL |         TyKind::CoroutineClosure(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:33:9
    |
-LL |         TyKind::CoroutineWitness(..) => (),
+LL |         TyKind::Coroutine(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:34:9
    |
-LL |         TyKind::Never => (),
+LL |         TyKind::CoroutineWitness(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:35:9
    |
-LL |         TyKind::Tuple(..) => (),
+LL |         TyKind::Never => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:36:9
    |
-LL |         TyKind::Alias(..) => (),
+LL |         TyKind::Tuple(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:37:9
    |
-LL |         TyKind::Param(..) => (),
+LL |         TyKind::Alias(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:38:9
    |
-LL |         TyKind::Bound(..) => (),
+LL |         TyKind::Param(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:39:9
    |
-LL |         TyKind::Placeholder(..) => (),
+LL |         TyKind::Bound(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:40:9
    |
-LL |         TyKind::Infer(..) => (),
+LL |         TyKind::Placeholder(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:41:9
    |
+LL |         TyKind::Infer(..) => (),
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
+
+error: usage of `ty::TyKind::<kind>`
+  --> $DIR/ty_tykind_usage.rs:42:9
+   |
 LL |         TyKind::Error(_) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:46:12
+  --> $DIR/ty_tykind_usage.rs:47:12
    |
 LL |     if let TyKind::Int(int_ty) = kind {}
    |            ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind`
-  --> $DIR/ty_tykind_usage.rs:48:24
+  --> $DIR/ty_tykind_usage.rs:49:24
    |
 LL |     fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {}
    |                        ^^^^^^^^^^
@@ -181,7 +187,7 @@ LL |     fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {}
    = help: try using `Ty` instead
 
 error: usage of `ty::TyKind`
-  --> $DIR/ty_tykind_usage.rs:50:37
+  --> $DIR/ty_tykind_usage.rs:51:37
    |
 LL |     fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
    |                                     ^^^^^^^^^^^
@@ -189,7 +195,7 @@ LL |     fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
    = help: try using `Ty` instead
 
 error: usage of `ty::TyKind`
-  --> $DIR/ty_tykind_usage.rs:50:53
+  --> $DIR/ty_tykind_usage.rs:51:53
    |
 LL |     fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
    |                                                     ^^^^^^^^^^^
@@ -197,12 +203,12 @@ LL |     fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
    = help: try using `Ty` instead
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:53:9
+  --> $DIR/ty_tykind_usage.rs:54:9
    |
 LL |         IrTyKind::Bool
    |         --------^^^^^^
    |         |
    |         help: try using `ty::<kind>` directly: `ty`
 
-error: aborting due to 32 previous errors
+error: aborting due to 33 previous errors
 
diff --git a/tests/ui-fulldeps/rustc_encodable_hygiene.rs b/tests/ui-fulldeps/rustc_encodable_hygiene.rs
index bec7930d462..36c684a131e 100644
--- a/tests/ui-fulldeps/rustc_encodable_hygiene.rs
+++ b/tests/ui-fulldeps/rustc_encodable_hygiene.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 #![feature(rustc_private)]
 
diff --git a/tests/ui/anon-params/anon-params-deprecated.fixed b/tests/ui/anon-params/anon-params-deprecated.fixed
index c09e2077084..8ec1d41a709 100644
--- a/tests/ui/anon-params/anon-params-deprecated.fixed
+++ b/tests/ui/anon-params/anon-params-deprecated.fixed
@@ -5,6 +5,7 @@
 // edition:2015
 // run-rustfix
 
+#[allow(dead_code)]
 trait T {
     fn foo(_: i32); //~ WARNING anonymous parameters are deprecated
                  //~| WARNING this is accepted in the current edition
diff --git a/tests/ui/anon-params/anon-params-deprecated.rs b/tests/ui/anon-params/anon-params-deprecated.rs
index 6f7385da040..108ba60a02f 100644
--- a/tests/ui/anon-params/anon-params-deprecated.rs
+++ b/tests/ui/anon-params/anon-params-deprecated.rs
@@ -5,6 +5,7 @@
 // edition:2015
 // run-rustfix
 
+#[allow(dead_code)]
 trait T {
     fn foo(i32); //~ WARNING anonymous parameters are deprecated
                  //~| WARNING this is accepted in the current edition
diff --git a/tests/ui/anon-params/anon-params-deprecated.stderr b/tests/ui/anon-params/anon-params-deprecated.stderr
index 691e2c79512..541cb004b5b 100644
--- a/tests/ui/anon-params/anon-params-deprecated.stderr
+++ b/tests/ui/anon-params/anon-params-deprecated.stderr
@@ -1,5 +1,5 @@
 warning: anonymous parameters are deprecated and will be removed in the next edition
-  --> $DIR/anon-params-deprecated.rs:9:12
+  --> $DIR/anon-params-deprecated.rs:10:12
    |
 LL |     fn foo(i32);
    |            ^^^ help: try naming the parameter or explicitly ignoring it: `_: i32`
@@ -13,7 +13,7 @@ LL | #![warn(anonymous_parameters)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 warning: anonymous parameters are deprecated and will be removed in the next edition
-  --> $DIR/anon-params-deprecated.rs:12:30
+  --> $DIR/anon-params-deprecated.rs:13:30
    |
 LL |     fn bar_with_default_impl(String, String) {}
    |                              ^^^^^^ help: try naming the parameter or explicitly ignoring it: `_: String`
@@ -22,7 +22,7 @@ LL |     fn bar_with_default_impl(String, String) {}
    = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686>
 
 warning: anonymous parameters are deprecated and will be removed in the next edition
-  --> $DIR/anon-params-deprecated.rs:12:38
+  --> $DIR/anon-params-deprecated.rs:13:38
    |
 LL |     fn bar_with_default_impl(String, String) {}
    |                                      ^^^^^^ help: try naming the parameter or explicitly ignoring it: `_: String`
diff --git a/tests/ui/associated-consts/associated-const-outer-ty-refs.rs b/tests/ui/associated-consts/associated-const-outer-ty-refs.rs
index f32ca0cccfc..d5e9a2bde00 100644
--- a/tests/ui/associated-consts/associated-const-outer-ty-refs.rs
+++ b/tests/ui/associated-consts/associated-const-outer-ty-refs.rs
@@ -1,4 +1,5 @@
-// run-pass
+// check-pass
+
 trait Lattice {
     const BOTTOM: Self;
 }
diff --git a/tests/ui/associated-consts/associated-const-type-parameters.rs b/tests/ui/associated-consts/associated-const-type-parameters.rs
index b62d47458be..a233b09ff89 100644
--- a/tests/ui/associated-consts/associated-const-type-parameters.rs
+++ b/tests/ui/associated-consts/associated-const-type-parameters.rs
@@ -27,7 +27,7 @@ fn sub<A: Foo, B: Foo>() -> i32 {
     A::X - B::X
 }
 
-trait Bar: Foo {
+trait Bar: Foo { //~ WARN trait `Bar` is never used
     const Y: i32 = Self::X;
 }
 
diff --git a/tests/ui/associated-consts/associated-const-type-parameters.stderr b/tests/ui/associated-consts/associated-const-type-parameters.stderr
new file mode 100644
index 00000000000..6ee2a5de1b6
--- /dev/null
+++ b/tests/ui/associated-consts/associated-const-type-parameters.stderr
@@ -0,0 +1,10 @@
+warning: trait `Bar` is never used
+  --> $DIR/associated-const-type-parameters.rs:30:7
+   |
+LL | trait Bar: Foo {
+   |       ^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/associated-type-bounds/dyn-impl-trait-type.rs b/tests/ui/associated-type-bounds/dyn-impl-trait-type.rs
index a3f4717791a..079c44b3a59 100644
--- a/tests/ui/associated-type-bounds/dyn-impl-trait-type.rs
+++ b/tests/ui/associated-type-bounds/dyn-impl-trait-type.rs
@@ -5,7 +5,7 @@
 use std::ops::Add;
 
 trait Tr1 { type As1; fn mk(&self) -> Self::As1; }
-trait Tr2<'a> { fn tr2(self) -> &'a Self; }
+trait Tr2<'a> { fn tr2(self) -> &'a Self; } //~ WARN method `tr2` is never used
 
 fn assert_copy<T: Copy>(x: T) { let _x = x; let _x = x; }
 fn assert_static<T: 'static>(_: T) {}
diff --git a/tests/ui/associated-type-bounds/dyn-impl-trait-type.stderr b/tests/ui/associated-type-bounds/dyn-impl-trait-type.stderr
new file mode 100644
index 00000000000..2e26a434f5d
--- /dev/null
+++ b/tests/ui/associated-type-bounds/dyn-impl-trait-type.stderr
@@ -0,0 +1,12 @@
+warning: method `tr2` is never used
+  --> $DIR/dyn-impl-trait-type.rs:8:20
+   |
+LL | trait Tr2<'a> { fn tr2(self) -> &'a Self; }
+   |       ---          ^^^
+   |       |
+   |       method in this trait
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/associated-type-bounds/dyn-rpit-and-let.rs b/tests/ui/associated-type-bounds/dyn-rpit-and-let.rs
index 52199124ea3..49e5e72f225 100644
--- a/tests/ui/associated-type-bounds/dyn-rpit-and-let.rs
+++ b/tests/ui/associated-type-bounds/dyn-rpit-and-let.rs
@@ -7,7 +7,7 @@
 use std::ops::Add;
 
 trait Tr1 { type As1; fn mk(&self) -> Self::As1; }
-trait Tr2<'a> { fn tr2(self) -> &'a Self; }
+trait Tr2<'a> { fn tr2(self) -> &'a Self; } //~ WARN method `tr2` is never used
 
 fn assert_copy<T: Copy>(x: T) { let _x = x; let _x = x; }
 fn assert_static<T: 'static>(_: T) {}
diff --git a/tests/ui/associated-type-bounds/dyn-rpit-and-let.stderr b/tests/ui/associated-type-bounds/dyn-rpit-and-let.stderr
new file mode 100644
index 00000000000..9eddbe46284
--- /dev/null
+++ b/tests/ui/associated-type-bounds/dyn-rpit-and-let.stderr
@@ -0,0 +1,12 @@
+warning: method `tr2` is never used
+  --> $DIR/dyn-rpit-and-let.rs:10:20
+   |
+LL | trait Tr2<'a> { fn tr2(self) -> &'a Self; }
+   |       ---          ^^^
+   |       |
+   |       method in this trait
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/associated-type-bounds/rpit.rs b/tests/ui/associated-type-bounds/rpit.rs
index 59c7733fbe4..557e63b5f71 100644
--- a/tests/ui/associated-type-bounds/rpit.rs
+++ b/tests/ui/associated-type-bounds/rpit.rs
@@ -5,7 +5,7 @@
 use std::ops::Add;
 
 trait Tr1 { type As1; fn mk(self) -> Self::As1; }
-trait Tr2<'a> { fn tr2(self) -> &'a Self; }
+trait Tr2<'a> { fn tr2(self) -> &'a Self; } //~ WARN method `tr2` is never used
 
 fn assert_copy<T: Copy>(x: T) { let _x = x; let _x = x; }
 fn assert_static<T: 'static>(_: T) {}
diff --git a/tests/ui/associated-type-bounds/rpit.stderr b/tests/ui/associated-type-bounds/rpit.stderr
new file mode 100644
index 00000000000..76bd75bd2ca
--- /dev/null
+++ b/tests/ui/associated-type-bounds/rpit.stderr
@@ -0,0 +1,12 @@
+warning: method `tr2` is never used
+  --> $DIR/rpit.rs:8:20
+   |
+LL | trait Tr2<'a> { fn tr2(self) -> &'a Self; }
+   |       ---          ^^^
+   |       |
+   |       method in this trait
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.fixed b/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.fixed
index b9f26a40219..128c7dfdda2 100644
--- a/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.fixed
+++ b/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.fixed
@@ -1,4 +1,5 @@
 // run-rustfix
+#![allow(dead_code)]
 trait O {
     type M;
 }
diff --git a/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.rs b/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.rs
index abff6af73e2..6b6478419b4 100644
--- a/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.rs
+++ b/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.rs
@@ -1,4 +1,5 @@
 // run-rustfix
+#![allow(dead_code)]
 trait O {
     type M;
 }
diff --git a/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.stderr b/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.stderr
index 7ca9aff4322..21bc37bb3ea 100644
--- a/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.stderr
+++ b/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/suggest-contraining-assoc-type-because-of-assoc-const.rs:12:21
+  --> $DIR/suggest-contraining-assoc-type-because-of-assoc-const.rs:13:21
    |
 LL |     const N: C::M = 4u8;
    |                     ^^^ expected associated type, found `u8`
diff --git a/tests/ui/associated-type-bounds/trait-alias-impl-trait.rs b/tests/ui/associated-type-bounds/trait-alias-impl-trait.rs
index 93a44c01ce0..60088e443f3 100644
--- a/tests/ui/associated-type-bounds/trait-alias-impl-trait.rs
+++ b/tests/ui/associated-type-bounds/trait-alias-impl-trait.rs
@@ -1,5 +1,6 @@
 // run-pass
 
+#![allow(dead_code)]
 #![feature(associated_type_bounds)]
 #![feature(type_alias_impl_trait)]
 
diff --git a/tests/ui/associated-types/associated-types-for-unimpl-trait.fixed b/tests/ui/associated-types/associated-types-for-unimpl-trait.fixed
index 80bbef17469..adfba994f32 100644
--- a/tests/ui/associated-types/associated-types-for-unimpl-trait.fixed
+++ b/tests/ui/associated-types/associated-types-for-unimpl-trait.fixed
@@ -1,4 +1,5 @@
 // run-rustfix
+#![allow(dead_code)]
 #![allow(unused_variables)]
 
 trait Get {
diff --git a/tests/ui/associated-types/associated-types-for-unimpl-trait.rs b/tests/ui/associated-types/associated-types-for-unimpl-trait.rs
index 0f6cea8e69f..50478171d86 100644
--- a/tests/ui/associated-types/associated-types-for-unimpl-trait.rs
+++ b/tests/ui/associated-types/associated-types-for-unimpl-trait.rs
@@ -1,4 +1,5 @@
 // run-rustfix
+#![allow(dead_code)]
 #![allow(unused_variables)]
 
 trait Get {
diff --git a/tests/ui/associated-types/associated-types-for-unimpl-trait.stderr b/tests/ui/associated-types/associated-types-for-unimpl-trait.stderr
index 17941b6bf1e..27014fa53d8 100644
--- a/tests/ui/associated-types/associated-types-for-unimpl-trait.stderr
+++ b/tests/ui/associated-types/associated-types-for-unimpl-trait.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `Self: Get` is not satisfied
-  --> $DIR/associated-types-for-unimpl-trait.rs:10:40
+  --> $DIR/associated-types-for-unimpl-trait.rs:11:40
    |
 LL |     fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
    |                                        ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
diff --git a/tests/ui/associated-types/associated-types-in-bound-type-arg.rs b/tests/ui/associated-types/associated-types-in-bound-type-arg.rs
index 88bb5fe0afe..05e66a168d9 100644
--- a/tests/ui/associated-types/associated-types-in-bound-type-arg.rs
+++ b/tests/ui/associated-types/associated-types-in-bound-type-arg.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 // Test the case where we resolve `C::Result` and the trait bound
 // itself includes a `Self::Item` shorthand.
 //
diff --git a/tests/ui/associated-types/associated-types-issue-20220.rs b/tests/ui/associated-types/associated-types-issue-20220.rs
index 19fa7a6085a..89efce19834 100644
--- a/tests/ui/associated-types/associated-types-issue-20220.rs
+++ b/tests/ui/associated-types/associated-types-issue-20220.rs
@@ -4,7 +4,7 @@
 
 use std::vec;
 
-trait IntoIteratorX {
+trait IntoIteratorX { //~ WARN trait `IntoIteratorX` is never used
     type Item;
     type IntoIter: Iterator<Item=Self::Item>;
 
diff --git a/tests/ui/associated-types/associated-types-issue-20220.stderr b/tests/ui/associated-types/associated-types-issue-20220.stderr
new file mode 100644
index 00000000000..c682f46e140
--- /dev/null
+++ b/tests/ui/associated-types/associated-types-issue-20220.stderr
@@ -0,0 +1,10 @@
+warning: trait `IntoIteratorX` is never used
+  --> $DIR/associated-types-issue-20220.rs:7:7
+   |
+LL | trait IntoIteratorX {
+   |       ^^^^^^^^^^^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/associated-types/associated-types-issue-20371.rs b/tests/ui/associated-types/associated-types-issue-20371.rs
index ae8a8767d27..cbec83d45b2 100644
--- a/tests/ui/associated-types/associated-types-issue-20371.rs
+++ b/tests/ui/associated-types/associated-types-issue-20371.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 // Test that we are able to have an impl that defines an associated type
 // before the actual trait.
 
diff --git a/tests/ui/associated-types/associated-types-nested-projections.rs b/tests/ui/associated-types/associated-types-nested-projections.rs
index 76ba7496250..440f35c8bde 100644
--- a/tests/ui/associated-types/associated-types-nested-projections.rs
+++ b/tests/ui/associated-types/associated-types-nested-projections.rs
@@ -13,7 +13,7 @@ impl<'a> Bound for &'a i32 {}
 trait IntoIterator {
     type Iter: Iterator;
 
-    fn into_iter(self) -> Self::Iter;
+    fn into_iter(self) -> Self::Iter; //~ WARN method `into_iter` is never used
 }
 
 impl<'a, T> IntoIterator for &'a [T; 3] {
diff --git a/tests/ui/associated-types/associated-types-nested-projections.stderr b/tests/ui/associated-types/associated-types-nested-projections.stderr
new file mode 100644
index 00000000000..97d5a758573
--- /dev/null
+++ b/tests/ui/associated-types/associated-types-nested-projections.stderr
@@ -0,0 +1,13 @@
+warning: method `into_iter` is never used
+  --> $DIR/associated-types-nested-projections.rs:16:8
+   |
+LL | trait IntoIterator {
+   |       ------------ method in this trait
+...
+LL |     fn into_iter(self) -> Self::Iter;
+   |        ^^^^^^^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/associated-types/associated-types-normalize-in-bounds-ufcs.rs b/tests/ui/associated-types/associated-types-normalize-in-bounds-ufcs.rs
index e09aa3663c6..6612598b1b8 100644
--- a/tests/ui/associated-types/associated-types-normalize-in-bounds-ufcs.rs
+++ b/tests/ui/associated-types/associated-types-normalize-in-bounds-ufcs.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 #![allow(unused_variables)]
 // Test that we normalize associated types that appear in bounds; if
 // we didn't, the call to `self.split2()` fails to type check.
diff --git a/tests/ui/associated-types/associated-types-normalize-in-bounds.rs b/tests/ui/associated-types/associated-types-normalize-in-bounds.rs
index dcfae0f37e1..df0a82ee7ce 100644
--- a/tests/ui/associated-types/associated-types-normalize-in-bounds.rs
+++ b/tests/ui/associated-types/associated-types-normalize-in-bounds.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 #![allow(unused_variables)]
 // Test that we normalize associated types that appear in bounds; if
 // we didn't, the call to `self.split2()` fails to type check.
diff --git a/tests/ui/associated-types/associated-types-projection-bound-in-supertraits.rs b/tests/ui/associated-types/associated-types-projection-bound-in-supertraits.rs
index 107e6b4ce0c..e99d0112ec4 100644
--- a/tests/ui/associated-types/associated-types-projection-bound-in-supertraits.rs
+++ b/tests/ui/associated-types/associated-types-projection-bound-in-supertraits.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 #![allow(unused_variables)]
 // Test that we correctly handle projection bounds appearing in the
 // supertrait list (and in conjunction with overloaded operators). In
diff --git a/tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.rs b/tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.rs
index a59c327be21..e172c6e5611 100644
--- a/tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.rs
+++ b/tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.rs
@@ -6,7 +6,7 @@ trait Int
 {
     type T;
 
-    fn dummy(&self) { }
+    fn dummy(&self) { } //~ WARN method `dummy` is never used
 }
 
 trait NonZero
diff --git a/tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.stderr b/tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.stderr
new file mode 100644
index 00000000000..c26ed79a026
--- /dev/null
+++ b/tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.stderr
@@ -0,0 +1,13 @@
+warning: method `dummy` is never used
+  --> $DIR/associated-types-projection-from-known-type-in-impl.rs:9:8
+   |
+LL | trait Int
+   |       --- method in this trait
+...
+LL |     fn dummy(&self) { }
+   |        ^^^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed b/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed
index 9bc308465eb..01f49d52ee2 100644
--- a/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed
+++ b/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed
@@ -2,6 +2,7 @@
 // Check that we get an error when you use `<Self as Get>::Value` in
 // the trait definition even if there is no default method.
 
+#![allow(dead_code)]
 trait Get {
     type Value;
 }
diff --git a/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.rs b/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.rs
index 549fc8fc618..7068a754a12 100644
--- a/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.rs
+++ b/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.rs
@@ -2,6 +2,7 @@
 // Check that we get an error when you use `<Self as Get>::Value` in
 // the trait definition even if there is no default method.
 
+#![allow(dead_code)]
 trait Get {
     type Value;
 }
diff --git a/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr b/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr
index 64a88525af8..79200dc3acc 100644
--- a/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr
+++ b/tests/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `Self: Get` is not satisfied
-  --> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:40
+  --> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:11:40
    |
 LL |     fn okay<U:Get>(&self, foo: U, bar: <Self as Get>::Value);
    |                                        ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
diff --git a/tests/ui/associated-types/associated-types-projection-to-unrelated-trait.rs b/tests/ui/associated-types/associated-types-projection-to-unrelated-trait.rs
index 3b8c8c019e5..a2d6c9ff5a4 100644
--- a/tests/ui/associated-types/associated-types-projection-to-unrelated-trait.rs
+++ b/tests/ui/associated-types/associated-types-projection-to-unrelated-trait.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 // Check that we do not get an error when you use `<Self as Get>::Value` in
 // the trait definition if there is no default method and for every impl,
 // `Self` does implement `Get`.
diff --git a/tests/ui/associated-types/associated-types-qualified-path-with-trait-with-type-parameters.rs b/tests/ui/associated-types/associated-types-qualified-path-with-trait-with-type-parameters.rs
index 3c830d37060..1768fd1687b 100644
--- a/tests/ui/associated-types/associated-types-qualified-path-with-trait-with-type-parameters.rs
+++ b/tests/ui/associated-types/associated-types-qualified-path-with-trait-with-type-parameters.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 // pretty-expanded FIXME #23616
 
 trait Foo<T> {
diff --git a/tests/ui/associated-types/associated-types-resolve-lifetime.rs b/tests/ui/associated-types/associated-types-resolve-lifetime.rs
index 52f2324d72a..563d0c11822 100644
--- a/tests/ui/associated-types/associated-types-resolve-lifetime.rs
+++ b/tests/ui/associated-types/associated-types-resolve-lifetime.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 // pretty-expanded FIXME #23616
 
 trait Get<T> {
diff --git a/tests/ui/associated-types/impl-wf-cycle-5.fixed b/tests/ui/associated-types/impl-wf-cycle-5.fixed
index bff6ca90975..2b8f1e0d865 100644
--- a/tests/ui/associated-types/impl-wf-cycle-5.fixed
+++ b/tests/ui/associated-types/impl-wf-cycle-5.fixed
@@ -1,9 +1,11 @@
 // run-rustfix
 
+#[allow(dead_code)]
 trait Baz {}
 impl Baz for () {}
 impl<T> Baz for (T,) {}
 
+#[allow(dead_code)]
 trait Fiz {}
 impl Fiz for bool {}
 
diff --git a/tests/ui/associated-types/impl-wf-cycle-5.rs b/tests/ui/associated-types/impl-wf-cycle-5.rs
index a822e1fb008..e6de292ca5c 100644
--- a/tests/ui/associated-types/impl-wf-cycle-5.rs
+++ b/tests/ui/associated-types/impl-wf-cycle-5.rs
@@ -1,9 +1,11 @@
 // run-rustfix
 
+#[allow(dead_code)]
 trait Baz {}
 impl Baz for () {}
 impl<T> Baz for (T,) {}
 
+#[allow(dead_code)]
 trait Fiz {}
 impl Fiz for bool {}
 
diff --git a/tests/ui/associated-types/impl-wf-cycle-5.stderr b/tests/ui/associated-types/impl-wf-cycle-5.stderr
index 284a50bb9a3..61edf18b43d 100644
--- a/tests/ui/associated-types/impl-wf-cycle-5.stderr
+++ b/tests/ui/associated-types/impl-wf-cycle-5.stderr
@@ -1,5 +1,5 @@
 error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
-  --> $DIR/impl-wf-cycle-5.rs:20:1
+  --> $DIR/impl-wf-cycle-5.rs:22:1
    |
 LL | / impl<T> Grault for (T,)
 LL | |
@@ -12,7 +12,7 @@ LL |       type A = ();
    |       ------ associated type `<(T,) as Grault>::A` is specified here
    |
 note: required for `(T,)` to implement `Grault`
-  --> $DIR/impl-wf-cycle-5.rs:20:9
+  --> $DIR/impl-wf-cycle-5.rs:22:9
    |
 LL | impl<T> Grault for (T,)
    |         ^^^^^^     ^^^^
diff --git a/tests/ui/associated-types/impl-wf-cycle-6.fixed b/tests/ui/associated-types/impl-wf-cycle-6.fixed
index 73ed64f7ce3..5ddf1faefe0 100644
--- a/tests/ui/associated-types/impl-wf-cycle-6.fixed
+++ b/tests/ui/associated-types/impl-wf-cycle-6.fixed
@@ -1,9 +1,11 @@
 // run-rustfix
 
+#[allow(dead_code)]
 trait Baz {}
 impl Baz for () {}
 impl<T> Baz for (T,) {}
 
+#[allow(dead_code)]
 trait Fiz {}
 impl Fiz for bool {}
 
diff --git a/tests/ui/associated-types/impl-wf-cycle-6.rs b/tests/ui/associated-types/impl-wf-cycle-6.rs
index 20d635cac5d..28f6deb77ce 100644
--- a/tests/ui/associated-types/impl-wf-cycle-6.rs
+++ b/tests/ui/associated-types/impl-wf-cycle-6.rs
@@ -1,9 +1,11 @@
 // run-rustfix
 
+#[allow(dead_code)]
 trait Baz {}
 impl Baz for () {}
 impl<T> Baz for (T,) {}
 
+#[allow(dead_code)]
 trait Fiz {}
 impl Fiz for bool {}
 
diff --git a/tests/ui/associated-types/impl-wf-cycle-6.stderr b/tests/ui/associated-types/impl-wf-cycle-6.stderr
index c9b5d8060be..1c749503318 100644
--- a/tests/ui/associated-types/impl-wf-cycle-6.stderr
+++ b/tests/ui/associated-types/impl-wf-cycle-6.stderr
@@ -1,5 +1,5 @@
 error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
-  --> $DIR/impl-wf-cycle-6.rs:20:1
+  --> $DIR/impl-wf-cycle-6.rs:22:1
    |
 LL | / impl<T: Grault> Grault for (T,)
 LL | |
@@ -11,7 +11,7 @@ LL |       type A = ();
    |       ------ associated type `<(T,) as Grault>::A` is specified here
    |
 note: required for `(T,)` to implement `Grault`
-  --> $DIR/impl-wf-cycle-6.rs:20:17
+  --> $DIR/impl-wf-cycle-6.rs:22:17
    |
 LL | impl<T: Grault> Grault for (T,)
    |                 ^^^^^^     ^^^^
diff --git a/tests/ui/async-await/async-borrowck-escaping-closure-error.rs b/tests/ui/async-await/async-borrowck-escaping-closure-error.rs
index f8ff9186842..2a3e382e118 100644
--- a/tests/ui/async-await/async-borrowck-escaping-closure-error.rs
+++ b/tests/ui/async-await/async-borrowck-escaping-closure-error.rs
@@ -1,10 +1,11 @@
 // edition:2018
-// check-pass
 
 #![feature(async_closure)]
 fn foo() -> Box<dyn std::future::Future<Output = u32>> {
     let x = 0u32;
     Box::new((async || x)())
+    //~^ ERROR cannot return value referencing local variable `x`
+    //~| ERROR cannot return value referencing temporary value
 }
 
 fn main() {
diff --git a/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr b/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr
new file mode 100644
index 00000000000..be67c78221a
--- /dev/null
+++ b/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr
@@ -0,0 +1,21 @@
+error[E0515]: cannot return value referencing local variable `x`
+  --> $DIR/async-borrowck-escaping-closure-error.rs:6:5
+   |
+LL |     Box::new((async || x)())
+   |     ^^^^^^^^^------------^^^
+   |     |        |
+   |     |        `x` is borrowed here
+   |     returns a value referencing data owned by the current function
+
+error[E0515]: cannot return value referencing temporary value
+  --> $DIR/async-borrowck-escaping-closure-error.rs:6:5
+   |
+LL |     Box::new((async || x)())
+   |     ^^^^^^^^^------------^^^
+   |     |        |
+   |     |        temporary value created here
+   |     returns a value referencing data owned by the current function
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0515`.
diff --git a/tests/ui/async-await/async-closures/arg-mismatch.rs b/tests/ui/async-await/async-closures/arg-mismatch.rs
new file mode 100644
index 00000000000..650e13677bc
--- /dev/null
+++ b/tests/ui/async-await/async-closures/arg-mismatch.rs
@@ -0,0 +1,15 @@
+// aux-build:block-on.rs
+// edition:2021
+
+#![feature(async_closure)]
+
+extern crate block_on;
+
+fn main() {
+    block_on::block_on(async {
+        let c = async |x| {};
+        c(1i32).await;
+        c(2usize).await;
+        //~^ ERROR mismatched types
+    });
+}
diff --git a/tests/ui/async-await/async-closures/arg-mismatch.stderr b/tests/ui/async-await/async-closures/arg-mismatch.stderr
new file mode 100644
index 00000000000..70853ae2815
--- /dev/null
+++ b/tests/ui/async-await/async-closures/arg-mismatch.stderr
@@ -0,0 +1,21 @@
+error[E0308]: mismatched types
+  --> $DIR/arg-mismatch.rs:12:11
+   |
+LL |         c(2usize).await;
+   |         - ^^^^^^ expected `i32`, found `usize`
+   |         |
+   |         arguments to this function are incorrect
+   |
+note: closure parameter defined here
+  --> $DIR/arg-mismatch.rs:10:24
+   |
+LL |         let c = async |x| {};
+   |                        ^
+help: change the type of the numeric literal from `usize` to `i32`
+   |
+LL |         c(2i32).await;
+   |            ~~~
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/async-await/async-closures/async-fn-mut-for-async-fn.rs b/tests/ui/async-await/async-closures/async-fn-mut-for-async-fn.rs
new file mode 100644
index 00000000000..f73b43dd152
--- /dev/null
+++ b/tests/ui/async-await/async-closures/async-fn-mut-for-async-fn.rs
@@ -0,0 +1,21 @@
+// aux-build:block-on.rs
+// edition:2021
+// run-pass
+
+// FIXME(async_closures): When `fn_sig_for_fn_abi` is fixed, remove this.
+// ignore-pass (test emits codegen-time warnings)
+
+#![feature(async_closure)]
+
+extern crate block_on;
+
+fn main() {
+    block_on::block_on(async {
+        let x = async || {};
+
+        async fn needs_async_fn_mut(mut x: impl async FnMut()) {
+            x().await;
+        }
+        needs_async_fn_mut(x).await;
+    });
+}
diff --git a/tests/ui/async-await/async-closures/async-fn-once-for-async-fn.rs b/tests/ui/async-await/async-closures/async-fn-once-for-async-fn.rs
new file mode 100644
index 00000000000..0ba323a71cd
--- /dev/null
+++ b/tests/ui/async-await/async-closures/async-fn-once-for-async-fn.rs
@@ -0,0 +1,21 @@
+// aux-build:block-on.rs
+// edition:2021
+// run-pass
+
+// FIXME(async_closures): When `fn_sig_for_fn_abi` is fixed, remove this.
+// ignore-pass (test emits codegen-time warnings)
+
+#![feature(async_closure)]
+
+extern crate block_on;
+
+fn main() {
+    block_on::block_on(async {
+        let x = async || {};
+
+        async fn needs_async_fn_once(x: impl async FnOnce()) {
+            x().await;
+        }
+        needs_async_fn_once(x).await;
+    });
+}
diff --git a/tests/ui/async-await/async-closures/auxiliary/block-on.rs b/tests/ui/async-await/async-closures/auxiliary/block-on.rs
new file mode 100644
index 00000000000..902e033cfe7
--- /dev/null
+++ b/tests/ui/async-await/async-closures/auxiliary/block-on.rs
@@ -0,0 +1,20 @@
+// edition: 2021
+
+#![feature(async_closure, noop_waker)]
+
+use std::future::Future;
+use std::pin::pin;
+use std::task::*;
+
+pub fn block_on<T>(fut: impl Future<Output = T>) -> T {
+    let mut fut = pin!(fut);
+    // Poll loop, just to test the future...
+    let ctx = &mut Context::from_waker(Waker::noop());
+
+    loop {
+        match unsafe { fut.as_mut().poll(ctx) } {
+            Poll::Pending => {}
+            Poll::Ready(t) => break t,
+        }
+    }
+}
diff --git a/tests/ui/async-await/async-closures/await-inference-guidance.rs b/tests/ui/async-await/async-closures/await-inference-guidance.rs
new file mode 100644
index 00000000000..3702915cbad
--- /dev/null
+++ b/tests/ui/async-await/async-closures/await-inference-guidance.rs
@@ -0,0 +1,16 @@
+// aux-build:block-on.rs
+// edition:2021
+// run-pass
+
+#![feature(async_closure)]
+
+extern crate block_on;
+
+fn main() {
+    block_on::block_on(async {
+        let x = async |x: &str| -> String { x.to_owned() };
+        let mut s = x("hello, world").await;
+        s.truncate(4);
+        println!("{s}");
+    });
+}
diff --git a/tests/ui/async-await/async-closures/brand.rs b/tests/ui/async-await/async-closures/brand.rs
new file mode 100644
index 00000000000..26d2ed5a6ef
--- /dev/null
+++ b/tests/ui/async-await/async-closures/brand.rs
@@ -0,0 +1,25 @@
+// aux-build:block-on.rs
+// edition:2021
+// build-pass
+
+#![feature(async_closure)]
+
+extern crate block_on;
+
+use std::future::Future;
+use std::marker::PhantomData;
+
+struct S;
+struct B<'b>(PhantomData<&'b mut &'b mut ()>);
+
+impl S {
+    async fn q<F: async Fn(B<'_>)>(self, f: F) {
+        f(B(PhantomData)).await;
+    }
+}
+
+fn main() {
+    block_on::block_on(async {
+        S.q(async |b: B<'_>| { println!("...") }).await;
+    });
+}
diff --git a/tests/ui/async-await/async-closures/def-path.rs b/tests/ui/async-await/async-closures/def-path.rs
index 2883a1715b0..87e99ddda64 100644
--- a/tests/ui/async-await/async-closures/def-path.rs
+++ b/tests/ui/async-await/async-closures/def-path.rs
@@ -8,7 +8,7 @@ fn main() {
     //~^ NOTE the expected `async` closure body
     let () = x();
     //~^ ERROR mismatched types
-    //~| NOTE this expression has type `{static main::{closure#0}::{closure#0} upvar_tys=
+    //~| NOTE this expression has type `{static main::{closure#0}::{closure#0}<
     //~| NOTE expected `async` closure body, found `()`
-    //~| NOTE expected `async` closure body `{static main::{closure#0}::{closure#0}
+    //~| NOTE expected `async` closure body `{static main::{closure#0}::{closure#0}<
 }
diff --git a/tests/ui/async-await/async-closures/def-path.stderr b/tests/ui/async-await/async-closures/def-path.stderr
index 4b37e50aac4..dae45825f37 100644
--- a/tests/ui/async-await/async-closures/def-path.stderr
+++ b/tests/ui/async-await/async-closures/def-path.stderr
@@ -5,11 +5,11 @@ LL |     let x = async || {};
    |                      -- the expected `async` closure body
 LL |
 LL |     let () = x();
-   |         ^^   --- this expression has type `{static main::{closure#0}::{closure#0} upvar_tys=?7t witness=?8t}`
+   |         ^^   --- this expression has type `{static main::{closure#0}::{closure#0}<?7t> upvar_tys=?15t witness=?6t}`
    |         |
    |         expected `async` closure body, found `()`
    |
-   = note: expected `async` closure body `{static main::{closure#0}::{closure#0} upvar_tys=?7t witness=?8t}`
+   = note: expected `async` closure body `{static main::{closure#0}::{closure#0}<?7t> upvar_tys=?15t witness=?6t}`
                          found unit type `()`
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/async-await/async-closures/drop.rs b/tests/ui/async-await/async-closures/drop.rs
new file mode 100644
index 00000000000..a243d20774d
--- /dev/null
+++ b/tests/ui/async-await/async-closures/drop.rs
@@ -0,0 +1,38 @@
+// aux-build:block-on.rs
+// edition:2018
+// run-pass
+// check-run-results
+
+#![feature(async_closure)]
+#![allow(unused)]
+
+extern crate block_on;
+
+struct DropMe(i32);
+
+impl Drop for DropMe {
+    fn drop(&mut self) {
+        println!("{} was dropped", self.0);
+    }
+}
+
+async fn call_once(f: impl async FnOnce()) {
+    println!("before call");
+    let fut = Box::pin(f());
+    println!("after call");
+    drop(fut);
+    println!("future dropped");
+}
+
+fn main() {
+    block_on::block_on(async {
+        let d = DropMe(42);
+        let async_closure = async move || {
+            let d = &d;
+            println!("called");
+        };
+
+        call_once(async_closure).await;
+        println!("after");
+    });
+}
diff --git a/tests/ui/async-await/async-closures/drop.run.stdout b/tests/ui/async-await/async-closures/drop.run.stdout
new file mode 100644
index 00000000000..ab233f491ba
--- /dev/null
+++ b/tests/ui/async-await/async-closures/drop.run.stdout
@@ -0,0 +1,5 @@
+before call
+after call
+42 was dropped
+future dropped
+after
diff --git a/tests/ui/async-await/async-closures/higher-ranked-return.rs b/tests/ui/async-await/async-closures/higher-ranked-return.rs
new file mode 100644
index 00000000000..d98779c6ea3
--- /dev/null
+++ b/tests/ui/async-await/async-closures/higher-ranked-return.rs
@@ -0,0 +1,18 @@
+// aux-build:block-on.rs
+// edition:2021
+
+// known-bug: unknown
+// Borrow checking doesn't like that higher-ranked output...
+
+#![feature(async_closure)]
+
+extern crate block_on;
+
+fn main() {
+    block_on::block_on(async {
+        let x = async move |x: &str| -> &str {
+            x
+        };
+        let s = x("hello!").await;
+    });
+}
diff --git a/tests/ui/async-await/async-closures/higher-ranked-return.stderr b/tests/ui/async-await/async-closures/higher-ranked-return.stderr
new file mode 100644
index 00000000000..268631f67cd
--- /dev/null
+++ b/tests/ui/async-await/async-closures/higher-ranked-return.stderr
@@ -0,0 +1,14 @@
+error: lifetime may not live long enough
+  --> $DIR/higher-ranked-return.rs:13:46
+   |
+LL |           let x = async move |x: &str| -> &str {
+   |  ________________________________-________----_^
+   | |                                |        |
+   | |                                |        return type of async closure `{async closure body@$DIR/higher-ranked-return.rs:13:46: 15:10}` contains a lifetime `'2`
+   | |                                let's call the lifetime of this reference `'1`
+LL | |             x
+LL | |         };
+   | |_________^ returning this value requires that `'1` must outlive `'2`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/async-await/async-closures/higher-ranked.rs b/tests/ui/async-await/async-closures/higher-ranked.rs
index f0bdcf691ae..17b5116cceb 100644
--- a/tests/ui/async-await/async-closures/higher-ranked.rs
+++ b/tests/ui/async-await/async-closures/higher-ranked.rs
@@ -1,12 +1,16 @@
+// aux-build:block-on.rs
 // edition:2021
+// build-pass
 
 #![feature(async_closure)]
 
+extern crate block_on;
+
 fn main() {
-    let x = async move |x: &str| {
-        //~^ ERROR lifetime may not live long enough
-        // This error is proof that the `&str` type is higher-ranked.
-        // This won't work until async closures are fully impl'd.
-        println!("{x}");
-    };
+    block_on::block_on(async {
+        let x = async move |x: &str| {
+            println!("{x}");
+        };
+        x("hello!").await;
+    });
 }
diff --git a/tests/ui/async-await/async-closures/higher-ranked.stderr b/tests/ui/async-await/async-closures/higher-ranked.stderr
deleted file mode 100644
index fb02a15b079..00000000000
--- a/tests/ui/async-await/async-closures/higher-ranked.stderr
+++ /dev/null
@@ -1,17 +0,0 @@
-error: lifetime may not live long enough
-  --> $DIR/higher-ranked.rs:6:34
-   |
-LL |       let x = async move |x: &str| {
-   |  ____________________________-___-_^
-   | |                            |   |
-   | |                            |   return type of closure `{async closure body@$DIR/higher-ranked.rs:6:34: 11:6}` contains a lifetime `'2`
-   | |                            let's call the lifetime of this reference `'1`
-LL | |
-LL | |         // This error is proof that the `&str` type is higher-ranked.
-LL | |         // This won't work until async closures are fully impl'd.
-LL | |         println!("{x}");
-LL | |     };
-   | |_____^ returning this value requires that `'1` must outlive `'2`
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/async-await/async-closures/is-not-fn.rs b/tests/ui/async-await/async-closures/is-not-fn.rs
new file mode 100644
index 00000000000..94c8e8563bd
--- /dev/null
+++ b/tests/ui/async-await/async-closures/is-not-fn.rs
@@ -0,0 +1,12 @@
+// edition:2021
+
+#![feature(async_closure)]
+
+fn main() {
+    fn needs_fn(x: impl FnOnce()) {}
+    needs_fn(async || {});
+    //~^ ERROR expected a `FnOnce()` closure, found `{coroutine-closure@
+    // FIXME(async_closures): This should explain in more detail how async fns don't
+    // implement the regular `Fn` traits. Or maybe we should just fix it and make them
+    // when there are no upvars or whatever.
+}
diff --git a/tests/ui/async-await/async-closures/is-not-fn.stderr b/tests/ui/async-await/async-closures/is-not-fn.stderr
new file mode 100644
index 00000000000..12da4b1fc6f
--- /dev/null
+++ b/tests/ui/async-await/async-closures/is-not-fn.stderr
@@ -0,0 +1,19 @@
+error[E0277]: expected a `FnOnce()` closure, found `{coroutine-closure@$DIR/is-not-fn.rs:7:14: 7:22}`
+  --> $DIR/is-not-fn.rs:7:14
+   |
+LL |     needs_fn(async || {});
+   |     -------- ^^^^^^^^^^^ expected an `FnOnce()` closure, found `{coroutine-closure@$DIR/is-not-fn.rs:7:14: 7:22}`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `FnOnce<()>` is not implemented for `{coroutine-closure@$DIR/is-not-fn.rs:7:14: 7:22}`
+   = note: wrap the `{coroutine-closure@$DIR/is-not-fn.rs:7:14: 7:22}` in a closure with no arguments: `|| { /* code */ }`
+note: required by a bound in `needs_fn`
+  --> $DIR/is-not-fn.rs:6:25
+   |
+LL |     fn needs_fn(x: impl FnOnce()) {}
+   |                         ^^^^^^^^ required by this bound in `needs_fn`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/async-await/async-closures/mangle.rs b/tests/ui/async-await/async-closures/mangle.rs
new file mode 100644
index 00000000000..9d231d55176
--- /dev/null
+++ b/tests/ui/async-await/async-closures/mangle.rs
@@ -0,0 +1,35 @@
+// aux-build:block-on.rs
+// edition:2021
+// build-pass
+// revisions: v0 legacy
+//[v0] compile-flags: -Csymbol-mangling-version=v0
+//[legacy] compile-flags: -Csymbol-mangling-version=legacy -Zunstable-options
+
+// FIXME(async_closures): When `fn_sig_for_fn_abi` is fixed, remove this.
+// ignore-pass (test emits codegen-time warnings)
+
+#![feature(async_closure, noop_waker)]
+
+extern crate block_on;
+
+use std::future::Future;
+use std::pin::pin;
+use std::task::*;
+
+async fn call_mut(f: &mut impl async FnMut()) {
+    f().await;
+}
+
+async fn call_once(f: impl async FnOnce()) {
+    f().await;
+}
+
+fn main() {
+    block_on::block_on(async {
+        let mut async_closure = async move || {
+            println!("called");
+        };
+        call_mut(&mut async_closure).await;
+        call_once(async_closure).await;
+    });
+}
diff --git a/tests/ui/async-await/async-closures/move-consuming-capture.rs b/tests/ui/async-await/async-closures/move-consuming-capture.rs
new file mode 100644
index 00000000000..b8964c571f9
--- /dev/null
+++ b/tests/ui/async-await/async-closures/move-consuming-capture.rs
@@ -0,0 +1,20 @@
+// aux-build:block-on.rs
+// edition:2021
+
+#![feature(async_closure)]
+
+extern crate block_on;
+
+struct NoCopy;
+
+fn main() {
+    block_on::block_on(async {
+        let s = NoCopy;
+        let x = async move || {
+            drop(s);
+        };
+        x().await;
+        x().await;
+        //~^ ERROR use of moved value: `x`
+    });
+}
diff --git a/tests/ui/async-await/async-closures/move-consuming-capture.stderr b/tests/ui/async-await/async-closures/move-consuming-capture.stderr
new file mode 100644
index 00000000000..2c2a0d1162d
--- /dev/null
+++ b/tests/ui/async-await/async-closures/move-consuming-capture.stderr
@@ -0,0 +1,17 @@
+error[E0382]: use of moved value: `x`
+  --> $DIR/move-consuming-capture.rs:17:9
+   |
+LL |         let x = async move || {
+   |             - move occurs because `x` has type `{coroutine-closure@$DIR/move-consuming-capture.rs:13:17: 13:30}`, which does not implement the `Copy` trait
+...
+LL |         x().await;
+   |         --- `x` moved due to this method call
+LL |         x().await;
+   |         ^ value used here after move
+   |
+note: `async_call_once` takes ownership of the receiver `self`, which moves `x`
+  --> $SRC_DIR/core/src/ops/async_function.rs:LL:COL
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/async-await/async-closures/move-is-async-fn.rs b/tests/ui/async-await/async-closures/move-is-async-fn.rs
new file mode 100644
index 00000000000..943c0629541
--- /dev/null
+++ b/tests/ui/async-await/async-closures/move-is-async-fn.rs
@@ -0,0 +1,21 @@
+// aux-build:block-on.rs
+// edition:2021
+// build-pass
+
+#![feature(async_closure)]
+
+extern crate block_on;
+
+fn main() {
+    block_on::block_on(async {
+        let s = String::from("hello, world");
+        let c = async move || {
+            println!("{s}");
+        };
+        c().await;
+        c().await;
+
+        fn is_static<T: 'static>(_: T) {}
+        is_static(c);
+    });
+}
diff --git a/tests/ui/async-await/async-closures/mutate.rs b/tests/ui/async-await/async-closures/mutate.rs
new file mode 100644
index 00000000000..cc1df5f034f
--- /dev/null
+++ b/tests/ui/async-await/async-closures/mutate.rs
@@ -0,0 +1,19 @@
+// aux-build:block-on.rs
+// edition:2021
+// run-pass
+
+#![feature(async_closure)]
+
+extern crate block_on;
+
+fn main() {
+    block_on::block_on(async {
+        let mut prefix = String::from("Hello");
+        let mut c = async move |x: &str| {
+            prefix.push(',');
+            println!("{prefix} {x}!")
+        };
+        c("world").await;
+        c("rust").await;
+    });
+}
diff --git a/tests/ui/async-await/async-closures/not-lending.rs b/tests/ui/async-await/async-closures/not-lending.rs
new file mode 100644
index 00000000000..90832e1a074
--- /dev/null
+++ b/tests/ui/async-await/async-closures/not-lending.rs
@@ -0,0 +1,21 @@
+// aux-build:block-on.rs
+// edition:2021
+
+#![feature(async_closure)]
+
+extern crate block_on;
+
+// Make sure that we can't make an async closure that evaluates to a self-borrow.
+// i.e. that the generator may reference captures, but the future's return type can't.
+
+fn main() {
+    block_on::block_on(async {
+        let s = String::new();
+        let x = async move || -> &String { &s };
+        //~^ ERROR lifetime may not live long enough
+
+        let s = String::new();
+        let x = async move || { &s };
+        //~^ ERROR lifetime may not live long enough
+    });
+}
diff --git a/tests/ui/async-await/async-closures/not-lending.stderr b/tests/ui/async-await/async-closures/not-lending.stderr
new file mode 100644
index 00000000000..1713e49b551
--- /dev/null
+++ b/tests/ui/async-await/async-closures/not-lending.stderr
@@ -0,0 +1,24 @@
+error: lifetime may not live long enough
+  --> $DIR/not-lending.rs:14:42
+   |
+LL |         let x = async move || -> &String { &s };
+   |                 ------------------------ ^^^^^^ returning this value requires that `'1` must outlive `'2`
+   |                 |                |
+   |                 |                return type of async closure `{async closure body@$DIR/not-lending.rs:14:42: 14:48}` contains a lifetime `'2`
+   |                 lifetime `'1` represents this closure's body
+   |
+   = note: closure implements `Fn`, so references to captured variables can't escape the closure
+
+error: lifetime may not live long enough
+  --> $DIR/not-lending.rs:18:31
+   |
+LL |         let x = async move || { &s };
+   |                 ------------- ^^^^^^ returning this value requires that `'1` must outlive `'2`
+   |                 |           |
+   |                 |           return type of async closure `{async closure body@$DIR/not-lending.rs:18:31: 18:37}` contains a lifetime `'2`
+   |                 lifetime `'1` represents this closure's body
+   |
+   = note: closure implements `Fn`, so references to captured variables can't escape the closure
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/async-await/async-closures/return-type-mismatch.rs b/tests/ui/async-await/async-closures/return-type-mismatch.rs
new file mode 100644
index 00000000000..9ad6be0b6e6
--- /dev/null
+++ b/tests/ui/async-await/async-closures/return-type-mismatch.rs
@@ -0,0 +1,14 @@
+// aux-build:block-on.rs
+// edition:2021
+
+#![feature(async_closure)]
+
+extern crate block_on;
+
+fn main() {
+    block_on::block_on(async {
+        let x = async || -> i32 { 0 };
+        let y: usize = x().await;
+        //~^ ERROR mismatched types
+    });
+}
diff --git a/tests/ui/async-await/async-closures/return-type-mismatch.stderr b/tests/ui/async-await/async-closures/return-type-mismatch.stderr
new file mode 100644
index 00000000000..53841f62777
--- /dev/null
+++ b/tests/ui/async-await/async-closures/return-type-mismatch.stderr
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+  --> $DIR/return-type-mismatch.rs:11:24
+   |
+LL |         let y: usize = x().await;
+   |                        ^^^^^^^^^ expected `usize`, found `i32`
+   |
+help: you can convert an `i32` to a `usize` and panic if the converted value doesn't fit
+   |
+LL |         let y: usize = x().await.try_into().unwrap();
+   |                                 ++++++++++++++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/async-await/async-closures/wrong-fn-kind.rs b/tests/ui/async-await/async-closures/wrong-fn-kind.rs
new file mode 100644
index 00000000000..f86cee3e070
--- /dev/null
+++ b/tests/ui/async-await/async-closures/wrong-fn-kind.rs
@@ -0,0 +1,16 @@
+// edition:2021
+
+// FIXME(async_closures): This needs a better error message!
+
+#![feature(async_closure)]
+
+fn main() {
+    fn needs_async_fn(_: impl async Fn()) {}
+
+    let mut x = 1;
+    needs_async_fn(async || {
+        //~^ ERROR i16: ops::async_function::internal_implementation_detail::AsyncFnKindHelper<i8>
+        // FIXME: Should say "closure is `async FnMut` but it needs `async Fn`" or sth.
+        x += 1;
+    });
+}
diff --git a/tests/ui/async-await/async-closures/wrong-fn-kind.stderr b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr
new file mode 100644
index 00000000000..4ef8484cc34
--- /dev/null
+++ b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr
@@ -0,0 +1,22 @@
+error[E0277]: the trait bound `i16: ops::async_function::internal_implementation_detail::AsyncFnKindHelper<i8>` is not satisfied
+  --> $DIR/wrong-fn-kind.rs:11:20
+   |
+LL |       needs_async_fn(async || {
+   |  _____--------------_^
+   | |     |
+   | |     required by a bound introduced by this call
+LL | |
+LL | |         // FIXME: Should say "closure is `async FnMut` but it needs `async Fn`" or sth.
+LL | |         x += 1;
+LL | |     });
+   | |_____^ the trait `ops::async_function::internal_implementation_detail::AsyncFnKindHelper<i8>` is not implemented for `i16`
+   |
+note: required by a bound in `needs_async_fn`
+  --> $DIR/wrong-fn-kind.rs:8:31
+   |
+LL |     fn needs_async_fn(_: impl async Fn()) {}
+   |                               ^^^^^^^^^^ required by this bound in `needs_async_fn`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/async-await/in-trait/auxiliary/bad-region.rs b/tests/ui/async-await/in-trait/auxiliary/bad-region.rs
new file mode 100644
index 00000000000..02dc25aaa16
--- /dev/null
+++ b/tests/ui/async-await/in-trait/auxiliary/bad-region.rs
@@ -0,0 +1,7 @@
+// edition:2021
+
+#[allow(async_fn_in_trait)]
+
+pub trait BleRadio<'a> {
+    async fn transmit(&mut self);
+}
diff --git a/tests/ui/async-await/in-trait/bad-region.rs b/tests/ui/async-await/in-trait/bad-region.rs
new file mode 100644
index 00000000000..444368e21a4
--- /dev/null
+++ b/tests/ui/async-await/in-trait/bad-region.rs
@@ -0,0 +1,17 @@
+// aux-build:bad-region.rs
+// edition:2021
+
+#![allow(async_fn_in_trait)]
+
+extern crate bad_region as jewel;
+
+use jewel::BleRadio;
+
+pub struct Radio {}
+
+impl BleRadio for Radio {
+//~^ ERROR implicit elided lifetime not allowed here
+    async fn transmit(&mut self) {}
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/in-trait/bad-region.stderr b/tests/ui/async-await/in-trait/bad-region.stderr
new file mode 100644
index 00000000000..9203fd790af
--- /dev/null
+++ b/tests/ui/async-await/in-trait/bad-region.stderr
@@ -0,0 +1,14 @@
+error[E0726]: implicit elided lifetime not allowed here
+  --> $DIR/bad-region.rs:12:6
+   |
+LL | impl BleRadio for Radio {
+   |      ^^^^^^^^ expected lifetime parameter
+   |
+help: indicate the anonymous lifetime
+   |
+LL | impl BleRadio<'_> for Radio {
+   |              ++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0726`.
diff --git a/tests/ui/async-await/issue-74072-lifetime-name-annotations.rs b/tests/ui/async-await/issue-74072-lifetime-name-annotations.rs
index 95683241aba..904d28fb0a7 100644
--- a/tests/ui/async-await/issue-74072-lifetime-name-annotations.rs
+++ b/tests/ui/async-await/issue-74072-lifetime-name-annotations.rs
@@ -12,6 +12,8 @@ pub async fn async_fn(x: &mut i32) -> &i32 {
 
 pub fn async_closure(x: &mut i32) -> impl Future<Output=&i32> {
     (async move || {
+        //~^ ERROR lifetime may not live long enough
+        //~| ERROR temporary value dropped while borrowed
         let y = &*x;
         *x += 1; //~ ERROR cannot assign to `*x` because it is borrowed
         y
@@ -20,6 +22,8 @@ pub fn async_closure(x: &mut i32) -> impl Future<Output=&i32> {
 
 pub fn async_closure_explicit_return_type(x: &mut i32) -> impl Future<Output=&i32> {
     (async move || -> &i32 {
+        //~^ ERROR lifetime may not live long enough
+        //~| ERROR temporary value dropped while borrowed
         let y = &*x;
         *x += 1; //~ ERROR cannot assign to `*x` because it is borrowed
         y
diff --git a/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr b/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr
index 628ba1a4818..bdf2820887c 100644
--- a/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr
+++ b/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr
@@ -11,7 +11,7 @@ LL |     y
    |     - returning this value requires that `*x` is borrowed for `'1`
 
 error[E0506]: cannot assign to `*x` because it is borrowed
-  --> $DIR/issue-74072-lifetime-name-annotations.rs:16:9
+  --> $DIR/issue-74072-lifetime-name-annotations.rs:18:9
    |
 LL |         let y = &*x;
    |                 --- `*x` is borrowed here
@@ -22,20 +22,92 @@ LL |         y
 LL |     })()
    |     - return type of async closure is &'1 i32
 
+error: lifetime may not live long enough
+  --> $DIR/issue-74072-lifetime-name-annotations.rs:14:20
+   |
+LL |       (async move || {
+   |  ______-------------_^
+   | |      |           |
+   | |      |           return type of async closure `{async closure body@$DIR/issue-74072-lifetime-name-annotations.rs:14:20: 20:6}` contains a lifetime `'2`
+   | |      lifetime `'1` represents this closure's body
+LL | |
+LL | |
+LL | |         let y = &*x;
+LL | |         *x += 1;
+LL | |         y
+LL | |     })()
+   | |_____^ returning this value requires that `'1` must outlive `'2`
+   |
+   = note: closure implements `FnMut`, so references to captured variables can't escape the closure
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/issue-74072-lifetime-name-annotations.rs:14:5
+   |
+LL |    pub fn async_closure(x: &mut i32) -> impl Future<Output=&i32> {
+   |                            - let's call the lifetime of this reference `'1`
+LL | //     (async move || {
+LL | ||
+LL | ||
+LL | ||         let y = &*x;
+LL | ||         *x += 1;
+LL | ||         y
+LL | ||     })()
+   | ||______^_- argument requires that borrow lasts for `'1`
+   | |_______|
+   |         creates a temporary value which is freed while still in use
+LL |    }
+   |    - temporary value is freed at the end of this statement
+
 error[E0506]: cannot assign to `*x` because it is borrowed
-  --> $DIR/issue-74072-lifetime-name-annotations.rs:24:9
+  --> $DIR/issue-74072-lifetime-name-annotations.rs:28:9
    |
-LL |     (async move || -> &i32 {
-   |                       - let's call the lifetime of this reference `'1`
 LL |         let y = &*x;
    |                 --- `*x` is borrowed here
 LL |         *x += 1;
    |         ^^^^^^^ `*x` is assigned to here but it was already borrowed
 LL |         y
    |         - returning this value requires that `*x` is borrowed for `'1`
+LL |     })()
+   |     - return type of async closure is &'1 i32
+
+error: lifetime may not live long enough
+  --> $DIR/issue-74072-lifetime-name-annotations.rs:24:28
+   |
+LL |       (async move || -> &i32 {
+   |  ______---------------------_^
+   | |      |                |
+   | |      |                return type of async closure `{async closure body@$DIR/issue-74072-lifetime-name-annotations.rs:24:28: 30:6}` contains a lifetime `'2`
+   | |      lifetime `'1` represents this closure's body
+LL | |
+LL | |
+LL | |         let y = &*x;
+LL | |         *x += 1;
+LL | |         y
+LL | |     })()
+   | |_____^ returning this value requires that `'1` must outlive `'2`
+   |
+   = note: closure implements `FnMut`, so references to captured variables can't escape the closure
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/issue-74072-lifetime-name-annotations.rs:24:5
+   |
+LL |    pub fn async_closure_explicit_return_type(x: &mut i32) -> impl Future<Output=&i32> {
+   |                                                 - let's call the lifetime of this reference `'1`
+LL | //     (async move || -> &i32 {
+LL | ||
+LL | ||
+LL | ||         let y = &*x;
+LL | ||         *x += 1;
+LL | ||         y
+LL | ||     })()
+   | ||______^_- argument requires that borrow lasts for `'1`
+   | |_______|
+   |         creates a temporary value which is freed while still in use
+LL |    }
+   |    - temporary value is freed at the end of this statement
 
 error[E0506]: cannot assign to `*x` because it is borrowed
-  --> $DIR/issue-74072-lifetime-name-annotations.rs:32:9
+  --> $DIR/issue-74072-lifetime-name-annotations.rs:36:9
    |
 LL |         let y = &*x;
    |                 --- `*x` is borrowed here
@@ -46,6 +118,7 @@ LL |         y
 LL |     }
    |     - return type of async block is &'1 i32
 
-error: aborting due to 4 previous errors
+error: aborting due to 8 previous errors
 
-For more information about this error, try `rustc --explain E0506`.
+Some errors have detailed explanations: E0506, E0716.
+For more information about an error, try `rustc --explain E0506`.
diff --git a/tests/ui/auto-traits/auto-trait-validation.fixed b/tests/ui/auto-traits/auto-trait-validation.fixed
index da878ac6222..e37fed9faab 100644
--- a/tests/ui/auto-traits/auto-trait-validation.fixed
+++ b/tests/ui/auto-traits/auto-trait-validation.fixed
@@ -1,4 +1,5 @@
 #![feature(auto_traits)]
+#![allow(dead_code)]
 
 // run-rustfix
 
diff --git a/tests/ui/auto-traits/auto-trait-validation.rs b/tests/ui/auto-traits/auto-trait-validation.rs
index d43055e270b..e209aa13220 100644
--- a/tests/ui/auto-traits/auto-trait-validation.rs
+++ b/tests/ui/auto-traits/auto-trait-validation.rs
@@ -1,4 +1,5 @@
 #![feature(auto_traits)]
+#![allow(dead_code)]
 
 // run-rustfix
 
diff --git a/tests/ui/auto-traits/auto-trait-validation.stderr b/tests/ui/auto-traits/auto-trait-validation.stderr
index 89b63d23d4c..a6e5ac54869 100644
--- a/tests/ui/auto-traits/auto-trait-validation.stderr
+++ b/tests/ui/auto-traits/auto-trait-validation.stderr
@@ -1,5 +1,5 @@
 error[E0567]: auto traits cannot have generic parameters
-  --> $DIR/auto-trait-validation.rs:5:19
+  --> $DIR/auto-trait-validation.rs:6:19
    |
 LL | auto trait Generic<T> {}
    |            -------^^^ help: remove the parameters
@@ -7,7 +7,7 @@ LL | auto trait Generic<T> {}
    |            auto trait cannot have generic parameters
 
 error[E0568]: auto traits cannot have super traits or lifetime bounds
-  --> $DIR/auto-trait-validation.rs:7:17
+  --> $DIR/auto-trait-validation.rs:8:17
    |
 LL | auto trait Bound : Copy {}
    |            -----^^^^^^^ help: remove the super traits or lifetime bounds
@@ -15,7 +15,7 @@ LL | auto trait Bound : Copy {}
    |            auto traits cannot have super traits or lifetime bounds
 
 error[E0568]: auto traits cannot have super traits or lifetime bounds
-  --> $DIR/auto-trait-validation.rs:9:25
+  --> $DIR/auto-trait-validation.rs:10:25
    |
 LL | auto trait LifetimeBound : 'static {}
    |            -------------^^^^^^^^^^ help: remove the super traits or lifetime bounds
@@ -23,7 +23,7 @@ LL | auto trait LifetimeBound : 'static {}
    |            auto traits cannot have super traits or lifetime bounds
 
 error[E0380]: auto traits cannot have associated items
-  --> $DIR/auto-trait-validation.rs:11:25
+  --> $DIR/auto-trait-validation.rs:12:25
    |
 LL | auto trait MyTrait { fn foo() {} }
    |            -------   ---^^^-----
diff --git a/tests/ui/auto-traits/auto-traits.rs b/tests/ui/auto-traits/auto-traits.rs
index 6d8e1a52ec1..1e0fbcc1fdf 100644
--- a/tests/ui/auto-traits/auto-traits.rs
+++ b/tests/ui/auto-traits/auto-traits.rs
@@ -19,8 +19,8 @@ fn take_auto_unsafe<T: AutoUnsafe>(_: T) {}
 
 fn main() {
     // Parse inside functions.
-    auto trait AutoInner {}
-    unsafe auto trait AutoUnsafeInner {}
+    auto trait AutoInner {} //~ WARN trait `AutoInner` is never used
+    unsafe auto trait AutoUnsafeInner {} //~ WARN trait `AutoUnsafeInner` is never used
 
     take_auto(0);
     take_auto(AutoBool(true));
diff --git a/tests/ui/auto-traits/auto-traits.stderr b/tests/ui/auto-traits/auto-traits.stderr
new file mode 100644
index 00000000000..34be8d3f67b
--- /dev/null
+++ b/tests/ui/auto-traits/auto-traits.stderr
@@ -0,0 +1,16 @@
+warning: trait `AutoInner` is never used
+  --> $DIR/auto-traits.rs:22:16
+   |
+LL |     auto trait AutoInner {}
+   |                ^^^^^^^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: trait `AutoUnsafeInner` is never used
+  --> $DIR/auto-traits.rs:23:23
+   |
+LL |     unsafe auto trait AutoUnsafeInner {}
+   |                       ^^^^^^^^^^^^^^^
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/binding/irrefutable-if-let-without-else.fixed b/tests/ui/binding/irrefutable-if-let-without-else.fixed
new file mode 100644
index 00000000000..3d7f4695ca8
--- /dev/null
+++ b/tests/ui/binding/irrefutable-if-let-without-else.fixed
@@ -0,0 +1,25 @@
+// run-rustfix
+enum Enum {
+    Variant(i32),
+}
+struct Struct(i32);
+
+fn foo(x: Enum) -> i32 {
+    let Enum::Variant(value) = x;
+        value
+}
+fn bar(x: Enum) -> i32 {
+    let Enum::Variant(value) = x;
+        let x = value + 1;
+        x
+}
+fn baz(x: Struct) -> i32 {
+    let Struct(value) = x;
+        let x = value + 1;
+        x
+}
+fn main() {
+    let _ = foo(Enum::Variant(42));
+    let _ = bar(Enum::Variant(42));
+    let _ = baz(Struct(42));
+}
diff --git a/tests/ui/binding/irrefutable-if-let-without-else.rs b/tests/ui/binding/irrefutable-if-let-without-else.rs
new file mode 100644
index 00000000000..5aaf4ace3f8
--- /dev/null
+++ b/tests/ui/binding/irrefutable-if-let-without-else.rs
@@ -0,0 +1,28 @@
+// run-rustfix
+enum Enum {
+    Variant(i32),
+}
+struct Struct(i32);
+
+fn foo(x: Enum) -> i32 {
+    if let Enum::Variant(value) = x { //~ ERROR `if` may be missing an `else` clause
+        value
+    }
+}
+fn bar(x: Enum) -> i32 {
+    if let Enum::Variant(value) = x { //~ ERROR `if` may be missing an `else` clause
+        let x = value + 1;
+        x
+    }
+}
+fn baz(x: Struct) -> i32 {
+    if let Struct(value) = x { //~ ERROR `if` may be missing an `else` clause
+        let x = value + 1;
+        x
+    }
+}
+fn main() {
+    let _ = foo(Enum::Variant(42));
+    let _ = bar(Enum::Variant(42));
+    let _ = baz(Struct(42));
+}
diff --git a/tests/ui/binding/irrefutable-if-let-without-else.stderr b/tests/ui/binding/irrefutable-if-let-without-else.stderr
new file mode 100644
index 00000000000..e234cfdd945
--- /dev/null
+++ b/tests/ui/binding/irrefutable-if-let-without-else.stderr
@@ -0,0 +1,61 @@
+error[E0317]: `if` may be missing an `else` clause
+  --> $DIR/irrefutable-if-let-without-else.rs:8:5
+   |
+LL |   fn foo(x: Enum) -> i32 {
+   |                      --- expected `i32` because of this return type
+LL | /     if let Enum::Variant(value) = x {
+LL | |         value
+LL | |     }
+   | |_____^ expected `i32`, found `()`
+   |
+   = note: `if` expressions without `else` evaluate to `()`
+   = help: consider adding an `else` block that evaluates to the expected type
+help: consider using an irrefutable `let` binding instead
+   |
+LL ~     let Enum::Variant(value) = x;
+LL ~         value
+   |
+
+error[E0317]: `if` may be missing an `else` clause
+  --> $DIR/irrefutable-if-let-without-else.rs:13:5
+   |
+LL |   fn bar(x: Enum) -> i32 {
+   |                      --- expected `i32` because of this return type
+LL | /     if let Enum::Variant(value) = x {
+LL | |         let x = value + 1;
+LL | |         x
+LL | |     }
+   | |_____^ expected `i32`, found `()`
+   |
+   = note: `if` expressions without `else` evaluate to `()`
+   = help: consider adding an `else` block that evaluates to the expected type
+help: consider using an irrefutable `let` binding instead
+   |
+LL ~     let Enum::Variant(value) = x;
+LL ~         let x = value + 1;
+LL ~         x
+   |
+
+error[E0317]: `if` may be missing an `else` clause
+  --> $DIR/irrefutable-if-let-without-else.rs:19:5
+   |
+LL |   fn baz(x: Struct) -> i32 {
+   |                        --- expected `i32` because of this return type
+LL | /     if let Struct(value) = x {
+LL | |         let x = value + 1;
+LL | |         x
+LL | |     }
+   | |_____^ expected `i32`, found `()`
+   |
+   = note: `if` expressions without `else` evaluate to `()`
+   = help: consider adding an `else` block that evaluates to the expected type
+help: consider using an irrefutable `let` binding instead
+   |
+LL ~     let Struct(value) = x;
+LL ~         let x = value + 1;
+LL ~         x
+   |
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0317`.
diff --git a/tests/ui/box/unit/unique-object-noncopyable.stderr b/tests/ui/box/unit/unique-object-noncopyable.stderr
index 49547872d1a..8ea6edb48a7 100644
--- a/tests/ui/box/unit/unique-object-noncopyable.stderr
+++ b/tests/ui/box/unit/unique-object-noncopyable.stderr
@@ -12,6 +12,9 @@ LL |     let _z = y.clone();
            which is required by `Box<dyn Foo>: Clone`
            `dyn Foo: Clone`
            which is required by `Box<dyn Foo>: Clone`
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following trait defines an item `clone`, perhaps you need to implement it:
+           candidate #1: `Clone`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/box/unit/unique-pinned-nocopy.stderr b/tests/ui/box/unit/unique-pinned-nocopy.stderr
index d2bf72249c4..69428604b19 100644
--- a/tests/ui/box/unit/unique-pinned-nocopy.stderr
+++ b/tests/ui/box/unit/unique-pinned-nocopy.stderr
@@ -10,9 +10,6 @@ LL |     let _j = i.clone();
    = note: the following trait bounds were not satisfied:
            `R: Clone`
            which is required by `Box<R>: Clone`
-   = help: items from traits can only be used if the trait is implemented and in scope
-   = note: the following trait defines an item `clone`, perhaps you need to implement it:
-           candidate #1: `Clone`
 help: consider annotating `R` with `#[derive(Clone)]`
    |
 LL + #[derive(Clone)]
diff --git a/tests/ui/builtin-superkinds/builtin-superkinds-in-metadata2.rs b/tests/ui/builtin-superkinds/builtin-superkinds-in-metadata2.rs
index 2edc52c6f55..7e8820cb2c6 100644
--- a/tests/ui/builtin-superkinds/builtin-superkinds-in-metadata2.rs
+++ b/tests/ui/builtin-superkinds/builtin-superkinds-in-metadata2.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 #![allow(unused_imports)]
 
diff --git a/tests/ui/builtin-superkinds/builtin-superkinds-simple2.rs b/tests/ui/builtin-superkinds/builtin-superkinds-simple2.rs
index 8d247715784..50914b1de53 100644
--- a/tests/ui/builtin-superkinds/builtin-superkinds-simple2.rs
+++ b/tests/ui/builtin-superkinds/builtin-superkinds-simple2.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 // Simple test case of implementing a trait with super-builtin-kinds.
 
 // pretty-expanded FIXME #23616
diff --git a/tests/ui/builtin-superkinds/builtin-superkinds-typaram.rs b/tests/ui/builtin-superkinds/builtin-superkinds-typaram.rs
index f999dfff786..0577acc572a 100644
--- a/tests/ui/builtin-superkinds/builtin-superkinds-typaram.rs
+++ b/tests/ui/builtin-superkinds/builtin-superkinds-typaram.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 // Tests correct implementation of traits with super-builtin-kinds
 // using a bounded type parameter.
 
diff --git a/tests/ui/cast/cast-rfc0401-vtable-kinds.rs b/tests/ui/cast/cast-rfc0401-vtable-kinds.rs
index 249481467e6..be6a6bb8b17 100644
--- a/tests/ui/cast/cast-rfc0401-vtable-kinds.rs
+++ b/tests/ui/cast/cast-rfc0401-vtable-kinds.rs
@@ -8,7 +8,7 @@ trait Foo<T> {
     fn foo(&self, _: T) -> u32 { 42 }
 }
 
-trait Bar {
+trait Bar { //~ WARN trait `Bar` is never used
     fn bar(&self) { println!("Bar!"); }
 }
 
diff --git a/tests/ui/cast/cast-rfc0401-vtable-kinds.stderr b/tests/ui/cast/cast-rfc0401-vtable-kinds.stderr
new file mode 100644
index 00000000000..952687e98d0
--- /dev/null
+++ b/tests/ui/cast/cast-rfc0401-vtable-kinds.stderr
@@ -0,0 +1,10 @@
+warning: trait `Bar` is never used
+  --> $DIR/cast-rfc0401-vtable-kinds.rs:11:7
+   |
+LL | trait Bar {
+   |       ^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/cast/fat-ptr-cast-rpass.rs b/tests/ui/cast/fat-ptr-cast-rpass.rs
index f5747eb8b96..c79468caddd 100644
--- a/tests/ui/cast/fat-ptr-cast-rpass.rs
+++ b/tests/ui/cast/fat-ptr-cast-rpass.rs
@@ -3,7 +3,7 @@
 #![feature(ptr_metadata)]
 
 trait Foo {
-    fn foo(&self) {}
+    fn foo(&self) {} //~ WARN method `foo` is never used
 }
 
 struct Bar;
diff --git a/tests/ui/cast/fat-ptr-cast-rpass.stderr b/tests/ui/cast/fat-ptr-cast-rpass.stderr
new file mode 100644
index 00000000000..d01688e0cc3
--- /dev/null
+++ b/tests/ui/cast/fat-ptr-cast-rpass.stderr
@@ -0,0 +1,12 @@
+warning: method `foo` is never used
+  --> $DIR/fat-ptr-cast-rpass.rs:6:8
+   |
+LL | trait Foo {
+   |       --- method in this trait
+LL |     fn foo(&self) {}
+   |        ^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.rs b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.rs
new file mode 100644
index 00000000000..a6e68e1b710
--- /dev/null
+++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.rs
@@ -0,0 +1,12 @@
+// #120427
+// This test checks we won't suggest more than 3 span suggestions for cfg names
+//
+// check-pass
+// compile-flags: -Z unstable-options
+// compile-flags: --check-cfg=cfg(foo,values("value")) --check-cfg=cfg(bar,values("value")) --check-cfg=cfg(bee,values("value")) --check-cfg=cfg(cow,values("value"))
+
+#[cfg(value)]
+//~^ WARNING unexpected `cfg` condition name: `value`
+fn x() {}
+
+fn main() {}
diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr
new file mode 100644
index 00000000000..82d471d715b
--- /dev/null
+++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr
@@ -0,0 +1,13 @@
+warning: unexpected `cfg` condition name: `value`
+  --> $DIR/cfg-value-for-cfg-name-duplicate.rs:8:7
+   |
+LL | #[cfg(value)]
+   |       ^^^^^
+   |
+   = help: expected names are: `bar`, `bee`, `cow`, `debug_assertions`, `doc`, `doctest`, `foo`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows`
+   = help: to expect this configuration use `--check-cfg=cfg(value)`
+   = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.rs b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.rs
new file mode 100644
index 00000000000..edde6244ed1
--- /dev/null
+++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.rs
@@ -0,0 +1,12 @@
+// #120427
+// This test checks that when a single cfg has a value for user's specified name
+//
+// check-pass
+// compile-flags: -Z unstable-options
+// compile-flags: --check-cfg=cfg(foo,values("my_value")) --check-cfg=cfg(bar,values("my_value"))
+
+#[cfg(my_value)]
+//~^ WARNING unexpected `cfg` condition name: `my_value`
+fn x() {}
+
+fn main() {}
diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr
new file mode 100644
index 00000000000..b88ee71a156
--- /dev/null
+++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr
@@ -0,0 +1,21 @@
+warning: unexpected `cfg` condition name: `my_value`
+  --> $DIR/cfg-value-for-cfg-name-multiple.rs:8:7
+   |
+LL | #[cfg(my_value)]
+   |       ^^^^^^^^
+   |
+   = help: expected names are: `bar`, `debug_assertions`, `doc`, `doctest`, `foo`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows`
+   = help: to expect this configuration use `--check-cfg=cfg(my_value)`
+   = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
+   = note: `#[warn(unexpected_cfgs)]` on by default
+help: found config with similar value
+   |
+LL | #[cfg(foo = "my_value")]
+   |       ~~~~~~~~~~~~~~~~
+help: found config with similar value
+   |
+LL | #[cfg(bar = "my_value")]
+   |       ~~~~~~~~~~~~~~~~
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name.rs b/tests/ui/check-cfg/cfg-value-for-cfg-name.rs
new file mode 100644
index 00000000000..7a0c345b7ca
--- /dev/null
+++ b/tests/ui/check-cfg/cfg-value-for-cfg-name.rs
@@ -0,0 +1,18 @@
+// #120427
+// This test checks that when a single cfg has a value for user's specified name
+// suggest to use `#[cfg(target_os = "linux")]` instead of `#[cfg(linux)]`
+//
+// check-pass
+// compile-flags: -Z unstable-options
+// compile-flags: --check-cfg=cfg()
+
+#[cfg(linux)]
+//~^ WARNING unexpected `cfg` condition name: `linux`
+fn x() {}
+
+// will not suggest if the cfg has a value
+#[cfg(linux = "os-name")]
+//~^ WARNING unexpected `cfg` condition name: `linux`
+fn y() {}
+
+fn main() {}
diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr
new file mode 100644
index 00000000000..c0447551424
--- /dev/null
+++ b/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr
@@ -0,0 +1,22 @@
+warning: unexpected `cfg` condition name: `linux`
+  --> $DIR/cfg-value-for-cfg-name.rs:9:7
+   |
+LL | #[cfg(linux)]
+   |       ^^^^^ help: found config with similar value: `target_os = "linux"`
+   |
+   = help: expected names are: `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows`
+   = help: to expect this configuration use `--check-cfg=cfg(linux)`
+   = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `cfg` condition name: `linux`
+  --> $DIR/cfg-value-for-cfg-name.rs:14:7
+   |
+LL | #[cfg(linux = "os-name")]
+   |       ^^^^^^^^^^^^^^^^^
+   |
+   = help: to expect this configuration use `--check-cfg=cfg(linux, values("os-name"))`
+   = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_1.stderr b/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_1.stderr
index c83ba41976b..8a2aaade665 100644
--- a/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_1.stderr
+++ b/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_1.stderr
@@ -5,8 +5,19 @@ LL |             NUMBER_POINTER => (),
    |             ^^^^^^^^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
    = note: `#[warn(pointer_structural_match)]` on by default
 
 warning: 1 warning emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/match-edge-cases_1.rs:29:13
+   |
+LL |             NUMBER_POINTER => (),
+   |             ^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
diff --git a/tests/ui/closures/binder/async-closure-with-binder.rs b/tests/ui/closures/binder/async-closure-with-binder.rs
index 4fa599d37cb..69d30f369e9 100644
--- a/tests/ui/closures/binder/async-closure-with-binder.rs
+++ b/tests/ui/closures/binder/async-closure-with-binder.rs
@@ -1,8 +1,9 @@
 // edition:2021
+// check-pass
+
 #![feature(closure_lifetime_binder)]
 #![feature(async_closure)]
+
 fn main() {
-    for<'a> async || ();
-    //~^ ERROR `for<...>` binders on `async` closures are not currently supported
-    //~^^ ERROR implicit types in closure signatures are forbidden when `for<...>` is present
+    for<'a> async || -> () {};
 }
diff --git a/tests/ui/closures/binder/async-closure-with-binder.stderr b/tests/ui/closures/binder/async-closure-with-binder.stderr
deleted file mode 100644
index 1d4628b1a49..00000000000
--- a/tests/ui/closures/binder/async-closure-with-binder.stderr
+++ /dev/null
@@ -1,16 +0,0 @@
-error: `for<...>` binders on `async` closures are not currently supported
-  --> $DIR/async-closure-with-binder.rs:5:5
-   |
-LL |     for<'a> async || ();
-   |     ^^^^^^^
-
-error: implicit types in closure signatures are forbidden when `for<...>` is present
-  --> $DIR/async-closure-with-binder.rs:5:5
-   |
-LL |     for<'a> async || ();
-   |     -------^^^^^^^^^
-   |     |
-   |     `for<...>` is here
-
-error: aborting due to 2 previous errors
-
diff --git a/tests/ui/coercion/issue-14589.rs b/tests/ui/coercion/issue-14589.rs
index f92385f8d72..6f95b30be06 100644
--- a/tests/ui/coercion/issue-14589.rs
+++ b/tests/ui/coercion/issue-14589.rs
@@ -19,6 +19,6 @@ impl<T> Test<T> {
     fn send(&self, _: T) {}
 }
 
-trait Foo { fn dummy(&self) { }}
+trait Foo { fn dummy(&self) { }} //~ WARN method `dummy` is never used
 struct Output(#[allow(dead_code)] isize);
 impl Foo for Output {}
diff --git a/tests/ui/coercion/issue-14589.stderr b/tests/ui/coercion/issue-14589.stderr
new file mode 100644
index 00000000000..37b7fce7462
--- /dev/null
+++ b/tests/ui/coercion/issue-14589.stderr
@@ -0,0 +1,12 @@
+warning: method `dummy` is never used
+  --> $DIR/issue-14589.rs:22:16
+   |
+LL | trait Foo { fn dummy(&self) { }}
+   |       ---      ^^^^^
+   |       |
+   |       method in this trait
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/coherence/coherence-multidispatch-tuple.rs b/tests/ui/coherence/coherence-multidispatch-tuple.rs
index fa1d4bbb496..b04b2a296b5 100644
--- a/tests/ui/coherence/coherence-multidispatch-tuple.rs
+++ b/tests/ui/coherence/coherence-multidispatch-tuple.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 #![allow(unused_imports)]
 // pretty-expanded FIXME #23616
 
diff --git a/tests/ui/const-generics/associated-type-bound.rs b/tests/ui/const-generics/associated-type-bound.rs
index 3044736b47e..0a57352c10d 100644
--- a/tests/ui/const-generics/associated-type-bound.rs
+++ b/tests/ui/const-generics/associated-type-bound.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 trait Bar<const N: usize> {}
 
 trait Foo<const N: usize> {
diff --git a/tests/ui/const-generics/condition-in-trait-const-arg.rs b/tests/ui/const-generics/condition-in-trait-const-arg.rs
index 6f85237cf0a..74a663a53ec 100644
--- a/tests/ui/const-generics/condition-in-trait-const-arg.rs
+++ b/tests/ui/const-generics/condition-in-trait-const-arg.rs
@@ -1,5 +1,5 @@
 // Checks that `impl Trait<{anon_const}> for Type` evaluates successfully.
-// run-pass
+// check-pass
 // revisions: full min
 
 #![cfg_attr(full, feature(generic_const_exprs))]
diff --git a/tests/ui/const-generics/dyn-supertraits.rs b/tests/ui/const-generics/dyn-supertraits.rs
index 3dee326a186..bb492452982 100644
--- a/tests/ui/const-generics/dyn-supertraits.rs
+++ b/tests/ui/const-generics/dyn-supertraits.rs
@@ -4,7 +4,7 @@ trait Foo<const N: usize> {
     fn myfun(&self) -> usize;
 }
 trait Bar<const N: usize> : Foo<N> {}
-trait Baz: Foo<3> {}
+trait Baz: Foo<3> {} //~ WARN trait `Baz` is never used
 
 struct FooType<const N: usize>;
 struct BarType<const N: usize>;
@@ -23,10 +23,10 @@ impl Foo<3> for BazType {
 impl Baz for BazType {}
 
 trait Foz {}
-trait Boz: Foo<3> + Foz {}
+trait Boz: Foo<3> + Foz {} //~ WARN trait `Boz` is never used
 trait Bok<const N: usize>: Foo<N> + Foz {}
 
-struct FozType;
+struct FozType; //~ WARN struct `FozType` is never constructed
 struct BozType;
 struct BokType<const N: usize>;
 
diff --git a/tests/ui/const-generics/dyn-supertraits.stderr b/tests/ui/const-generics/dyn-supertraits.stderr
new file mode 100644
index 00000000000..38b67ef4403
--- /dev/null
+++ b/tests/ui/const-generics/dyn-supertraits.stderr
@@ -0,0 +1,22 @@
+warning: trait `Baz` is never used
+  --> $DIR/dyn-supertraits.rs:7:7
+   |
+LL | trait Baz: Foo<3> {}
+   |       ^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: trait `Boz` is never used
+  --> $DIR/dyn-supertraits.rs:26:7
+   |
+LL | trait Boz: Foo<3> + Foz {}
+   |       ^^^
+
+warning: struct `FozType` is never constructed
+  --> $DIR/dyn-supertraits.rs:29:8
+   |
+LL | struct FozType;
+   |        ^^^^^^^
+
+warning: 3 warnings emitted
+
diff --git a/tests/ui/const-generics/issues/issue-69654-run-pass.rs b/tests/ui/const-generics/issues/issue-69654-run-pass.rs
index 63d7fde78ac..21d6270b1fa 100644
--- a/tests/ui/const-generics/issues/issue-69654-run-pass.rs
+++ b/tests/ui/const-generics/issues/issue-69654-run-pass.rs
@@ -1,5 +1,5 @@
 // run-pass
-trait Bar<T> {}
+trait Bar<T> {} //~ WARN trait `Bar` is never used
 impl<T> Bar<T> for [u8; 7] {}
 
 struct Foo<const N: usize> {}
diff --git a/tests/ui/const-generics/issues/issue-69654-run-pass.stderr b/tests/ui/const-generics/issues/issue-69654-run-pass.stderr
new file mode 100644
index 00000000000..7b3cd4f375f
--- /dev/null
+++ b/tests/ui/const-generics/issues/issue-69654-run-pass.stderr
@@ -0,0 +1,10 @@
+warning: trait `Bar` is never used
+  --> $DIR/issue-69654-run-pass.rs:2:7
+   |
+LL | trait Bar<T> {}
+   |       ^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/consts/const-block-item.rs b/tests/ui/consts/const-block-item.rs
index cf0d4441d4a..a04f4db263b 100644
--- a/tests/ui/consts/const-block-item.rs
+++ b/tests/ui/consts/const-block-item.rs
@@ -2,7 +2,7 @@
 #![allow(unused_imports)]
 
 mod foo {
-    pub trait Value {
+    pub trait Value { //~ WARN trait `Value` is never used
         fn value(&self) -> usize;
     }
 }
diff --git a/tests/ui/consts/const-block-item.stderr b/tests/ui/consts/const-block-item.stderr
new file mode 100644
index 00000000000..04658742b56
--- /dev/null
+++ b/tests/ui/consts/const-block-item.stderr
@@ -0,0 +1,10 @@
+warning: trait `Value` is never used
+  --> $DIR/const-block-item.rs:5:15
+   |
+LL |     pub trait Value {
+   |               ^^^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.rs b/tests/ui/consts/const-eval/raw-pointer-ub.rs
index 3341f3c78e0..47105de453c 100644
--- a/tests/ui/consts/const-eval/raw-pointer-ub.rs
+++ b/tests/ui/consts/const-eval/raw-pointer-ub.rs
@@ -1,4 +1,4 @@
-#![feature(const_mut_refs)]
+#![feature(const_mut_refs, const_intrinsic_copy)]
 
 
 const MISALIGNED_LOAD: () = unsafe {
diff --git a/tests/ui/consts/const_in_pattern/accept_structural.rs b/tests/ui/consts/const_in_pattern/accept_structural.rs
index 1f56f581c02..69b4e75c622 100644
--- a/tests/ui/consts/const_in_pattern/accept_structural.rs
+++ b/tests/ui/consts/const_in_pattern/accept_structural.rs
@@ -63,4 +63,18 @@ fn main() {
 
     const ADDR_OF: &OND = &None;
     match &None { ADDR_OF => dbg!(ADDR_OF),  _ => panic!("whoops"), };
+
+    // These ones are more subtle: the final value is fine, but statically analyzing the expression
+    // that computes the value would likely (incorrectly) have us conclude that this may match on
+    // values that do not have structural equality.
+    const INDEX: Option<NoDerive> = [None, Some(NoDerive(10))][0];
+    match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), };
+
+    const fn build() -> Option<NoDerive> { None }
+    const CALL: Option<NoDerive> = build();
+    match None { Some(_) => panic!("whoops"), CALL => dbg!(CALL), };
+
+    impl NoDerive { const fn none() -> Option<NoDerive> { None } }
+    const METHOD_CALL: Option<NoDerive> = NoDerive::none();
+    match None { Some(_) => panic!("whoops"), METHOD_CALL => dbg!(METHOD_CALL), };
 }
diff --git a/tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs b/tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs
index a38731ceb8a..ac89b7925ff 100644
--- a/tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs
+++ b/tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs
@@ -12,6 +12,7 @@ impl PartialEq for CustomEq {
 }
 
 #[derive(PartialEq, Eq)]
+#[allow(unused)]
 enum Foo {
     Bar,
     Baz,
@@ -21,7 +22,7 @@ enum Foo {
 const BAR_BAZ: Foo = if 42 == 42 {
     Foo::Bar
 } else {
-    Foo::Baz
+    Foo::Qux(CustomEq) // dead arm
 };
 
 fn main() {
diff --git a/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.rs b/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.rs
deleted file mode 100644
index 34b1422dfb3..00000000000
--- a/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-// check-pass
-
-struct CustomEq;
-
-impl Eq for CustomEq {}
-impl PartialEq for CustomEq {
-    fn eq(&self, _: &Self) -> bool {
-        false
-    }
-}
-
-#[derive(PartialEq, Eq)]
-enum Foo {
-    Bar,
-    Baz,
-    Qux(CustomEq),
-}
-
-// We know that `BAR_BAZ` will always be `Foo::Bar` and thus eligible for structural matching, but
-// dataflow will be more conservative.
-const BAR_BAZ: Foo = if 42 == 42 {
-    Foo::Bar
-} else {
-    Foo::Qux(CustomEq)
-};
-
-fn main() {
-    match Foo::Qux(CustomEq) {
-        BAR_BAZ => panic!(),
-        //~^ WARN must be annotated with `#[derive(PartialEq)]`
-        //~| NOTE the traits must be derived
-        //~| NOTE StructuralPartialEq.html for details
-        //~| WARN this was previously accepted
-        //~| NOTE see issue #73448
-        //~| NOTE `#[warn(nontrivial_structural_match)]` on by default
-        _ => {}
-    }
-}
diff --git a/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr b/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr
deleted file mode 100644
index c473c00f8db..00000000000
--- a/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-warning: to use a constant of type `CustomEq` in a pattern, the constant's initializer must be trivial or `CustomEq` must be annotated with `#[derive(PartialEq)]`
-  --> $DIR/custom-eq-branch-warn.rs:29:9
-   |
-LL |         BAR_BAZ => panic!(),
-   |         ^^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #73448 <https://github.com/rust-lang/rust/issues/73448>
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
-   = note: `#[warn(nontrivial_structural_match)]` on by default
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr b/tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr
index 1546f23908c..bc1015c1734 100644
--- a/tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr
+++ b/tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr
@@ -5,7 +5,7 @@ LL |         C => {}
    |         ^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 note: the lint level is defined here
   --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:1:9
    |
@@ -19,7 +19,7 @@ LL |         C_INNER => {}
    |         ^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:30:9
@@ -28,7 +28,7 @@ LL |         D => {}
    |         ^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:36:9
@@ -37,7 +37,67 @@ LL |         STR => {}
    |         ^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 error: aborting due to 4 previous errors
 
+Future incompatibility report: Future breakage diagnostic:
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:10:9
+   |
+LL |         C => {}
+   |         ^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+note: the lint level is defined here
+  --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:1:9
+   |
+LL | #![deny(pointer_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:18:9
+   |
+LL |         C_INNER => {}
+   |         ^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+note: the lint level is defined here
+  --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:1:9
+   |
+LL | #![deny(pointer_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:30:9
+   |
+LL |         D => {}
+   |         ^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+note: the lint level is defined here
+  --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:1:9
+   |
+LL | #![deny(pointer_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:36:9
+   |
+LL |         STR => {}
+   |         ^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+note: the lint level is defined here
+  --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:1:9
+   |
+LL | #![deny(pointer_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/tests/ui/consts/const_in_pattern/issue-44333.stderr b/tests/ui/consts/const_in_pattern/issue-44333.stderr
index 441aeecbc6d..f5931f0cad0 100644
--- a/tests/ui/consts/const_in_pattern/issue-44333.stderr
+++ b/tests/ui/consts/const_in_pattern/issue-44333.stderr
@@ -5,7 +5,7 @@ LL |         FOO => println!("foo"),
    |         ^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 note: the lint level is defined here
   --> $DIR/issue-44333.rs:3:9
    |
@@ -19,7 +19,37 @@ LL |         BAR => println!("bar"),
    |         ^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: 2 warnings emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/issue-44333.rs:19:9
+   |
+LL |         FOO => println!("foo"),
+   |         ^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+note: the lint level is defined here
+  --> $DIR/issue-44333.rs:3:9
+   |
+LL | #![warn(pointer_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/issue-44333.rs:21:9
+   |
+LL |         BAR => println!("bar"),
+   |         ^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+note: the lint level is defined here
+  --> $DIR/issue-44333.rs:3:9
+   |
+LL | #![warn(pointer_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/tests/ui/consts/const_in_pattern/issue-73431.stderr b/tests/ui/consts/const_in_pattern/issue-73431.stderr
deleted file mode 100644
index c82dea4aa50..00000000000
--- a/tests/ui/consts/const_in_pattern/issue-73431.stderr
+++ /dev/null
@@ -1 +0,0 @@
-WARN rustc_mir_build::thir::pattern::const_to_pat MIR const-checker found novel structural match violation. See #73448.
diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.rs b/tests/ui/consts/const_in_pattern/reject_non_structural.rs
index 196930baed5..71d4138104d 100644
--- a/tests/ui/consts/const_in_pattern/reject_non_structural.rs
+++ b/tests/ui/consts/const_in_pattern/reject_non_structural.rs
@@ -100,5 +100,5 @@ fn main() {
     //~| NOTE the traits must be derived
     //~| NOTE StructuralPartialEq.html for details
     //~| WARN previously accepted by the compiler but is being phased out
-    //~| NOTE for more information, see issue #62411
+    //~| NOTE for more information, see
 }
diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr
index da32b6d698b..2c7aaf89aa7 100644
--- a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr
+++ b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr
@@ -86,7 +86,7 @@ LL |     match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops")
    |                             ^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 note: the lint level is defined here
@@ -97,3 +97,20 @@ LL | #![warn(indirect_structural_match)]
 
 error: aborting due to 9 previous errors; 1 warning emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
+  --> $DIR/reject_non_structural.rs:98:29
+   |
+LL |     match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), };
+   |                             ^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: the traits must be derived, manual `impl`s are not sufficient
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+note: the lint level is defined here
+  --> $DIR/reject_non_structural.rs:14:9
+   |
+LL | #![warn(indirect_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/tests/ui/consts/const_in_pattern/warn_corner_cases.rs b/tests/ui/consts/const_in_pattern/warn_corner_cases.rs
deleted file mode 100644
index 75f1965921c..00000000000
--- a/tests/ui/consts/const_in_pattern/warn_corner_cases.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-// run-pass
-
-// This test is checking our logic for structural match checking by enumerating
-// the different kinds of const expressions. This test is collecting cases where
-// we have accepted the const expression as a pattern in the past but we want
-// to begin warning the user that a future version of Rust may start rejecting
-// such const expressions.
-
-// The specific corner cases we are exploring here are instances where the
-// const-evaluator computes a value that *does* meet the conditions for
-// structural-match, but the const expression itself has abstractions (like
-// calls to const functions) that may fit better with a type-based analysis
-// rather than a commitment to a specific value.
-
-#![warn(indirect_structural_match)]
-
-#[derive(Copy, Clone, Debug)]
-struct NoDerive(#[allow(dead_code)] u32);
-
-// This impl makes `NoDerive` irreflexive.
-impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
-impl Eq for NoDerive { }
-
-fn main() {
-    const INDEX: Option<NoDerive> = [None, Some(NoDerive(10))][0];
-    match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), };
-    //~^ WARN must be annotated with `#[derive(PartialEq)]`
-    //~| WARN this was previously accepted
-
-    const fn build() -> Option<NoDerive> { None }
-    const CALL: Option<NoDerive> = build();
-    match None { Some(_) => panic!("whoops"), CALL => dbg!(CALL), };
-    //~^ WARN must be annotated with `#[derive(PartialEq)]`
-    //~| WARN this was previously accepted
-
-    impl NoDerive { const fn none() -> Option<NoDerive> { None } }
-    const METHOD_CALL: Option<NoDerive> = NoDerive::none();
-    match None { Some(_) => panic!("whoops"), METHOD_CALL => dbg!(METHOD_CALL), };
-    //~^ WARN must be annotated with `#[derive(PartialEq)]`
-    //~| WARN this was previously accepted
-}
diff --git a/tests/ui/consts/const_in_pattern/warn_corner_cases.stderr b/tests/ui/consts/const_in_pattern/warn_corner_cases.stderr
deleted file mode 100644
index 8ffd035ebec..00000000000
--- a/tests/ui/consts/const_in_pattern/warn_corner_cases.stderr
+++ /dev/null
@@ -1,36 +0,0 @@
-warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq)]`
-  --> $DIR/warn_corner_cases.rs:26:47
-   |
-LL |     match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), };
-   |                                               ^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #73448 <https://github.com/rust-lang/rust/issues/73448>
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
-   = note: `#[warn(nontrivial_structural_match)]` on by default
-
-warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq)]`
-  --> $DIR/warn_corner_cases.rs:32:47
-   |
-LL |     match None { Some(_) => panic!("whoops"), CALL => dbg!(CALL), };
-   |                                               ^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #73448 <https://github.com/rust-lang/rust/issues/73448>
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
-
-warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq)]`
-  --> $DIR/warn_corner_cases.rs:38:47
-   |
-LL |     match None { Some(_) => panic!("whoops"), METHOD_CALL => dbg!(METHOD_CALL), };
-   |                                               ^^^^^^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #73448 <https://github.com/rust-lang/rust/issues/73448>
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
-
-warning: 3 warnings emitted
-
diff --git a/tests/ui/consts/issue-89088.stderr b/tests/ui/consts/issue-89088.stderr
new file mode 100644
index 00000000000..d5c5f76b90a
--- /dev/null
+++ b/tests/ui/consts/issue-89088.stderr
@@ -0,0 +1,17 @@
+Future incompatibility report: Future breakage diagnostic:
+warning: to use a constant of type `Cow<'_, str>` in a pattern, `Cow<'_, str>` must be annotated with `#[derive(PartialEq)]`
+  --> $DIR/issue-89088.rs:19:9
+   |
+LL |         FOO => todo!(),
+   |         ^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: the traits must be derived, manual `impl`s are not sufficient
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+note: the lint level is defined here
+  --> $DIR/issue-89088.rs:5:10
+   |
+LL | #![allow(indirect_structural_match)]
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/tests/ui/consts/underscore_const_names.rs b/tests/ui/consts/underscore_const_names.rs
index d0e625bf199..e2ae5a9d53a 100644
--- a/tests/ui/consts/underscore_const_names.rs
+++ b/tests/ui/consts/underscore_const_names.rs
@@ -2,12 +2,12 @@
 
 #![deny(unused)]
 
-trait Trt {}
+pub trait Trt {}
 pub struct Str {}
 impl Trt for Str {}
 
 macro_rules! check_impl {
-    ($struct:ident,$trait:ident) => {
+    ($struct:ident, $trait:ident) => {
         const _ : () = {
             use std::marker::PhantomData;
             struct ImplementsTrait<T: $trait>(PhantomData<T>);
diff --git a/tests/ui/default-method-parsing.rs b/tests/ui/default-method-parsing.rs
index 9ffb8d94a59..5001d58f0a4 100644
--- a/tests/ui/default-method-parsing.rs
+++ b/tests/ui/default-method-parsing.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 // pretty-expanded FIXME #23616
 
 trait Foo {
diff --git a/tests/ui/delegation/target-expr-pass.rs b/tests/ui/delegation/target-expr-pass.rs
index 56068dfce01..4ccb81c292a 100644
--- a/tests/ui/delegation/target-expr-pass.rs
+++ b/tests/ui/delegation/target-expr-pass.rs
@@ -14,14 +14,14 @@ reuse to_reuse::foo {{
     x + self
 }}
 
-trait Trait {
+trait Trait { //~ WARN trait `Trait` is never used
     fn bar(&self, x: i32) -> i32 { x }
 }
 
-struct F;
+struct F; //~ WARN struct `F` is never constructed
 impl Trait for F {}
 
-struct S(F);
+struct S(F); //~ WARN struct `S` is never constructed
 impl Trait for S {
     reuse <F as Trait>::bar {
         #[allow(unused_imports)]
diff --git a/tests/ui/delegation/target-expr-pass.stderr b/tests/ui/delegation/target-expr-pass.stderr
index ea594f8a26a..dd1f3a14e0b 100644
--- a/tests/ui/delegation/target-expr-pass.stderr
+++ b/tests/ui/delegation/target-expr-pass.stderr
@@ -7,5 +7,25 @@ LL | #![feature(fn_delegation)]
    = note: see issue #118212 <https://github.com/rust-lang/rust/issues/118212> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-warning: 1 warning emitted
+warning: trait `Trait` is never used
+  --> $DIR/target-expr-pass.rs:17:7
+   |
+LL | trait Trait {
+   |       ^^^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: struct `F` is never constructed
+  --> $DIR/target-expr-pass.rs:21:8
+   |
+LL | struct F;
+   |        ^
+
+warning: struct `S` is never constructed
+  --> $DIR/target-expr-pass.rs:24:8
+   |
+LL | struct S(F);
+   |        ^
+
+warning: 4 warnings emitted
 
diff --git a/tests/ui/derives/derive-assoc-type-not-impl.stderr b/tests/ui/derives/derive-assoc-type-not-impl.stderr
index 61268ffc7f8..13ba80243a5 100644
--- a/tests/ui/derives/derive-assoc-type-not-impl.stderr
+++ b/tests/ui/derives/derive-assoc-type-not-impl.stderr
@@ -15,9 +15,6 @@ note: trait bound `NotClone: Clone` was not satisfied
    |
 LL | #[derive(Clone)]
    |          ^^^^^ unsatisfied trait bound introduced in this `derive` macro
-   = help: items from traits can only be used if the trait is implemented and in scope
-   = note: the following trait defines an item `clone`, perhaps you need to implement it:
-           candidate #1: `Clone`
 help: consider annotating `NotClone` with `#[derive(Clone)]`
    |
 LL + #[derive(Clone)]
diff --git a/tests/ui/deriving/deriving-bounds.rs b/tests/ui/deriving/deriving-bounds.rs
index f0b921d0e7c..f3e7cf99437 100644
--- a/tests/ui/deriving/deriving-bounds.rs
+++ b/tests/ui/deriving/deriving-bounds.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 #[derive(Copy, Clone)]
 struct Test;
 
diff --git a/tests/ui/drop/drop-struct-as-object.rs b/tests/ui/drop/drop-struct-as-object.rs
index 377027a4fc5..1aa68777042 100644
--- a/tests/ui/drop/drop-struct-as-object.rs
+++ b/tests/ui/drop/drop-struct-as-object.rs
@@ -12,7 +12,7 @@ struct Cat {
 }
 
 trait Dummy {
-    fn get(&self) -> usize;
+    fn get(&self) -> usize; //~ WARN method `get` is never used
 }
 
 impl Dummy for Cat {
diff --git a/tests/ui/drop/drop-struct-as-object.stderr b/tests/ui/drop/drop-struct-as-object.stderr
new file mode 100644
index 00000000000..10527c968ed
--- /dev/null
+++ b/tests/ui/drop/drop-struct-as-object.stderr
@@ -0,0 +1,12 @@
+warning: method `get` is never used
+  --> $DIR/drop-struct-as-object.rs:15:8
+   |
+LL | trait Dummy {
+   |       ----- method in this trait
+LL |     fn get(&self) -> usize;
+   |        ^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/dynamically-sized-types/dst-coercions.rs b/tests/ui/dynamically-sized-types/dst-coercions.rs
index 66688e93fb8..1efdf1de0e6 100644
--- a/tests/ui/dynamically-sized-types/dst-coercions.rs
+++ b/tests/ui/dynamically-sized-types/dst-coercions.rs
@@ -5,7 +5,7 @@
 // pretty-expanded FIXME #23616
 
 struct S;
-trait T { fn dummy(&self) { } }
+trait T { fn dummy(&self) { } } //~ WARN method `dummy` is never used
 impl T for S {}
 
 pub fn main() {
diff --git a/tests/ui/dynamically-sized-types/dst-coercions.stderr b/tests/ui/dynamically-sized-types/dst-coercions.stderr
new file mode 100644
index 00000000000..e4721ce50a0
--- /dev/null
+++ b/tests/ui/dynamically-sized-types/dst-coercions.stderr
@@ -0,0 +1,12 @@
+warning: method `dummy` is never used
+  --> $DIR/dst-coercions.rs:8:14
+   |
+LL | trait T { fn dummy(&self) { } }
+   |       -      ^^^^^
+   |       |
+   |       method in this trait
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/empty-type-parameter-list.rs b/tests/ui/empty-type-parameter-list.rs
index e168cd03b27..23d09fbf281 100644
--- a/tests/ui/empty-type-parameter-list.rs
+++ b/tests/ui/empty-type-parameter-list.rs
@@ -3,7 +3,7 @@
 // no type parameters at all
 
 struct S<>;
-trait T<> {}
+trait T<> {} //~ WARN trait `T` is never used
 enum E<> { V }
 impl<> T<> for S<> {}
 impl T for E {}
diff --git a/tests/ui/empty-type-parameter-list.stderr b/tests/ui/empty-type-parameter-list.stderr
new file mode 100644
index 00000000000..31a5015e993
--- /dev/null
+++ b/tests/ui/empty-type-parameter-list.stderr
@@ -0,0 +1,10 @@
+warning: trait `T` is never used
+  --> $DIR/empty-type-parameter-list.rs:6:7
+   |
+LL | trait T<> {}
+   |       ^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/error-codes/E0401.stderr b/tests/ui/error-codes/E0401.stderr
index d27fade487f..754867061c7 100644
--- a/tests/ui/error-codes/E0401.stderr
+++ b/tests/ui/error-codes/E0401.stderr
@@ -20,7 +20,7 @@ LL |     fn baz<U,
 LL |            (y: T) {
    |                ^ use of generic parameter from outer item
 
-error[E0401]: can't use generic parameters from outer item
+error[E0401]: can't use `Self` from outer item
   --> $DIR/E0401.rs:24:25
    |
 LL | impl<T> Iterator for A<T> {
@@ -29,7 +29,7 @@ LL | impl<T> Iterator for A<T> {
 LL |         fn helper(sel: &Self) -> u8 {
    |                         ^^^^
    |                         |
-   |                         use of generic parameter from outer item
+   |                         use of `Self` from outer item
    |                         refer to the type directly here instead
 
 error[E0283]: type annotations needed
diff --git a/tests/ui/explicit/explicit-call-to-supertrait-dtor.fixed b/tests/ui/explicit/explicit-call-to-supertrait-dtor.fixed
index bb093a4af4a..3c71587c8e3 100644
--- a/tests/ui/explicit/explicit-call-to-supertrait-dtor.fixed
+++ b/tests/ui/explicit/explicit-call-to-supertrait-dtor.fixed
@@ -1,5 +1,6 @@
 // run-rustfix
 
+#![allow(dead_code)]
 #![allow(dropping_references)]
 
 struct Foo {
diff --git a/tests/ui/explicit/explicit-call-to-supertrait-dtor.rs b/tests/ui/explicit/explicit-call-to-supertrait-dtor.rs
index 1a9f89c054f..075d4cbe02b 100644
--- a/tests/ui/explicit/explicit-call-to-supertrait-dtor.rs
+++ b/tests/ui/explicit/explicit-call-to-supertrait-dtor.rs
@@ -1,5 +1,6 @@
 // run-rustfix
 
+#![allow(dead_code)]
 #![allow(dropping_references)]
 
 struct Foo {
diff --git a/tests/ui/explicit/explicit-call-to-supertrait-dtor.stderr b/tests/ui/explicit/explicit-call-to-supertrait-dtor.stderr
index d2d69ce6daf..13b6ee9987e 100644
--- a/tests/ui/explicit/explicit-call-to-supertrait-dtor.stderr
+++ b/tests/ui/explicit/explicit-call-to-supertrait-dtor.stderr
@@ -1,5 +1,5 @@
 error[E0040]: explicit use of destructor method
-  --> $DIR/explicit-call-to-supertrait-dtor.rs:22:14
+  --> $DIR/explicit-call-to-supertrait-dtor.rs:23:14
    |
 LL |         self.drop();
    |              ^^^^ explicit destructor calls not allowed
diff --git a/tests/ui/extern/no-mangle-associated-fn.rs b/tests/ui/extern/no-mangle-associated-fn.rs
index ecd44abbf26..56afd8b9092 100644
--- a/tests/ui/extern/no-mangle-associated-fn.rs
+++ b/tests/ui/extern/no-mangle-associated-fn.rs
@@ -12,7 +12,7 @@ impl Foo {
     }
 }
 
-trait Bar {
+trait Bar { //~ WARN trait `Bar` is never used
     fn qux() -> u8;
 }
 
diff --git a/tests/ui/extern/no-mangle-associated-fn.stderr b/tests/ui/extern/no-mangle-associated-fn.stderr
new file mode 100644
index 00000000000..772cbf6cf7d
--- /dev/null
+++ b/tests/ui/extern/no-mangle-associated-fn.stderr
@@ -0,0 +1,10 @@
+warning: trait `Bar` is never used
+  --> $DIR/no-mangle-associated-fn.rs:15:7
+   |
+LL | trait Bar {
+   |       ^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/feature-gates/feature-gate-ffi_returns_twice.rs b/tests/ui/feature-gates/feature-gate-ffi_returns_twice.rs
deleted file mode 100644
index f354534356c..00000000000
--- a/tests/ui/feature-gates/feature-gate-ffi_returns_twice.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-#![crate_type = "lib"]
-
-extern "C" {
-    #[ffi_returns_twice] //~ ERROR the `#[ffi_returns_twice]` attribute is an experimental feature
-    pub fn foo();
-}
diff --git a/tests/ui/feature-gates/feature-gate-ffi_returns_twice.stderr b/tests/ui/feature-gates/feature-gate-ffi_returns_twice.stderr
deleted file mode 100644
index 8d19874c36a..00000000000
--- a/tests/ui/feature-gates/feature-gate-ffi_returns_twice.stderr
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0658]: the `#[ffi_returns_twice]` attribute is an experimental feature
-  --> $DIR/feature-gate-ffi_returns_twice.rs:4:5
-   |
-LL |     #[ffi_returns_twice]
-   |     ^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #58314 <https://github.com/rust-lang/rust/issues/58314> for more information
-   = help: add `#![feature(ffi_returns_twice)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/ffi_returns_twice.rs b/tests/ui/ffi_returns_twice.rs
deleted file mode 100644
index 8195d0e4863..00000000000
--- a/tests/ui/ffi_returns_twice.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-#![feature(ffi_returns_twice)]
-#![crate_type = "lib"]
-
-#[ffi_returns_twice] //~ ERROR `#[ffi_returns_twice]` may only be used on foreign functions
-pub fn foo() {}
-
-#[ffi_returns_twice] //~ ERROR `#[ffi_returns_twice]` may only be used on foreign functions
-macro_rules! bar {
-    () => ()
-}
-
-extern "C" {
-    #[ffi_returns_twice] //~ ERROR `#[ffi_returns_twice]` may only be used on foreign functions
-    static INT: i32;
-}
diff --git a/tests/ui/ffi_returns_twice.stderr b/tests/ui/ffi_returns_twice.stderr
deleted file mode 100644
index 0abe7613f14..00000000000
--- a/tests/ui/ffi_returns_twice.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0724]: `#[ffi_returns_twice]` may only be used on foreign functions
-  --> $DIR/ffi_returns_twice.rs:4:1
-   |
-LL | #[ffi_returns_twice]
-   | ^^^^^^^^^^^^^^^^^^^^
-
-error[E0724]: `#[ffi_returns_twice]` may only be used on foreign functions
-  --> $DIR/ffi_returns_twice.rs:7:1
-   |
-LL | #[ffi_returns_twice]
-   | ^^^^^^^^^^^^^^^^^^^^
-
-error[E0724]: `#[ffi_returns_twice]` may only be used on foreign functions
-  --> $DIR/ffi_returns_twice.rs:13:5
-   |
-LL |     #[ffi_returns_twice]
-   |     ^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0724`.
diff --git a/tests/ui/generic-associated-types/issue-88360.fixed b/tests/ui/generic-associated-types/issue-88360.fixed
index 3dea8bf7ac8..6fb1e2559c0 100644
--- a/tests/ui/generic-associated-types/issue-88360.fixed
+++ b/tests/ui/generic-associated-types/issue-88360.fixed
@@ -1,4 +1,5 @@
 // run-rustfix
+#![allow(dead_code)]
 
 trait GatTrait {
     type Gat<'a> where Self: 'a;
diff --git a/tests/ui/generic-associated-types/issue-88360.rs b/tests/ui/generic-associated-types/issue-88360.rs
index 4d4c7ea3180..c8f07955b61 100644
--- a/tests/ui/generic-associated-types/issue-88360.rs
+++ b/tests/ui/generic-associated-types/issue-88360.rs
@@ -1,4 +1,5 @@
 // run-rustfix
+#![allow(dead_code)]
 
 trait GatTrait {
     type Gat<'a> where Self: 'a;
diff --git a/tests/ui/generic-associated-types/issue-88360.stderr b/tests/ui/generic-associated-types/issue-88360.stderr
index 49d36acadd6..488e50d2843 100644
--- a/tests/ui/generic-associated-types/issue-88360.stderr
+++ b/tests/ui/generic-associated-types/issue-88360.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/issue-88360.rs:15:9
+  --> $DIR/issue-88360.rs:16:9
    |
 LL | trait SuperTrait<T>
    |                  - found this type parameter
diff --git a/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.rs b/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.rs
index add4d58f86a..92ce4a0970f 100644
--- a/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.rs
+++ b/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.rs
@@ -5,7 +5,7 @@ trait X {
     type Y<T>;
 }
 
-trait M {
+trait M { //~ NOTE
     fn f(&self) {}
 }
 
diff --git a/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr b/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr
index 1dd463f996c..61512dd4658 100644
--- a/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr
+++ b/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr
@@ -14,6 +14,12 @@ LL | impl<T: X<Y<i32> = i32>> M for T {}
    |           ^^^^^^^^^^^^   -     -
    |           |
    |           unsatisfied trait bound introduced here
+   = help: items from traits can only be used if the trait is implemented and in scope
+note: `M` defines an item `f`, perhaps you need to implement it
+  --> $DIR/method-unsatisfied-assoc-type-predicate.rs:8:1
+   |
+LL | trait M {
+   | ^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/generics/generic-no-mangle.fixed b/tests/ui/generics/generic-no-mangle.fixed
index aa6d6310f5f..f51040358c0 100644
--- a/tests/ui/generics/generic-no-mangle.fixed
+++ b/tests/ui/generics/generic-no-mangle.fixed
@@ -1,5 +1,5 @@
 // run-rustfix
-
+#![allow(dead_code)]
 #![deny(no_mangle_generic_items)]
 
 
diff --git a/tests/ui/generics/generic-no-mangle.rs b/tests/ui/generics/generic-no-mangle.rs
index 8a59ca75aaf..02015331c57 100644
--- a/tests/ui/generics/generic-no-mangle.rs
+++ b/tests/ui/generics/generic-no-mangle.rs
@@ -1,5 +1,5 @@
 // run-rustfix
-
+#![allow(dead_code)]
 #![deny(no_mangle_generic_items)]
 
 #[no_mangle]
diff --git a/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr b/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr
index 73870703cfb..699a4ecc42b 100644
--- a/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr
+++ b/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr
@@ -15,6 +15,12 @@ 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
+   = help: items from traits can only be used if the trait is implemented and in scope
+note: `StreamExt` defines an item `filterx`, perhaps you need to implement it
+  --> $DIR/issue-30786.rs:66:1
+   |
+LL | pub trait StreamExt
+   | ^^^^^^^^^^^^^^^^^^^
 
 error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, fn(&u64) -> &u64 {identity::<u64>}>, {closure@issue-30786.rs:131:30}>`, but its trait bounds were not satisfied
   --> $DIR/issue-30786.rs:132:24
@@ -33,6 +39,12 @@ 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
+   = help: items from traits can only be used if the trait is implemented and in scope
+note: `StreamExt` defines an item `countx`, perhaps you need to implement it
+  --> $DIR/issue-30786.rs:66:1
+   |
+LL | pub trait StreamExt
+   | ^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr b/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr
index 1011fc4163b..0e3cd2ff060 100644
--- a/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr
+++ b/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr
@@ -1,4 +1,4 @@
-note: no errors encountered even though `span_delayed_bug` issued
+note: no errors encountered even though delayed bugs were created
 
 note: those delayed bugs will now be shown as internal compiler errors
 
diff --git a/tests/ui/impl-trait/example-st.rs b/tests/ui/impl-trait/example-st.rs
index 4e1aa3a0859..1e6ebc52365 100644
--- a/tests/ui/impl-trait/example-st.rs
+++ b/tests/ui/impl-trait/example-st.rs
@@ -3,7 +3,7 @@
 struct State;
 type Error = ();
 
-trait Bind<F> {
+trait Bind<F> { //~ WARN trait `Bind` is never used
     type Output;
     fn bind(self, f: F) -> Self::Output;
 }
diff --git a/tests/ui/impl-trait/example-st.stderr b/tests/ui/impl-trait/example-st.stderr
new file mode 100644
index 00000000000..f722d7f6582
--- /dev/null
+++ b/tests/ui/impl-trait/example-st.stderr
@@ -0,0 +1,10 @@
+warning: trait `Bind` is never used
+  --> $DIR/example-st.rs:6:7
+   |
+LL | trait Bind<F> {
+   |       ^^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed b/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed
index 8dc8e045d47..ecc8488a152 100644
--- a/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed
+++ b/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed
@@ -1,6 +1,7 @@
 // edition:2021
 // run-rustfix
 
+#![allow(dead_code)]
 trait Trait {
     #[allow(async_fn_in_trait)]
     async fn foo();
diff --git a/tests/ui/impl-trait/in-trait/suggest-missing-item.rs b/tests/ui/impl-trait/in-trait/suggest-missing-item.rs
index 30b04d87b9a..860fea07df9 100644
--- a/tests/ui/impl-trait/in-trait/suggest-missing-item.rs
+++ b/tests/ui/impl-trait/in-trait/suggest-missing-item.rs
@@ -1,6 +1,7 @@
 // edition:2021
 // run-rustfix
 
+#![allow(dead_code)]
 trait Trait {
     #[allow(async_fn_in_trait)]
     async fn foo();
diff --git a/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr b/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr
index cf68ed87030..45fd79badb3 100644
--- a/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr
+++ b/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr
@@ -1,5 +1,5 @@
 error[E0046]: not all trait items implemented, missing: `foo`, `bar`, `test`, `baz`
-  --> $DIR/suggest-missing-item.rs:19:1
+  --> $DIR/suggest-missing-item.rs:20:1
    |
 LL |     async fn foo();
    |     --------------- `foo` from trait
diff --git a/tests/ui/impl-trait/type-alias-generic-param.rs b/tests/ui/impl-trait/type-alias-generic-param.rs
index 1211625dac9..e4b2e412420 100644
--- a/tests/ui/impl-trait/type-alias-generic-param.rs
+++ b/tests/ui/impl-trait/type-alias-generic-param.rs
@@ -5,7 +5,7 @@
 // run-pass
 #![feature(impl_trait_in_assoc_type)]
 
-trait Meow {
+trait Meow { //~ WARN trait `Meow` is never used
     type MeowType;
     fn meow(self) -> Self::MeowType;
 }
diff --git a/tests/ui/impl-trait/type-alias-generic-param.stderr b/tests/ui/impl-trait/type-alias-generic-param.stderr
new file mode 100644
index 00000000000..e4115dc1319
--- /dev/null
+++ b/tests/ui/impl-trait/type-alias-generic-param.stderr
@@ -0,0 +1,10 @@
+warning: trait `Meow` is never used
+  --> $DIR/type-alias-generic-param.rs:8:7
+   |
+LL | trait Meow {
+   |       ^^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/inner-static-type-parameter.stderr b/tests/ui/inner-static-type-parameter.stderr
index 6c7f1ffbe16..88d33b44c59 100644
--- a/tests/ui/inner-static-type-parameter.stderr
+++ b/tests/ui/inner-static-type-parameter.stderr
@@ -5,6 +5,8 @@ LL | fn foo<T>() {
    |        - type parameter from outer item
 LL |     static a: Bar<T> = Bar::What;
    |                   ^ use of generic parameter from outer item
+   |
+   = note: a `static` is a separate item from the item that contains it
 
 error[E0392]: type parameter `T` is never used
   --> $DIR/inner-static-type-parameter.rs:3:10
diff --git a/tests/ui/issues/issue-14399.rs b/tests/ui/issues/issue-14399.rs
index 7b32bf8e4cb..0c6c4d8dc6b 100644
--- a/tests/ui/issues/issue-14399.rs
+++ b/tests/ui/issues/issue-14399.rs
@@ -9,7 +9,7 @@
 #[derive(Clone)]
 struct B1;
 
-trait A { fn foo(&self) {} }
+trait A { fn foo(&self) {} } //~ WARN method `foo` is never used
 impl A for B1 {}
 
 fn main() {
diff --git a/tests/ui/issues/issue-14399.stderr b/tests/ui/issues/issue-14399.stderr
new file mode 100644
index 00000000000..d226ece6fb0
--- /dev/null
+++ b/tests/ui/issues/issue-14399.stderr
@@ -0,0 +1,12 @@
+warning: method `foo` is never used
+  --> $DIR/issue-14399.rs:12:14
+   |
+LL | trait A { fn foo(&self) {} }
+   |       -      ^^^
+   |       |
+   |       method in this trait
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/issues/issue-15858.rs b/tests/ui/issues/issue-15858.rs
index 77941c07671..e3e3c293d7a 100644
--- a/tests/ui/issues/issue-15858.rs
+++ b/tests/ui/issues/issue-15858.rs
@@ -2,7 +2,7 @@
 static mut DROP_RAN: bool = false;
 
 trait Bar {
-    fn do_something(&mut self);
+    fn do_something(&mut self); //~ WARN method `do_something` is never used
 }
 
 struct BarImpl;
diff --git a/tests/ui/issues/issue-15858.stderr b/tests/ui/issues/issue-15858.stderr
new file mode 100644
index 00000000000..f36bcc21bd7
--- /dev/null
+++ b/tests/ui/issues/issue-15858.stderr
@@ -0,0 +1,12 @@
+warning: method `do_something` is never used
+  --> $DIR/issue-15858.rs:5:8
+   |
+LL | trait Bar {
+   |       --- method in this trait
+LL |     fn do_something(&mut self);
+   |        ^^^^^^^^^^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/issues/issue-17351.rs b/tests/ui/issues/issue-17351.rs
index 62f6bcf15e3..12bb8a73b7b 100644
--- a/tests/ui/issues/issue-17351.rs
+++ b/tests/ui/issues/issue-17351.rs
@@ -1,7 +1,7 @@
 // run-pass
 // pretty-expanded FIXME #23616
 
-trait Str { fn foo(&self) {} }
+trait Str { fn foo(&self) {} } //~ WARN method `foo` is never used
 impl Str for str {}
 impl<'a, S: ?Sized> Str for &'a S where S: Str {}
 
diff --git a/tests/ui/issues/issue-17351.stderr b/tests/ui/issues/issue-17351.stderr
new file mode 100644
index 00000000000..3242d578dab
--- /dev/null
+++ b/tests/ui/issues/issue-17351.stderr
@@ -0,0 +1,12 @@
+warning: method `foo` is never used
+  --> $DIR/issue-17351.rs:4:16
+   |
+LL | trait Str { fn foo(&self) {} }
+   |       ---      ^^^
+   |       |
+   |       method in this trait
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/issues/issue-18173.rs b/tests/ui/issues/issue-18173.rs
index 11468040ee5..010efee9f8a 100644
--- a/tests/ui/issues/issue-18173.rs
+++ b/tests/ui/issues/issue-18173.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 trait Foo {
     type T;
 }
diff --git a/tests/ui/issues/issue-20055-box-trait.rs b/tests/ui/issues/issue-20055-box-trait.rs
index 772cd9d7eda..36f597450ad 100644
--- a/tests/ui/issues/issue-20055-box-trait.rs
+++ b/tests/ui/issues/issue-20055-box-trait.rs
@@ -8,7 +8,7 @@
 // statement surrounding the `match`.
 
 trait Boo {
-    fn dummy(&self) { }
+    fn dummy(&self) { } //~ WARN method `dummy` is never used
 }
 
 impl Boo for [i8; 1] { }
diff --git a/tests/ui/issues/issue-20055-box-trait.stderr b/tests/ui/issues/issue-20055-box-trait.stderr
new file mode 100644
index 00000000000..db9d359e225
--- /dev/null
+++ b/tests/ui/issues/issue-20055-box-trait.stderr
@@ -0,0 +1,12 @@
+warning: method `dummy` is never used
+  --> $DIR/issue-20055-box-trait.rs:11:8
+   |
+LL | trait Boo {
+   |       --- method in this trait
+LL |     fn dummy(&self) { }
+   |        ^^^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/issues/issue-21909.rs b/tests/ui/issues/issue-21909.rs
index 7cb558d9a4f..6a6cdcfee15 100644
--- a/tests/ui/issues/issue-21909.rs
+++ b/tests/ui/issues/issue-21909.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 // pretty-expanded FIXME #23616
 
 trait A<X> {
diff --git a/tests/ui/issues/issue-23485.rs b/tests/ui/issues/issue-23485.rs
index 1dd3d9293bc..07ed0f1b00d 100644
--- a/tests/ui/issues/issue-23485.rs
+++ b/tests/ui/issues/issue-23485.rs
@@ -17,7 +17,7 @@ trait Iterator {
 
     fn next(&mut self) -> Option<Self::Item>;
 
-    fn clone_first(mut self) -> Option<<Self::Item as Deref>::Target> where
+    fn clone_first(mut self) -> Option<<Self::Item as Deref>::Target> where //~ WARN method `clone_first` is never used
         Self: Sized,
         Self::Item: Deref,
         <Self::Item as Deref>::Target: Clone,
diff --git a/tests/ui/issues/issue-23485.stderr b/tests/ui/issues/issue-23485.stderr
new file mode 100644
index 00000000000..ed2d2400d0d
--- /dev/null
+++ b/tests/ui/issues/issue-23485.stderr
@@ -0,0 +1,13 @@
+warning: method `clone_first` is never used
+  --> $DIR/issue-23485.rs:20:8
+   |
+LL | trait Iterator {
+   |       -------- method in this trait
+...
+LL |     fn clone_first(mut self) -> Option<<Self::Item as Deref>::Target> where
+   |        ^^^^^^^^^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/issues/issue-2989.rs b/tests/ui/issues/issue-2989.rs
index c0b67374370..a9586751407 100644
--- a/tests/ui/issues/issue-2989.rs
+++ b/tests/ui/issues/issue-2989.rs
@@ -1,8 +1,8 @@
 // run-pass
 #![allow(non_camel_case_types)]
 
-trait methods {
-    fn to_bytes(&self) -> Vec<u8> ;
+trait methods { //~ WARN trait `methods` is never used
+    fn to_bytes(&self) -> Vec<u8>;
 }
 
 impl methods for () {
diff --git a/tests/ui/issues/issue-2989.stderr b/tests/ui/issues/issue-2989.stderr
new file mode 100644
index 00000000000..57181607cec
--- /dev/null
+++ b/tests/ui/issues/issue-2989.stderr
@@ -0,0 +1,10 @@
+warning: trait `methods` is never used
+  --> $DIR/issue-2989.rs:4:7
+   |
+LL | trait methods {
+   |       ^^^^^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/issues/issue-34074.rs b/tests/ui/issues/issue-34074.rs
index 0600d3937c1..ca7d7b49a04 100644
--- a/tests/ui/issues/issue-34074.rs
+++ b/tests/ui/issues/issue-34074.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 // Make sure several unnamed function parameters don't conflict with each other
 
 trait Tr {
diff --git a/tests/ui/issues/issue-34503.rs b/tests/ui/issues/issue-34503.rs
index 26e7358408f..d2c95d990ec 100644
--- a/tests/ui/issues/issue-34503.rs
+++ b/tests/ui/issues/issue-34503.rs
@@ -2,7 +2,7 @@
 fn main() {
     struct X;
     trait Foo<T> {
-        fn foo(&self) where (T, Option<T>): Ord {}
+        fn foo(&self) where (T, Option<T>): Ord {} //~ WARN methods `foo` and `bar` are never used
         fn bar(&self, x: &Option<T>) -> bool
         where Option<T>: Ord { *x < *x }
     }
diff --git a/tests/ui/issues/issue-34503.stderr b/tests/ui/issues/issue-34503.stderr
new file mode 100644
index 00000000000..60d8d76a619
--- /dev/null
+++ b/tests/ui/issues/issue-34503.stderr
@@ -0,0 +1,14 @@
+warning: methods `foo` and `bar` are never used
+  --> $DIR/issue-34503.rs:5:12
+   |
+LL |     trait Foo<T> {
+   |           --- methods in this trait
+LL |         fn foo(&self) where (T, Option<T>): Ord {}
+   |            ^^^
+LL |         fn bar(&self, x: &Option<T>) -> bool
+   |            ^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/issues/issue-3563-3.rs b/tests/ui/issues/issue-3563-3.rs
index bedfdab97d5..6346b82167c 100644
--- a/tests/ui/issues/issue-3563-3.rs
+++ b/tests/ui/issues/issue-3563-3.rs
@@ -112,7 +112,7 @@ trait Canvas {
 
     // Unlike interfaces traits support default implementations.
     // Got an ICE as soon as I added this method.
-    fn add_points(&mut self, shapes: &[Point]) {
+    fn add_points(&mut self, shapes: &[Point]) { //~ WARN method `add_points` is never used
         for pt in shapes {self.add_point(*pt)};
     }
 }
diff --git a/tests/ui/issues/issue-3563-3.stderr b/tests/ui/issues/issue-3563-3.stderr
new file mode 100644
index 00000000000..bd65c1e3fd5
--- /dev/null
+++ b/tests/ui/issues/issue-3563-3.stderr
@@ -0,0 +1,13 @@
+warning: method `add_points` is never used
+  --> $DIR/issue-3563-3.rs:115:8
+   |
+LL | trait Canvas {
+   |       ------ method in this trait
+...
+LL |     fn add_points(&mut self, shapes: &[Point]) {
+   |        ^^^^^^^^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/issues/issue-50571.fixed b/tests/ui/issues/issue-50571.fixed
index 2f8c925b853..13c830cd0d4 100644
--- a/tests/ui/issues/issue-50571.fixed
+++ b/tests/ui/issues/issue-50571.fixed
@@ -1,5 +1,6 @@
 // run-rustfix
 
+#![allow(dead_code)]
 trait Foo {
     fn foo(_: [i32; 2]) {}
     //~^ ERROR: patterns aren't allowed in methods without bodies
diff --git a/tests/ui/issues/issue-50571.rs b/tests/ui/issues/issue-50571.rs
index 56f422e7d58..6fe13e3f707 100644
--- a/tests/ui/issues/issue-50571.rs
+++ b/tests/ui/issues/issue-50571.rs
@@ -1,5 +1,6 @@
 // run-rustfix
 
+#![allow(dead_code)]
 trait Foo {
     fn foo([a, b]: [i32; 2]) {}
     //~^ ERROR: patterns aren't allowed in methods without bodies
diff --git a/tests/ui/issues/issue-50571.stderr b/tests/ui/issues/issue-50571.stderr
index fe47790f1dd..12256ded1c0 100644
--- a/tests/ui/issues/issue-50571.stderr
+++ b/tests/ui/issues/issue-50571.stderr
@@ -1,5 +1,5 @@
 error[E0642]: patterns aren't allowed in methods without bodies
-  --> $DIR/issue-50571.rs:4:12
+  --> $DIR/issue-50571.rs:5:12
    |
 LL |     fn foo([a, b]: [i32; 2]) {}
    |            ^^^^^^
diff --git a/tests/ui/issues/issue-7575.rs b/tests/ui/issues/issue-7575.rs
index ac69f2b1c80..0074f660c4e 100644
--- a/tests/ui/issues/issue-7575.rs
+++ b/tests/ui/issues/issue-7575.rs
@@ -1,6 +1,6 @@
 // run-pass
 
-trait Foo {
+trait Foo { //~ WARN trait `Foo` is never used
     fn new() -> bool { false }
     fn dummy(&self) { }
 }
diff --git a/tests/ui/issues/issue-7575.stderr b/tests/ui/issues/issue-7575.stderr
new file mode 100644
index 00000000000..2f987d19c80
--- /dev/null
+++ b/tests/ui/issues/issue-7575.stderr
@@ -0,0 +1,10 @@
+warning: trait `Foo` is never used
+  --> $DIR/issue-7575.rs:3:7
+   |
+LL | trait Foo {
+   |       ^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/issues/issue-7911.rs b/tests/ui/issues/issue-7911.rs
index d4db3b0776b..114574b9009 100644
--- a/tests/ui/issues/issue-7911.rs
+++ b/tests/ui/issues/issue-7911.rs
@@ -4,7 +4,7 @@
 
 #![allow(unused_variables)] // unused foobar_immut + foobar_mut
 trait FooBar {
-    fn dummy(&self) { }
+    fn dummy(&self) { } //~ WARN method `dummy` is never used
 }
 struct Bar(#[allow(dead_code)] i32);
 struct Foo { bar: Bar }
diff --git a/tests/ui/issues/issue-7911.stderr b/tests/ui/issues/issue-7911.stderr
new file mode 100644
index 00000000000..ead7ee191ac
--- /dev/null
+++ b/tests/ui/issues/issue-7911.stderr
@@ -0,0 +1,12 @@
+warning: method `dummy` is never used
+  --> $DIR/issue-7911.rs:7:8
+   |
+LL | trait FooBar {
+   |       ------ method in this trait
+LL |     fn dummy(&self) { }
+   |        ^^^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/issues/issue-8248.rs b/tests/ui/issues/issue-8248.rs
index 31a305c31be..94b1a5203b4 100644
--- a/tests/ui/issues/issue-8248.rs
+++ b/tests/ui/issues/issue-8248.rs
@@ -2,7 +2,7 @@
 // pretty-expanded FIXME #23616
 
 trait A {
-    fn dummy(&self) { }
+    fn dummy(&self) { } //~ WARN method `dummy` is never used
 }
 struct B;
 impl A for B {}
diff --git a/tests/ui/issues/issue-8248.stderr b/tests/ui/issues/issue-8248.stderr
new file mode 100644
index 00000000000..a0098bcb771
--- /dev/null
+++ b/tests/ui/issues/issue-8248.stderr
@@ -0,0 +1,12 @@
+warning: method `dummy` is never used
+  --> $DIR/issue-8248.rs:5:8
+   |
+LL | trait A {
+   |       - method in this trait
+LL |     fn dummy(&self) { }
+   |        ^^^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/issues/issue-9951.rs b/tests/ui/issues/issue-9951.rs
index 2698a3b17c6..5db3f74efaa 100644
--- a/tests/ui/issues/issue-9951.rs
+++ b/tests/ui/issues/issue-9951.rs
@@ -4,7 +4,7 @@
 #![allow(unused_variables)]
 
 trait Bar {
-  fn noop(&self);
+  fn noop(&self); //~ WARN method `noop` is never used
 }
 impl Bar for u8 {
   fn noop(&self) {}
diff --git a/tests/ui/issues/issue-9951.stderr b/tests/ui/issues/issue-9951.stderr
new file mode 100644
index 00000000000..475f2817914
--- /dev/null
+++ b/tests/ui/issues/issue-9951.stderr
@@ -0,0 +1,12 @@
+warning: method `noop` is never used
+  --> $DIR/issue-9951.rs:7:6
+   |
+LL | trait Bar {
+   |       --- method in this trait
+LL |   fn noop(&self);
+   |      ^^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/lint/dead-code/associated-type.rs b/tests/ui/lint/dead-code/associated-type.rs
index 1cf66e75a95..25106a66e7e 100644
--- a/tests/ui/lint/dead-code/associated-type.rs
+++ b/tests/ui/lint/dead-code/associated-type.rs
@@ -15,5 +15,5 @@ impl Foo for Ex {
 }
 
 pub fn main() {
-    let _x = Ex;
+    let _x: &dyn Foo<Bar = <Ex as Foo>::Bar> = &Ex;
 }
diff --git a/tests/ui/lint/dead-code/issue-41883.rs b/tests/ui/lint/dead-code/issue-41883.rs
new file mode 100644
index 00000000000..e165861e893
--- /dev/null
+++ b/tests/ui/lint/dead-code/issue-41883.rs
@@ -0,0 +1,29 @@
+#![deny(dead_code)]
+
+enum Category {
+    Dead, //~ ERROR variant `Dead` is never constructed
+    Used,
+}
+
+trait UnusedTrait { //~ ERROR trait `UnusedTrait` is never used
+    fn this_is_unused(&self) -> Category {
+        Category::Dead
+    }
+}
+
+struct UnusedStruct; //~ ERROR struct `UnusedStruct` is never constructed
+
+impl UnusedTrait for UnusedStruct {
+    fn this_is_unused(&self) -> Category {
+        Category::Used
+    }
+}
+
+mod private {
+    #[derive(Debug)]
+    struct UnusedStruct; //~ ERROR struct `UnusedStruct` is never constructed
+}
+
+fn main() {
+    let _c = Category::Used;
+}
diff --git a/tests/ui/lint/dead-code/issue-41883.stderr b/tests/ui/lint/dead-code/issue-41883.stderr
new file mode 100644
index 00000000000..cf079e4dda3
--- /dev/null
+++ b/tests/ui/lint/dead-code/issue-41883.stderr
@@ -0,0 +1,36 @@
+error: variant `Dead` is never constructed
+  --> $DIR/issue-41883.rs:4:5
+   |
+LL | enum Category {
+   |      -------- variant in this enum
+LL |     Dead,
+   |     ^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/issue-41883.rs:1:9
+   |
+LL | #![deny(dead_code)]
+   |         ^^^^^^^^^
+
+error: trait `UnusedTrait` is never used
+  --> $DIR/issue-41883.rs:8:7
+   |
+LL | trait UnusedTrait {
+   |       ^^^^^^^^^^^
+
+error: struct `UnusedStruct` is never constructed
+  --> $DIR/issue-41883.rs:14:8
+   |
+LL | struct UnusedStruct;
+   |        ^^^^^^^^^^^^
+
+error: struct `UnusedStruct` is never constructed
+  --> $DIR/issue-41883.rs:24:12
+   |
+LL |     struct UnusedStruct;
+   |            ^^^^^^^^^^^^
+   |
+   = note: `UnusedStruct` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.rs b/tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.rs
index 942c5516500..2d6364aa0cd 100644
--- a/tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.rs
+++ b/tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.rs
@@ -17,7 +17,7 @@ struct Bar {
 
 // Issue 119267: this should not ICE.
 #[derive(Debug)]
-struct Foo(usize, #[allow(unused)] usize); //~ WARN field `0` is never read
+struct Foo(usize, #[allow(unused)] usize); //~ WARN struct `Foo` is never constructed
 
 fn main() {
     Bar {
diff --git a/tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.stderr b/tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.stderr
index 06f9b229c18..b992005318f 100644
--- a/tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.stderr
+++ b/tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.stderr
@@ -51,19 +51,13 @@ note: the lint level is defined here
 LL |     #[forbid(dead_code)]
    |              ^^^^^^^^^
 
-warning: field `0` is never read
-  --> $DIR/multiple-dead-codes-in-the-same-struct.rs:20:12
+warning: struct `Foo` is never constructed
+  --> $DIR/multiple-dead-codes-in-the-same-struct.rs:20:8
    |
 LL | struct Foo(usize, #[allow(unused)] usize);
-   |        --- ^^^^^
-   |        |
-   |        field in this struct
+   |        ^^^
    |
    = note: `Foo` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
-help: consider changing the field to be of unit type to suppress this warning while preserving the field numbering, or remove the field
-   |
-LL | struct Foo((), #[allow(unused)] usize);
-   |            ~~
 
 error: aborting due to 2 previous errors; 2 warnings emitted
 
diff --git a/tests/ui/lint/future-incompat-json-test.stderr b/tests/ui/lint/future-incompat-json-test.stderr
index c4ab5a00d16..18fc3f17f00 100644
--- a/tests/ui/lint/future-incompat-json-test.stderr
+++ b/tests/ui/lint/future-incompat-json-test.stderr
@@ -1,4 +1,4 @@
-{"$message_type":"future_incompat","future_incompat_report":[{"diagnostic":{"$message_type":"diagnostic","message":"unused variable: `x`","code":{"code":"unused_variables","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/future-incompat-json-test.rs","byte_start":338,"byte_end":339,"line_start":9,"line_end":9,"column_start":9,"column_end":10,"is_primary":true,"text":[{"text":"    let x = 1;","highlight_start":9,"highlight_end":10}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"`-A unused-variables` implied by `-A unused`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"to override `-A unused` add `#[allow(unused_variables)]`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"if this is intentional, prefix it with an underscore","code":null,"level":"help","spans":[{"file_name":"$DIR/future-incompat-json-test.rs","byte_start":338,"byte_end":339,"line_start":9,"line_end":9,"column_start":9,"column_end":10,"is_primary":true,"text":[{"text":"    let x = 1;","highlight_start":9,"highlight_end":10}],"label":null,"suggested_replacement":"_x","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"warning: unused variable: `x`
+{"$message_type":"future_incompat","future_incompat_report":[{"diagnostic":{"$message_type":"diagnostic","message":"unused variable: `x`","code":{"code":"unused_variables","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/future-incompat-json-test.rs","byte_start":338,"byte_end":339,"line_start":9,"line_end":9,"column_start":9,"column_end":10,"is_primary":true,"text":[{"text":"    let x = 1;","highlight_start":9,"highlight_end":10}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"`-A unused-variables` implied by `-A unused`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"to override `-A unused` add `#[allow(unused_variables)]`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"if this is intentional, prefix it with an underscore","code":null,"level":"help","spans":[{"file_name":"$DIR/future-incompat-json-test.rs","byte_start":338,"byte_end":339,"line_start":9,"line_end":9,"column_start":9,"column_end":10,"is_primary":true,"text":[{"text":"    let x = 1;","highlight_start":9,"highlight_end":10}],"label":null,"suggested_replacement":"_x","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"warning: unused variable: `x`
   --> $DIR/future-incompat-json-test.rs:9:9
    |
 LL |     let x = 1;
diff --git a/tests/ui/lint/issue-20343.rs b/tests/ui/lint/issue-20343.rs
index 000b6398442..f0f4eccc676 100644
--- a/tests/ui/lint/issue-20343.rs
+++ b/tests/ui/lint/issue-20343.rs
@@ -22,6 +22,8 @@ impl B {
 
     // test for unused code in generics
     fn baz<A: T<D>>() {}
+
+    fn foz<A: T<D>>(a: A) { a.dummy(D); }
 }
 
 pub fn main() {
@@ -29,4 +31,5 @@ pub fn main() {
     B::foo(b);
     B::bar();
     B::baz::<()>();
+    B::foz::<()>(());
 }
diff --git a/tests/ui/macros/issue-22463.rs b/tests/ui/macros/issue-22463.rs
index fdf5a2fca72..8f7b27cb9a0 100644
--- a/tests/ui/macros/issue-22463.rs
+++ b/tests/ui/macros/issue-22463.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 macro_rules! items {
     () => {
         type A = ();
diff --git a/tests/ui/methods/method-call-err-msg.stderr b/tests/ui/methods/method-call-err-msg.stderr
index f4310857454..6df49e432a1 100644
--- a/tests/ui/methods/method-call-err-msg.stderr
+++ b/tests/ui/methods/method-call-err-msg.stderr
@@ -63,8 +63,9 @@ LL | |      .take()
 note: the trait `Iterator` must be implemented
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
    = help: items from traits can only be used if the trait is implemented and in scope
-   = note: the following trait defines an item `take`, perhaps you need to implement it:
-           candidate #1: `Iterator`
+   = note: the following traits define an item `take`, perhaps you need to implement one of them:
+           candidate #1: `std::io::Read`
+           candidate #2: `Iterator`
 
 error[E0061]: this method takes 3 arguments but 0 arguments were supplied
   --> $DIR/method-call-err-msg.rs:21:7
diff --git a/tests/ui/methods/method-lookup-order.rs b/tests/ui/methods/method-lookup-order.rs
index 986fe103cdc..5a46cf35dec 100644
--- a/tests/ui/methods/method-lookup-order.rs
+++ b/tests/ui/methods/method-lookup-order.rs
@@ -1,6 +1,7 @@
 // ignore-tidy-linelength
 
 // run-pass
+#![allow(dead_code)]
 
 // There are five cfg's below. I explored the set of all non-empty combinations
 // of the below five cfg's, which is 2^5 - 1 = 31 combinations.
diff --git a/tests/ui/methods/method-recursive-blanket-impl.rs b/tests/ui/methods/method-recursive-blanket-impl.rs
index a2db75b4e85..e7e83cbec77 100644
--- a/tests/ui/methods/method-recursive-blanket-impl.rs
+++ b/tests/ui/methods/method-recursive-blanket-impl.rs
@@ -11,7 +11,7 @@
 use std::marker::Sized;
 
 // Note: this must be generic for the problem to show up
-trait Foo<A> {
+trait Foo<A> { //~ WARN trait `Foo` is never used
     fn foo(&self, a: A);
 }
 
diff --git a/tests/ui/methods/method-recursive-blanket-impl.stderr b/tests/ui/methods/method-recursive-blanket-impl.stderr
new file mode 100644
index 00000000000..9797a8f6c83
--- /dev/null
+++ b/tests/ui/methods/method-recursive-blanket-impl.stderr
@@ -0,0 +1,10 @@
+warning: trait `Foo` is never used
+  --> $DIR/method-recursive-blanket-impl.rs:14:7
+   |
+LL | trait Foo<A> {
+   |       ^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/methods/method-two-trait-defer-resolution-2.rs b/tests/ui/methods/method-two-trait-defer-resolution-2.rs
index fc5766da971..d6076126732 100644
--- a/tests/ui/methods/method-two-trait-defer-resolution-2.rs
+++ b/tests/ui/methods/method-two-trait-defer-resolution-2.rs
@@ -14,7 +14,7 @@ trait Foo {
     fn foo(&self) -> isize;
 }
 
-trait MyCopy { fn foo(&self) { } }
+trait MyCopy { fn foo(&self) { } } //~ WARN method `foo` is never used
 impl MyCopy for i32 { }
 
 impl<T:MyCopy> Foo for Vec<T> {
diff --git a/tests/ui/methods/method-two-trait-defer-resolution-2.stderr b/tests/ui/methods/method-two-trait-defer-resolution-2.stderr
new file mode 100644
index 00000000000..4501ea5d243
--- /dev/null
+++ b/tests/ui/methods/method-two-trait-defer-resolution-2.stderr
@@ -0,0 +1,12 @@
+warning: method `foo` is never used
+  --> $DIR/method-two-trait-defer-resolution-2.rs:17:19
+   |
+LL | trait MyCopy { fn foo(&self) { } }
+   |       ------      ^^^
+   |       |
+   |       method in this trait
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/methods/method-two-traits-distinguished-via-where-clause.rs b/tests/ui/methods/method-two-traits-distinguished-via-where-clause.rs
index d820d2ad08a..2fd6c3bfab8 100644
--- a/tests/ui/methods/method-two-traits-distinguished-via-where-clause.rs
+++ b/tests/ui/methods/method-two-traits-distinguished-via-where-clause.rs
@@ -4,7 +4,7 @@
 
 // pretty-expanded FIXME #23616
 
-trait A {
+trait A { //~ WARN trait `A` is never used
     fn foo(self);
 }
 
diff --git a/tests/ui/methods/method-two-traits-distinguished-via-where-clause.stderr b/tests/ui/methods/method-two-traits-distinguished-via-where-clause.stderr
new file mode 100644
index 00000000000..0a60c6242bb
--- /dev/null
+++ b/tests/ui/methods/method-two-traits-distinguished-via-where-clause.stderr
@@ -0,0 +1,10 @@
+warning: trait `A` is never used
+  --> $DIR/method-two-traits-distinguished-via-where-clause.rs:7:7
+   |
+LL | trait A {
+   |       ^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/mir/mir_raw_fat_ptr.rs b/tests/ui/mir/mir_raw_fat_ptr.rs
index 8e5a2043dc6..e141aa03aa9 100644
--- a/tests/ui/mir/mir_raw_fat_ptr.rs
+++ b/tests/ui/mir/mir_raw_fat_ptr.rs
@@ -98,7 +98,7 @@ fn assert_inorder<T: Copy>(a: &[T],
     }
 }
 
-trait Foo { fn foo(&self) -> usize; }
+trait Foo { fn foo(&self) -> usize; } //~ WARN method `foo` is never used
 impl<T> Foo for T {
     fn foo(&self) -> usize {
         mem::size_of::<T>()
diff --git a/tests/ui/mir/mir_raw_fat_ptr.stderr b/tests/ui/mir/mir_raw_fat_ptr.stderr
new file mode 100644
index 00000000000..a9e9dd66ebd
--- /dev/null
+++ b/tests/ui/mir/mir_raw_fat_ptr.stderr
@@ -0,0 +1,12 @@
+warning: method `foo` is never used
+  --> $DIR/mir_raw_fat_ptr.rs:101:16
+   |
+LL | trait Foo { fn foo(&self) -> usize; }
+   |       ---      ^^^
+   |       |
+   |       method in this trait
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/moves/issue-22536-copy-mustnt-zero.rs b/tests/ui/moves/issue-22536-copy-mustnt-zero.rs
index 017f36484c1..b3fc1a56f88 100644
--- a/tests/ui/moves/issue-22536-copy-mustnt-zero.rs
+++ b/tests/ui/moves/issue-22536-copy-mustnt-zero.rs
@@ -5,7 +5,7 @@
 
 trait Resources {
     type Buffer: Copy;
-    fn foo(&self) {}
+    fn foo(&self) {} //~ WARN method `foo` is never used
 }
 
 struct BufferHandle<R: Resources> {
diff --git a/tests/ui/moves/issue-22536-copy-mustnt-zero.stderr b/tests/ui/moves/issue-22536-copy-mustnt-zero.stderr
new file mode 100644
index 00000000000..b1fcdfa44c3
--- /dev/null
+++ b/tests/ui/moves/issue-22536-copy-mustnt-zero.stderr
@@ -0,0 +1,13 @@
+warning: method `foo` is never used
+  --> $DIR/issue-22536-copy-mustnt-zero.rs:8:8
+   |
+LL | trait Resources {
+   |       --------- method in this trait
+LL |     type Buffer: Copy;
+LL |     fn foo(&self) {}
+   |        ^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed
index 45c7e07a264..52046a8ab69 100644
--- a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed
+++ b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed
@@ -1,4 +1,5 @@
 // run-rustfix
+#![allow(dead_code)]
 trait TraitWithAType {
     type Item: ?Sized;
 }
diff --git a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs
index c3e958f4983..96620c0abda 100644
--- a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs
+++ b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs
@@ -1,4 +1,5 @@
 // run-rustfix
+#![allow(dead_code)]
 trait TraitWithAType {
     type Item;
 }
diff --git a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr
index cd2aa9fdbe3..9bb770ce431 100644
--- a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr
+++ b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr
@@ -1,12 +1,12 @@
 error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time
-  --> $DIR/assoc_type_bounds_implicit_sized.rs:8:17
+  --> $DIR/assoc_type_bounds_implicit_sized.rs:9:17
    |
 LL |     type Item = dyn Trait;
    |                 ^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `(dyn Trait + 'static)`
 note: required by a bound in `TraitWithAType::Item`
-  --> $DIR/assoc_type_bounds_implicit_sized.rs:3:5
+  --> $DIR/assoc_type_bounds_implicit_sized.rs:4:5
    |
 LL |     type Item;
    |     ^^^^^^^^^^ required by this bound in `TraitWithAType::Item`
diff --git a/tests/ui/overloaded/issue-14958.rs b/tests/ui/overloaded/issue-14958.rs
index a12564ca9c0..80abf5e4e76 100644
--- a/tests/ui/overloaded/issue-14958.rs
+++ b/tests/ui/overloaded/issue-14958.rs
@@ -3,7 +3,7 @@
 
 #![feature(fn_traits, unboxed_closures)]
 
-trait Foo { fn dummy(&self) { }}
+trait Foo { fn dummy(&self) { }} //~ WARN method `dummy` is never used
 
 struct Bar;
 
diff --git a/tests/ui/overloaded/issue-14958.stderr b/tests/ui/overloaded/issue-14958.stderr
new file mode 100644
index 00000000000..cc97730239c
--- /dev/null
+++ b/tests/ui/overloaded/issue-14958.stderr
@@ -0,0 +1,12 @@
+warning: method `dummy` is never used
+  --> $DIR/issue-14958.rs:6:16
+   |
+LL | trait Foo { fn dummy(&self) { }}
+   |       ---      ^^^^^
+   |       |
+   |       method in this trait
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/overloaded/overloaded-index-in-field.rs b/tests/ui/overloaded/overloaded-index-in-field.rs
index 8a1fa7deb99..0dc45ea8ca2 100644
--- a/tests/ui/overloaded/overloaded-index-in-field.rs
+++ b/tests/ui/overloaded/overloaded-index-in-field.rs
@@ -27,7 +27,7 @@ impl Index<isize> for Foo {
 
 trait Int {
     fn get(self) -> isize;
-    fn get_from_ref(&self) -> isize;
+    fn get_from_ref(&self) -> isize; //~ WARN methods `get_from_ref` and `inc` are never used
     fn inc(&mut self);
 }
 
diff --git a/tests/ui/overloaded/overloaded-index-in-field.stderr b/tests/ui/overloaded/overloaded-index-in-field.stderr
new file mode 100644
index 00000000000..10c0a3faeb5
--- /dev/null
+++ b/tests/ui/overloaded/overloaded-index-in-field.stderr
@@ -0,0 +1,15 @@
+warning: methods `get_from_ref` and `inc` are never used
+  --> $DIR/overloaded-index-in-field.rs:30:8
+   |
+LL | trait Int {
+   |       --- methods in this trait
+LL |     fn get(self) -> isize;
+LL |     fn get_from_ref(&self) -> isize;
+   |        ^^^^^^^^^^^^
+LL |     fn inc(&mut self);
+   |        ^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.rs b/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.rs
new file mode 100644
index 00000000000..148a59240f9
--- /dev/null
+++ b/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.rs
@@ -0,0 +1,16 @@
+// compile-flags: -Z threads=16
+// build-fail
+
+#![crate_type="rlib"]
+#![allow(warnings)]
+
+#[export_name="fail"]
+pub fn a() {
+}
+
+#[export_name="fail"]
+pub fn b() {
+//~^ Error symbol `fail` is already defined
+}
+
+fn main() {}
diff --git a/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.stderr b/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.stderr
new file mode 100644
index 00000000000..7963165e31b
--- /dev/null
+++ b/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.stderr
@@ -0,0 +1,8 @@
+error: symbol `fail` is already defined
+  --> $DIR/cache-after-waiting-issue-111528.rs:12:1
+   |
+LL | pub fn b() {
+   | ^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/parallel-rustc/export-symbols-deadlock-issue-118205-2.rs b/tests/ui/parallel-rustc/export-symbols-deadlock-issue-118205-2.rs
new file mode 100644
index 00000000000..8240b249018
--- /dev/null
+++ b/tests/ui/parallel-rustc/export-symbols-deadlock-issue-118205-2.rs
@@ -0,0 +1,7 @@
+// compile-flags:-C extra-filename=-1 -Z threads=16
+// no-prefer-dynamic
+// build-pass
+#![crate_name = "crateresolve1"]
+#![crate_type = "lib"]
+
+pub fn f() -> isize { 10 }
diff --git a/tests/ui/parallel-rustc/export-symbols-deadlock-issue-118205.rs b/tests/ui/parallel-rustc/export-symbols-deadlock-issue-118205.rs
new file mode 100644
index 00000000000..691c36cfc9e
--- /dev/null
+++ b/tests/ui/parallel-rustc/export-symbols-deadlock-issue-118205.rs
@@ -0,0 +1,22 @@
+// compile-flags: -Z threads=16
+// build-pass
+
+pub static GLOBAL: isize = 3;
+
+static GLOBAL0: isize = 4;
+
+pub static GLOBAL2: &'static isize = &GLOBAL0;
+
+pub fn verify_same(a: &'static isize) {
+    let a = a as *const isize as usize;
+    let b = &GLOBAL as *const isize as usize;
+    assert_eq!(a, b);
+}
+
+pub fn verify_same2(a: &'static isize) {
+    let a = a as *const isize as usize;
+    let b = GLOBAL2 as *const isize as usize;
+    assert_eq!(a, b);
+}
+
+fn main() {}
diff --git a/tests/ui/parallel-rustc/hello_world.rs b/tests/ui/parallel-rustc/hello_world.rs
new file mode 100644
index 00000000000..53e95c890ef
--- /dev/null
+++ b/tests/ui/parallel-rustc/hello_world.rs
@@ -0,0 +1,6 @@
+// compile-flags: -Z threads=8
+// run-pass
+
+fn main() {
+    println!("Hello world!");
+}
diff --git a/tests/ui/parallel-rustc/read-stolen-value-issue-111520.rs b/tests/ui/parallel-rustc/read-stolen-value-issue-111520.rs
new file mode 100644
index 00000000000..1907348cf09
--- /dev/null
+++ b/tests/ui/parallel-rustc/read-stolen-value-issue-111520.rs
@@ -0,0 +1,18 @@
+// compile-flags: -Z threads=16
+// run-pass
+
+#[repr(transparent)]
+struct Sched {
+    i: i32,
+}
+impl Sched {
+    extern "C" fn get(self) -> i32 { self.i }
+}
+
+fn main() {
+    let s = Sched { i: 4 };
+    let f = || -> i32 {
+        s.get()
+    };
+    println!("f: {}", f());
+}
diff --git a/tests/ui/parser/parse-assoc-type-lt.rs b/tests/ui/parser/parse-assoc-type-lt.rs
index d3fe6079a5d..913fcd920bd 100644
--- a/tests/ui/parser/parse-assoc-type-lt.rs
+++ b/tests/ui/parser/parse-assoc-type-lt.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 // pretty-expanded FIXME #23616
 
 trait Foo {
diff --git a/tests/ui/parser/suggest-assoc-const.fixed b/tests/ui/parser/suggest-assoc-const.fixed
index 259f37b23a5..4229135ebb2 100644
--- a/tests/ui/parser/suggest-assoc-const.fixed
+++ b/tests/ui/parser/suggest-assoc-const.fixed
@@ -1,5 +1,6 @@
 // Issue: 101797, Suggest associated const for incorrect use of let in traits
 // run-rustfix
+#![allow(dead_code)]
 trait Trait {
     const _X: i32;
     //~^ ERROR non-item in item list
diff --git a/tests/ui/parser/suggest-assoc-const.rs b/tests/ui/parser/suggest-assoc-const.rs
index c7be712ec07..0cf695bd40a 100644
--- a/tests/ui/parser/suggest-assoc-const.rs
+++ b/tests/ui/parser/suggest-assoc-const.rs
@@ -1,5 +1,6 @@
 // Issue: 101797, Suggest associated const for incorrect use of let in traits
 // run-rustfix
+#![allow(dead_code)]
 trait Trait {
     let _X: i32;
     //~^ ERROR non-item in item list
diff --git a/tests/ui/parser/suggest-assoc-const.stderr b/tests/ui/parser/suggest-assoc-const.stderr
index 7ba1dbdff7e..6e29fad98d4 100644
--- a/tests/ui/parser/suggest-assoc-const.stderr
+++ b/tests/ui/parser/suggest-assoc-const.stderr
@@ -1,5 +1,5 @@
 error: non-item in item list
-  --> $DIR/suggest-assoc-const.rs:4:5
+  --> $DIR/suggest-assoc-const.rs:5:5
    |
 LL |     let _X: i32;
    |     ^^^ help: consider using `const` instead of `let` for associated const: `const`
diff --git a/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.fixed b/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.fixed
index 63704735490..81ee6cdf0a7 100644
--- a/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.fixed
+++ b/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.fixed
@@ -1,4 +1,5 @@
 // run-rustfix
+#![allow(dead_code)]
 
 trait Foo {
     fn bar() {} //~ ERROR non-item in item list
diff --git a/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.rs b/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.rs
index 4650b05e20c..c8f525fc4f0 100644
--- a/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.rs
+++ b/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.rs
@@ -1,4 +1,5 @@
 // run-rustfix
+#![allow(dead_code)]
 
 trait Foo {
     fn bar() {}; //~ ERROR non-item in item list
diff --git a/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.stderr b/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.stderr
index c716d5908ea..396c76ac85f 100644
--- a/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.stderr
+++ b/tests/ui/parser/suggest-removing-semicolon-after-impl-trait-items.stderr
@@ -1,5 +1,5 @@
 error: non-item in item list
-  --> $DIR/suggest-removing-semicolon-after-impl-trait-items.rs:4:16
+  --> $DIR/suggest-removing-semicolon-after-impl-trait-items.rs:5:16
    |
 LL | trait Foo {
    |           - item list starts here
diff --git a/tests/ui/pattern/issue-22546.rs b/tests/ui/pattern/issue-22546.rs
index c26e457f9e4..8a0f51d0b84 100644
--- a/tests/ui/pattern/issue-22546.rs
+++ b/tests/ui/pattern/issue-22546.rs
@@ -15,7 +15,7 @@ impl<T: ::std::fmt::Display> Foo<T> {
     }
 }
 
-trait Tr {
+trait Tr { //~ WARN trait `Tr` is never used
     type U;
 }
 
diff --git a/tests/ui/pattern/issue-22546.stderr b/tests/ui/pattern/issue-22546.stderr
new file mode 100644
index 00000000000..e067a95e422
--- /dev/null
+++ b/tests/ui/pattern/issue-22546.stderr
@@ -0,0 +1,10 @@
+warning: trait `Tr` is never used
+  --> $DIR/issue-22546.rs:18:7
+   |
+LL | trait Tr {
+   |       ^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.rs b/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.rs
index a619fcafc86..1eba7aeb4d6 100644
--- a/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.rs
+++ b/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.rs
@@ -1,9 +1,23 @@
 fn main() {
     match &[1, 2, 3][..] {
-        [1, rest..] => println!("{rest:?}"),
+        [1, rest..] => println!("{rest}"),
         //~^ ERROR cannot find value `rest` in this scope
         //~| ERROR cannot find value `rest` in this scope
         //~| ERROR `X..` patterns in slices are experimental
         _ => {}
     }
+    match &[4, 5, 6][..] {
+        [] => {}
+        [_, ..tail] => println!("{tail}"),
+        //~^ ERROR cannot find value `tail` in this scope
+        //~| ERROR cannot find value `tail` in this scope
+        //~| ERROR exclusive range pattern syntax is experimental
+    }
+    match &[7, 8, 9][..] {
+        [] => {}
+        [_, ...tail] => println!("{tail}"),
+        //~^ ERROR cannot find value `tail` in this scope
+        //~| ERROR cannot find value `tail` in this scope
+        //~| ERROR range-to patterns with `...` are not allowed
+    }
 }
diff --git a/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr b/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr
index c3c9131b63e..3a19517c85b 100644
--- a/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr
+++ b/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr
@@ -1,31 +1,82 @@
+error: range-to patterns with `...` are not allowed
+  --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:18:13
+   |
+LL |         [_, ...tail] => println!("{tail}"),
+   |             ^^^ help: use `..=` instead
+
 error[E0425]: cannot find value `rest` in this scope
   --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:3:13
    |
-LL |         [1, rest..] => println!("{rest:?}"),
+LL |         [1, rest..] => println!("{rest}"),
    |             ^^^^ not found in this scope
    |
 help: if you meant to collect the rest of the slice in `rest`, use the at operator
    |
-LL |         [1, rest @ ..] => println!("{rest:?}"),
+LL |         [1, rest @ ..] => println!("{rest}"),
    |                  +
 
 error[E0425]: cannot find value `rest` in this scope
   --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:3:35
    |
-LL |         [1, rest..] => println!("{rest:?}"),
+LL |         [1, rest..] => println!("{rest}"),
+   |                                   ^^^^ not found in this scope
+
+error[E0425]: cannot find value `tail` in this scope
+  --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:11:15
+   |
+LL |         [_, ..tail] => println!("{tail}"),
+   |               ^^^^ not found in this scope
+   |
+help: if you meant to collect the rest of the slice in `tail`, use the at operator
+   |
+LL |         [_, tail @ ..] => println!("{tail}"),
+   |             ~~~~~~~~~
+
+error[E0425]: cannot find value `tail` in this scope
+  --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:11:35
+   |
+LL |         [_, ..tail] => println!("{tail}"),
    |                                   ^^^^ not found in this scope
 
+error[E0425]: cannot find value `tail` in this scope
+  --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:18:16
+   |
+LL |         [_, ...tail] => println!("{tail}"),
+   |                ^^^^ not found in this scope
+   |
+help: if you meant to collect the rest of the slice in `tail`, use the at operator
+   |
+LL |         [_, tail @ ..] => println!("{tail}"),
+   |             ~~~~~~~~~
+
+error[E0425]: cannot find value `tail` in this scope
+  --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:18:36
+   |
+LL |         [_, ...tail] => println!("{tail}"),
+   |                                    ^^^^ not found in this scope
+
 error[E0658]: `X..` patterns in slices are experimental
   --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:3:13
    |
-LL |         [1, rest..] => println!("{rest:?}"),
+LL |         [1, rest..] => println!("{rest}"),
    |             ^^^^^^
    |
    = note: see issue #67264 <https://github.com/rust-lang/rust/issues/67264> for more information
    = help: add `#![feature(half_open_range_patterns_in_slices)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: aborting due to 3 previous errors
+error[E0658]: exclusive range pattern syntax is experimental
+  --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:11:13
+   |
+LL |         [_, ..tail] => println!("{tail}"),
+   |             ^^^^^^
+   |
+   = note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
+   = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = help: use an inclusive range pattern, like N..=M
+
+error: aborting due to 9 previous errors
 
 Some errors have detailed explanations: E0425, E0658.
 For more information about an error, try `rustc --explain E0425`.
diff --git a/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr
index 0b4d9972758..59b454d3981 100644
--- a/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr
+++ b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr
@@ -9,3 +9,21 @@ LL |     if let CONSTANT = &&MyType {
 
 error: aborting due to 1 previous error
 
+Future incompatibility report: Future breakage diagnostic:
+warning: to use a constant of type `MyType` in a pattern, `MyType` must be annotated with `#[derive(PartialEq)]`
+  --> $DIR/const-partial_eq-fallback-ice.rs:14:12
+   |
+LL |     if let CONSTANT = &&MyType {
+   |            ^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: the traits must be derived, manual `impl`s are not sufficient
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+note: the lint level is defined here
+  --> $DIR/const-partial_eq-fallback-ice.rs:1:10
+   |
+LL | #![allow(warnings)]
+   |          ^^^^^^^^
+   = note: `#[allow(indirect_structural_match)]` implied by `#[allow(warnings)]`
+
diff --git a/tests/ui/pattern/usefulness/consts-opaque.stderr b/tests/ui/pattern/usefulness/consts-opaque.stderr
index 0b1a2e2736e..6a5bd185e39 100644
--- a/tests/ui/pattern/usefulness/consts-opaque.stderr
+++ b/tests/ui/pattern/usefulness/consts-opaque.stderr
@@ -5,7 +5,7 @@ LL |         QUUX => {}
    |         ^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
    = note: `#[warn(pointer_structural_match)]` on by default
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
@@ -15,7 +15,7 @@ LL |         QUUX => {}
    |         ^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/consts-opaque.rs:108:9
@@ -24,7 +24,7 @@ LL |         WRAPQUUX => {}
    |         ^^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/consts-opaque.rs:110:9
@@ -33,7 +33,7 @@ LL |         WRAPQUUX => {}
    |         ^^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/consts-opaque.rs:117:9
@@ -42,7 +42,7 @@ LL |         WRAPQUUX => {}
    |         ^^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/consts-opaque.rs:127:9
@@ -51,7 +51,7 @@ LL |         WRAPQUUX => {}
    |         ^^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/consts-opaque.rs:139:9
@@ -60,7 +60,7 @@ LL |         WHOKNOWSQUUX => {}
    |         ^^^^^^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/consts-opaque.rs:142:9
@@ -69,7 +69,7 @@ LL |         WHOKNOWSQUUX => {}
    |         ^^^^^^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 error: unreachable pattern
   --> $DIR/consts-opaque.rs:48:9
@@ -166,3 +166,91 @@ LL |         WRAPQUUX => {}, Wrap(_) => todo!()
 error: aborting due to 10 previous errors; 8 warnings emitted
 
 For more information about this error, try `rustc --explain E0004`.
+Future incompatibility report: Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/consts-opaque.rs:96:9
+   |
+LL |         QUUX => {}
+   |         ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/consts-opaque.rs:98:9
+   |
+LL |         QUUX => {}
+   |         ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/consts-opaque.rs:108:9
+   |
+LL |         WRAPQUUX => {}
+   |         ^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/consts-opaque.rs:110:9
+   |
+LL |         WRAPQUUX => {}
+   |         ^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/consts-opaque.rs:117:9
+   |
+LL |         WRAPQUUX => {}
+   |         ^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/consts-opaque.rs:127:9
+   |
+LL |         WRAPQUUX => {}
+   |         ^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/consts-opaque.rs:139:9
+   |
+LL |         WHOKNOWSQUUX => {}
+   |         ^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/consts-opaque.rs:142:9
+   |
+LL |         WHOKNOWSQUUX => {}
+   |         ^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
diff --git a/tests/ui/privacy/sealed-traits/re-exported-trait.fixed b/tests/ui/privacy/sealed-traits/re-exported-trait.fixed
index 79b6a6516ab..6de7b865a99 100644
--- a/tests/ui/privacy/sealed-traits/re-exported-trait.fixed
+++ b/tests/ui/privacy/sealed-traits/re-exported-trait.fixed
@@ -1,4 +1,5 @@
 // run-rustfix
+#![allow(dead_code)]
 
 pub mod a {
     pub use self::b::Trait;
diff --git a/tests/ui/privacy/sealed-traits/re-exported-trait.rs b/tests/ui/privacy/sealed-traits/re-exported-trait.rs
index 5f96dfdcbd6..bf07d666dff 100644
--- a/tests/ui/privacy/sealed-traits/re-exported-trait.rs
+++ b/tests/ui/privacy/sealed-traits/re-exported-trait.rs
@@ -1,4 +1,5 @@
 // run-rustfix
+#![allow(dead_code)]
 
 pub mod a {
     pub use self::b::Trait;
diff --git a/tests/ui/privacy/sealed-traits/re-exported-trait.stderr b/tests/ui/privacy/sealed-traits/re-exported-trait.stderr
index 9f2291e6825..6e2f36e3f38 100644
--- a/tests/ui/privacy/sealed-traits/re-exported-trait.stderr
+++ b/tests/ui/privacy/sealed-traits/re-exported-trait.stderr
@@ -1,11 +1,11 @@
 error[E0603]: module `b` is private
-  --> $DIR/re-exported-trait.rs:11:9
+  --> $DIR/re-exported-trait.rs:12:9
    |
 LL | impl a::b::Trait for S {}
    |         ^ private module
    |
 note: the module `b` is defined here
-  --> $DIR/re-exported-trait.rs:5:5
+  --> $DIR/re-exported-trait.rs:6:5
    |
 LL |     mod b {
    |     ^^^^^
diff --git a/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.fixed b/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.fixed
index ae5f9f86726..a61c868ed0a 100644
--- a/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.fixed
+++ b/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.fixed
@@ -1,6 +1,7 @@
 // run-rustfix
 
 #[derive(Debug)] //~ ERROR `derive` attribute cannot be used at crate level
+#[allow(dead_code)]
 struct Test {}
 
 fn main() {}
diff --git a/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.rs b/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.rs
index 639c64f8827..403f4470de7 100644
--- a/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.rs
+++ b/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.rs
@@ -1,6 +1,7 @@
 // run-rustfix
 
 #![derive(Debug)] //~ ERROR `derive` attribute cannot be used at crate level
+#[allow(dead_code)]
 struct Test {}
 
 fn main() {}
diff --git a/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.stderr b/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.stderr
index f62cdd14b87..09908160542 100644
--- a/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.stderr
+++ b/tests/ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.stderr
@@ -3,6 +3,7 @@ error: `derive` attribute cannot be used at crate level
    |
 LL | #![derive(Debug)]
    | ^^^^^^^^^^^^^^^^^
+LL | #[allow(dead_code)]
 LL | struct Test {}
    |        ---- the inner attribute doesn't annotate this struct
    |
diff --git a/tests/ui/regions/regions-no-variance-from-fn-generics.rs b/tests/ui/regions/regions-no-variance-from-fn-generics.rs
index 76706a82781..a455d4efd71 100644
--- a/tests/ui/regions/regions-no-variance-from-fn-generics.rs
+++ b/tests/ui/regions/regions-no-variance-from-fn-generics.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 #![allow(unused_variables)]
 // Issue #12856: a lifetime formal binding introduced by a generic fn
 // should not upset the variance inference for actual occurrences of
diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr
index 4f853829279..fbb9ede8aa1 100644
--- a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr
+++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr
@@ -5,6 +5,8 @@ LL | fn outer<T: Tr>() { // outer function
    |          - type parameter from outer item
 LL |     const K: u32 = T::C;
    |                    ^^^^ use of generic parameter from outer item
+   |
+   = note: a `const` is a separate item from the item that contains it
 
 error[E0401]: can't use generic parameters from outer item
   --> $DIR/generic-params-from-outer-item-in-const-item.rs:19:24
@@ -14,6 +16,8 @@ LL | impl<T> Tr for T { // outer impl block
 LL |     const C: u32 = {
 LL |         const I: u32 = T::C;
    |                        ^^^^ use of generic parameter from outer item
+   |
+   = note: a `const` is a separate item from the item that contains it
 
 error[E0401]: can't use generic parameters from outer item
   --> $DIR/generic-params-from-outer-item-in-const-item.rs:27:20
@@ -22,6 +26,8 @@ LL | struct S<T: Tr>(U32<{ // outer struct
    |          - type parameter from outer item
 LL |     const _: u32 = T::C;
    |                    ^^^^ use of generic parameter from outer item
+   |
+   = note: a `const` is a separate item from the item that contains it
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr
index 1cb55842bc6..60aa94038c3 100644
--- a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr
+++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr
@@ -7,6 +7,8 @@ LL |     const K: u32 = T::C;
    |            -       ^^^^ use of generic parameter from outer item
    |            |
    |            help: try introducing a local generic parameter here: `<T>`
+   |
+   = note: a `const` is a separate item from the item that contains it
 
 error[E0401]: can't use generic parameters from outer item
   --> $DIR/generic-params-from-outer-item-in-const-item.rs:19:24
@@ -18,6 +20,8 @@ LL |         const I: u32 = T::C;
    |                -       ^^^^ use of generic parameter from outer item
    |                |
    |                help: try introducing a local generic parameter here: `<T>`
+   |
+   = note: a `const` is a separate item from the item that contains it
 
 error[E0401]: can't use generic parameters from outer item
   --> $DIR/generic-params-from-outer-item-in-const-item.rs:27:20
@@ -28,6 +32,8 @@ LL |     const _: u32 = T::C;
    |            -       ^^^^ use of generic parameter from outer item
    |            |
    |            help: try introducing a local generic parameter here: `<T>`
+   |
+   = note: a `const` is a separate item from the item that contains it
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.fixed b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.fixed
index e730f94660b..a7ab88fe993 100644
--- a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.fixed
+++ b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.fixed
@@ -1,5 +1,6 @@
 // run-rustfix
 
+#![allow(dead_code)]
 #![deny(unused_qualifications)]
 #![feature(unsized_fn_params)]
 
diff --git a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs
index 641c892e3de..05936b191ff 100644
--- a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs
+++ b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs
@@ -1,5 +1,6 @@
 // run-rustfix
 
+#![allow(dead_code)]
 #![deny(unused_qualifications)]
 #![feature(unsized_fn_params)]
 
diff --git a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.stderr b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.stderr
index d9c7fd21871..bcda7210712 100644
--- a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.stderr
+++ b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.stderr
@@ -1,11 +1,11 @@
 error: unnecessary qualification
-  --> $DIR/issue-113808-invalid-unused-qualifications-suggestion.rs:12:6
+  --> $DIR/issue-113808-invalid-unused-qualifications-suggestion.rs:13:6
    |
 LL | impl ops::Index<str> for A {
    |      ^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/issue-113808-invalid-unused-qualifications-suggestion.rs:3:9
+  --> $DIR/issue-113808-invalid-unused-qualifications-suggestion.rs:4:9
    |
 LL | #![deny(unused_qualifications)]
    |         ^^^^^^^^^^^^^^^^^^^^^
@@ -16,7 +16,7 @@ LL + impl Index<str> for A {
    |
 
 error: unnecessary qualification
-  --> $DIR/issue-113808-invalid-unused-qualifications-suggestion.rs:28:6
+  --> $DIR/issue-113808-invalid-unused-qualifications-suggestion.rs:29:6
    |
 LL | impl inner::Trait<u8> for () {}
    |      ^^^^^^^^^^^^^^^^
diff --git a/tests/ui/resolve/issue-12796.rs b/tests/ui/resolve/issue-12796.rs
index de3e73437f0..e5dcf964345 100644
--- a/tests/ui/resolve/issue-12796.rs
+++ b/tests/ui/resolve/issue-12796.rs
@@ -1,7 +1,7 @@
 trait Trait {
     fn outer(&self) {
         fn inner(_: &Self) {
-            //~^ ERROR can't use generic parameters from outer item
+            //~^ ERROR can't use `Self` from outer item
         }
     }
 }
diff --git a/tests/ui/resolve/issue-12796.stderr b/tests/ui/resolve/issue-12796.stderr
index 6809fd50f74..2305971303a 100644
--- a/tests/ui/resolve/issue-12796.stderr
+++ b/tests/ui/resolve/issue-12796.stderr
@@ -1,10 +1,10 @@
-error[E0401]: can't use generic parameters from outer item
+error[E0401]: can't use `Self` from outer item
   --> $DIR/issue-12796.rs:3:22
    |
 LL |         fn inner(_: &Self) {
    |                      ^^^^
    |                      |
-   |                      use of generic parameter from outer item
+   |                      use of `Self` from outer item
    |                      can't use `Self` here
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/resolve/issue-65025-extern-static-parent-generics.stderr b/tests/ui/resolve/issue-65025-extern-static-parent-generics.stderr
index 363bb556478..ca32147d197 100644
--- a/tests/ui/resolve/issue-65025-extern-static-parent-generics.stderr
+++ b/tests/ui/resolve/issue-65025-extern-static-parent-generics.stderr
@@ -6,6 +6,8 @@ LL | unsafe fn foo<A>() {
 LL |     extern "C" {
 LL |         static baz: *const A;
    |                            ^ use of generic parameter from outer item
+   |
+   = note: a `static` is a separate item from the item that contains it
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/resolve/issue-65035-static-with-parent-generics.stderr b/tests/ui/resolve/issue-65035-static-with-parent-generics.stderr
index f1fe1a6002c..98ffb4567f1 100644
--- a/tests/ui/resolve/issue-65035-static-with-parent-generics.stderr
+++ b/tests/ui/resolve/issue-65035-static-with-parent-generics.stderr
@@ -6,6 +6,8 @@ LL | fn f<T>() {
 LL |     extern "C" {
 LL |         static a: *const T;
    |                          ^ use of generic parameter from outer item
+   |
+   = note: a `static` is a separate item from the item that contains it
 
 error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-65035-static-with-parent-generics.rs:9:22
@@ -14,6 +16,8 @@ LL | fn g<T: Default>() {
    |      - type parameter from outer item
 LL |     static a: *const T = Default::default();
    |                      ^ use of generic parameter from outer item
+   |
+   = note: a `static` is a separate item from the item that contains it
 
 error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-65035-static-with-parent-generics.rs:15:24
@@ -23,6 +27,8 @@ LL | fn h<const N: usize>() {
 LL |     extern "C" {
 LL |         static a: [u8; N];
    |                        ^ use of generic parameter from outer item
+   |
+   = note: a `static` is a separate item from the item that contains it
 
 error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-65035-static-with-parent-generics.rs:21:20
@@ -31,6 +37,8 @@ LL | fn i<const N: usize>() {
    |            - const parameter from outer item
 LL |     static a: [u8; N] = [0; N];
    |                    ^ use of generic parameter from outer item
+   |
+   = note: a `static` is a separate item from the item that contains it
 
 error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-65035-static-with-parent-generics.rs:21:29
@@ -39,6 +47,8 @@ LL | fn i<const N: usize>() {
    |            - const parameter from outer item
 LL |     static a: [u8; N] = [0; N];
    |                             ^ use of generic parameter from outer item
+   |
+   = note: a `static` is a separate item from the item that contains it
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/resolve/use-self-in-inner-fn.rs b/tests/ui/resolve/use-self-in-inner-fn.rs
index f4dfa4c40ab..62f9dc5664f 100644
--- a/tests/ui/resolve/use-self-in-inner-fn.rs
+++ b/tests/ui/resolve/use-self-in-inner-fn.rs
@@ -4,8 +4,8 @@ impl A {
 //~^ NOTE `Self` type implicitly declared here, by this `impl`
     fn banana(&mut self) {
         fn peach(this: &Self) {
-        //~^ ERROR can't use generic parameters from outer item
-        //~| NOTE use of generic parameter from outer item
+        //~^ ERROR can't use `Self` from outer item
+        //~| NOTE use of `Self` from outer item
         //~| NOTE refer to the type directly here instead
         }
     }
diff --git a/tests/ui/resolve/use-self-in-inner-fn.stderr b/tests/ui/resolve/use-self-in-inner-fn.stderr
index 165e100bf2f..9c388df8bc2 100644
--- a/tests/ui/resolve/use-self-in-inner-fn.stderr
+++ b/tests/ui/resolve/use-self-in-inner-fn.stderr
@@ -1,4 +1,4 @@
-error[E0401]: can't use generic parameters from outer item
+error[E0401]: can't use `Self` from outer item
   --> $DIR/use-self-in-inner-fn.rs:6:25
    |
 LL | impl A {
@@ -7,7 +7,7 @@ LL | impl A {
 LL |         fn peach(this: &Self) {
    |                         ^^^^
    |                         |
-   |                         use of generic parameter from outer item
+   |                         use of `Self` from outer item
    |                         refer to the type directly here instead
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr
index 910d491baaf..9945041113d 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr
@@ -5,7 +5,7 @@ LL |         WRAP_DOUBLY_INDIRECT_INLINE => { panic!("WRAP_DOUBLY_INDIRECT_INLIN
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 note: the lint level is defined here
@@ -16,3 +16,20 @@ LL | #![warn(indirect_structural_match)]
 
 warning: 1 warning emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
+  --> $DIR/cant-hide-behind-doubly-indirect-embedded.rs:24:9
+   |
+LL |         WRAP_DOUBLY_INDIRECT_INLINE => { panic!("WRAP_DOUBLY_INDIRECT_INLINE matched itself"); }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: the traits must be derived, manual `impl`s are not sufficient
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+note: the lint level is defined here
+  --> $DIR/cant-hide-behind-doubly-indirect-embedded.rs:7:9
+   |
+LL | #![warn(indirect_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr
index cadd9be023c..6ac261ae814 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr
@@ -5,7 +5,7 @@ LL |         WRAP_DOUBLY_INDIRECT_PARAM => { panic!("WRAP_DOUBLY_INDIRECT_PARAM
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 note: the lint level is defined here
@@ -16,3 +16,20 @@ LL | #![warn(indirect_structural_match)]
 
 warning: 1 warning emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
+  --> $DIR/cant-hide-behind-doubly-indirect-param.rs:24:9
+   |
+LL |         WRAP_DOUBLY_INDIRECT_PARAM => { panic!("WRAP_DOUBLY_INDIRECT_PARAM matched itself"); }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: the traits must be derived, manual `impl`s are not sufficient
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+note: the lint level is defined here
+  --> $DIR/cant-hide-behind-doubly-indirect-param.rs:7:9
+   |
+LL | #![warn(indirect_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr
index e4321cc6a4c..41616fb90fe 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr
@@ -5,7 +5,7 @@ LL |         WRAP_INDIRECT_INLINE => { panic!("WRAP_INDIRECT_INLINE matched itse
    |         ^^^^^^^^^^^^^^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 note: the lint level is defined here
@@ -16,3 +16,20 @@ LL | #![warn(indirect_structural_match)]
 
 warning: 1 warning emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
+  --> $DIR/cant-hide-behind-indirect-struct-embedded.rs:24:9
+   |
+LL |         WRAP_INDIRECT_INLINE => { panic!("WRAP_INDIRECT_INLINE matched itself"); }
+   |         ^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: the traits must be derived, manual `impl`s are not sufficient
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+note: the lint level is defined here
+  --> $DIR/cant-hide-behind-indirect-struct-embedded.rs:7:9
+   |
+LL | #![warn(indirect_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr
index decc29ad67c..99dea5171d1 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr
@@ -5,7 +5,7 @@ LL |         WRAP_INDIRECT_PARAM => { panic!("WRAP_INDIRECT_PARAM matched itself
    |         ^^^^^^^^^^^^^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 note: the lint level is defined here
@@ -16,3 +16,20 @@ LL | #![warn(indirect_structural_match)]
 
 warning: 1 warning emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
+  --> $DIR/cant-hide-behind-indirect-struct-param.rs:24:9
+   |
+LL |         WRAP_INDIRECT_PARAM => { panic!("WRAP_INDIRECT_PARAM matched itself"); }
+   |         ^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: the traits must be derived, manual `impl`s are not sufficient
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+note: the lint level is defined here
+  --> $DIR/cant-hide-behind-indirect-struct-param.rs:7:9
+   |
+LL | #![warn(indirect_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.stderr
index 080bf5885ba..11163ba70ec 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.stderr
@@ -5,7 +5,7 @@ LL |         Wrap(CFN1) => count += 1,
    |              ^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
    = note: `#[warn(pointer_structural_match)]` on by default
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
@@ -15,7 +15,7 @@ LL |         Wrap(CFN2) => count += 1,
    |              ^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/fn-ptr-is-structurally-matchable.rs:61:14
@@ -24,7 +24,7 @@ LL |         Wrap(CFN3) => count += 1,
    |              ^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/fn-ptr-is-structurally-matchable.rs:70:14
@@ -33,7 +33,7 @@ LL |         Wrap(CFN4) => count += 1,
    |              ^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/fn-ptr-is-structurally-matchable.rs:79:14
@@ -42,7 +42,7 @@ LL |         Wrap(CFN5) => count += 1,
    |              ^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/fn-ptr-is-structurally-matchable.rs:88:14
@@ -51,7 +51,7 @@ LL |         Wrap(CFN6) => count += 1,
    |              ^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/fn-ptr-is-structurally-matchable.rs:97:14
@@ -60,7 +60,7 @@ LL |         Wrap(CFN7) => count += 1,
    |              ^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/fn-ptr-is-structurally-matchable.rs:106:14
@@ -69,7 +69,7 @@ LL |         Wrap(CFN8) => count += 1,
    |              ^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/fn-ptr-is-structurally-matchable.rs:115:14
@@ -78,7 +78,7 @@ LL |         Wrap(CFN9) => count += 1,
    |              ^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/fn-ptr-is-structurally-matchable.rs:138:9
@@ -87,7 +87,117 @@ LL |         CFOO => count += 1,
    |         ^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: 10 warnings emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/fn-ptr-is-structurally-matchable.rs:43:14
+   |
+LL |         Wrap(CFN1) => count += 1,
+   |              ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/fn-ptr-is-structurally-matchable.rs:52:14
+   |
+LL |         Wrap(CFN2) => count += 1,
+   |              ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/fn-ptr-is-structurally-matchable.rs:61:14
+   |
+LL |         Wrap(CFN3) => count += 1,
+   |              ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/fn-ptr-is-structurally-matchable.rs:70:14
+   |
+LL |         Wrap(CFN4) => count += 1,
+   |              ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/fn-ptr-is-structurally-matchable.rs:79:14
+   |
+LL |         Wrap(CFN5) => count += 1,
+   |              ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/fn-ptr-is-structurally-matchable.rs:88:14
+   |
+LL |         Wrap(CFN6) => count += 1,
+   |              ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/fn-ptr-is-structurally-matchable.rs:97:14
+   |
+LL |         Wrap(CFN7) => count += 1,
+   |              ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/fn-ptr-is-structurally-matchable.rs:106:14
+   |
+LL |         Wrap(CFN8) => count += 1,
+   |              ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/fn-ptr-is-structurally-matchable.rs:115:14
+   |
+LL |         Wrap(CFN9) => count += 1,
+   |              ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/fn-ptr-is-structurally-matchable.rs:138:9
+   |
+LL |         CFOO => count += 1,
+   |         ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs
index fdb67bcf2d8..374e5d5acd0 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs
@@ -10,7 +10,7 @@
 
 // Issue 62307 pointed out a case where the structural-match checking
 // was too shallow.
-#![warn(indirect_structural_match, nontrivial_structural_match)]
+#![warn(indirect_structural_match)]
 // run-pass
 
 #[derive(Debug)]
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr
index d0f2b820afa..d4ab1ce3ba2 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr
@@ -5,13 +5,13 @@ LL |         RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0);
    |         ^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 note: the lint level is defined here
   --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:13:9
    |
-LL | #![warn(indirect_structural_match, nontrivial_structural_match)]
+LL | #![warn(indirect_structural_match)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq)]`
@@ -21,9 +21,43 @@ LL |         RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1);
    |         ^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 warning: 2 warnings emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq)]`
+  --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:31:9
+   |
+LL |         RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); }
+   |         ^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: the traits must be derived, manual `impl`s are not sufficient
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+note: the lint level is defined here
+  --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:13:9
+   |
+LL | #![warn(indirect_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+warning: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq)]`
+  --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:38:9
+   |
+LL |         RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1); }
+   |         ^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: the traits must be derived, manual `impl`s are not sufficient
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+note: the lint level is defined here
+  --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:13:9
+   |
+LL | #![warn(indirect_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr
index 4fdfce60bb8..0edcf44c4d7 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr
@@ -5,7 +5,7 @@ LL |     B(TEST) => println!("matched"),
    |       ^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 note: the lint level is defined here
   --> $DIR/issue-63479-match-fnptr.rs:8:9
    |
@@ -19,7 +19,37 @@ LL |     TEST2 => println!("matched"),
    |     ^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: 2 warnings emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/issue-63479-match-fnptr.rs:36:7
+   |
+LL |     B(TEST) => println!("matched"),
+   |       ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+note: the lint level is defined here
+  --> $DIR/issue-63479-match-fnptr.rs:8:9
+   |
+LL | #![warn(pointer_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/issue-63479-match-fnptr.rs:42:5
+   |
+LL |     TEST2 => println!("matched"),
+   |     ^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+note: the lint level is defined here
+  --> $DIR/issue-63479-match-fnptr.rs:8:9
+   |
+LL | #![warn(pointer_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.current.stderr b/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.current.stderr
new file mode 100644
index 00000000000..4a219ff8b55
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.current.stderr
@@ -0,0 +1,15 @@
+warning: methods `good_virt` and `good_indirect` are never used
+  --> $DIR/manual-self-impl-for-unsafe-obj.rs:22:8
+   |
+LL | trait Good {
+   |       ---- methods in this trait
+LL |     fn good_virt(&self) -> char {
+   |        ^^^^^^^^^
+...
+LL |     fn good_indirect(&self) -> char {
+   |        ^^^^^^^^^^^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.next.stderr b/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.next.stderr
new file mode 100644
index 00000000000..4a219ff8b55
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.next.stderr
@@ -0,0 +1,15 @@
+warning: methods `good_virt` and `good_indirect` are never used
+  --> $DIR/manual-self-impl-for-unsafe-obj.rs:22:8
+   |
+LL | trait Good {
+   |       ---- methods in this trait
+LL |     fn good_virt(&self) -> char {
+   |        ^^^^^^^^^
+...
+LL |     fn good_indirect(&self) -> char {
+   |        ^^^^^^^^^^^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs b/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs
index c7665affb99..c8eee9835fe 100644
--- a/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs
+++ b/tests/ui/rfcs/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs
@@ -19,7 +19,7 @@ trait Bad {
 }
 
 trait Good {
-    fn good_virt(&self) -> char {
+    fn good_virt(&self) -> char { //~ WARN methods `good_virt` and `good_indirect` are never used
         panic!()
     }
     fn good_indirect(&self) -> char {
diff --git a/tests/ui/rust-2018/issue-51008-1.rs b/tests/ui/rust-2018/issue-51008-1.rs
index da7b8ef65c5..67dfbf64601 100644
--- a/tests/ui/rust-2018/issue-51008-1.rs
+++ b/tests/ui/rust-2018/issue-51008-1.rs
@@ -2,7 +2,7 @@
 // being incorrectly considered part of the "elided lifetimes" from
 // the impl.
 //
-// run-pass
+// check-pass
 
 trait A {
 
diff --git a/tests/ui/rust-2018/issue-51008.rs b/tests/ui/rust-2018/issue-51008.rs
index 56517b9adee..f9e4bc14ec8 100644
--- a/tests/ui/rust-2018/issue-51008.rs
+++ b/tests/ui/rust-2018/issue-51008.rs
@@ -2,7 +2,7 @@
 // being incorrectly considered part of the "elided lifetimes" from
 // the impl.
 //
-// run-pass
+// check-pass
 
 trait A {
 
diff --git a/tests/ui/sized/coinductive-2.rs b/tests/ui/sized/coinductive-2.rs
index 212274d2e4b..43a5a28f710 100644
--- a/tests/ui/sized/coinductive-2.rs
+++ b/tests/ui/sized/coinductive-2.rs
@@ -11,7 +11,7 @@ impl<T> CollectionFactory<T> for Vec<()> {
     type Collection = Vec<T>;
 }
 
-trait Collection<T>: Sized {
+trait Collection<T>: Sized { //~ WARN trait `Collection` is never used
     fn push(&mut self, v: T);
 }
 
diff --git a/tests/ui/sized/coinductive-2.stderr b/tests/ui/sized/coinductive-2.stderr
new file mode 100644
index 00000000000..1390b1f8d7b
--- /dev/null
+++ b/tests/ui/sized/coinductive-2.stderr
@@ -0,0 +1,10 @@
+warning: trait `Collection` is never used
+  --> $DIR/coinductive-2.rs:14:7
+   |
+LL | trait Collection<T>: Sized {
+   |       ^^^^^^^^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs
index a9d678c1e6a..66a432be357 100644
--- a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs
+++ b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs
@@ -9,7 +9,7 @@ impl Numberer {
     //~^ ERROR `async fn` is not permitted in Rust 2015
         interval: Duration,
         //~^ ERROR cannot find type `Duration` in this scope
-    ) -> Numberer { //~WARN: changes to closure capture in Rust 2021
+    ) -> Numberer {
         Numberer {}
     }
 }
diff --git a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr
index 71e9e7602e8..60433e1c284 100644
--- a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr
+++ b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr
@@ -18,32 +18,7 @@ help: consider importing this struct
 LL + use std::time::Duration;
    |
 
-warning: changes to closure capture in Rust 2021 will affect drop order
-  --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs:12:19
-   |
-LL |           interval: Duration,
-   |           -------- in Rust 2018, this causes the closure to capture `interval`, but in Rust 2021, it has no effect
-LL |
-LL |       ) -> Numberer {
-   |  _________________-_^
-   | |                 |
-   | |                 in Rust 2018, `interval` is dropped here along with the closure, but in Rust 2021 `interval` is not part of the closure
-LL | |         Numberer {}
-LL | |     }
-   | |_____^
-   |
-   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
-note: the lint level is defined here
-  --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs:1:9
-   |
-LL | #![warn(rust_2021_incompatible_closure_captures)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: add a dummy let to cause `interval` to be fully captured
-   |
-LL |     ) -> Numberer { let _ = &interval;
-   |                     ++++++++++++++++++
-
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0412, E0670.
 For more information about an error, try `rustc --explain E0412`.
diff --git a/tests/ui/specialization/assoc-ty-graph-cycle.rs b/tests/ui/specialization/assoc-ty-graph-cycle.rs
index fc39b553a61..bec8cc187b4 100644
--- a/tests/ui/specialization/assoc-ty-graph-cycle.rs
+++ b/tests/ui/specialization/assoc-ty-graph-cycle.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 // Make sure we don't crash with a cycle error during coherence.
 
diff --git a/tests/ui/specialization/defaultimpl/out-of-order.rs b/tests/ui/specialization/defaultimpl/out-of-order.rs
index 13258ac8c9f..94b3905178f 100644
--- a/tests/ui/specialization/defaultimpl/out-of-order.rs
+++ b/tests/ui/specialization/defaultimpl/out-of-order.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 // Test that you can list the more specific impl before the more general one.
 
diff --git a/tests/ui/specialization/defaultimpl/overlap-projection.rs b/tests/ui/specialization/defaultimpl/overlap-projection.rs
index 0add4d5516c..46f54c466a8 100644
--- a/tests/ui/specialization/defaultimpl/overlap-projection.rs
+++ b/tests/ui/specialization/defaultimpl/overlap-projection.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 // Test that impls on projected self types can resolve overlap, even when the
 // projections involve specialization, so long as the associated type is
diff --git a/tests/ui/specialization/specialization-out-of-order.rs b/tests/ui/specialization/specialization-out-of-order.rs
index cb7563e2760..66e6c3c9eab 100644
--- a/tests/ui/specialization/specialization-out-of-order.rs
+++ b/tests/ui/specialization/specialization-out-of-order.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 // Test that you can list the more specific impl before the more general one.
 
diff --git a/tests/ui/specialization/specialization-overlap-projection.rs b/tests/ui/specialization/specialization-overlap-projection.rs
index b07efb2a5c1..cd21eab24c0 100644
--- a/tests/ui/specialization/specialization-overlap-projection.rs
+++ b/tests/ui/specialization/specialization-overlap-projection.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 // Test that impls on projected self types can resolve overlap, even when the
 // projections involve specialization, so long as the associated type is
diff --git a/tests/ui/specialization/specialization-supertraits.rs b/tests/ui/specialization/specialization-supertraits.rs
index fb85d801921..d0c9dbb1d40 100644
--- a/tests/ui/specialization/specialization-supertraits.rs
+++ b/tests/ui/specialization/specialization-supertraits.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 #![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
diff --git a/tests/ui/statics/static-impl.rs b/tests/ui/statics/static-impl.rs
index e7bdb38ee62..9e2db7e0caf 100644
--- a/tests/ui/statics/static-impl.rs
+++ b/tests/ui/statics/static-impl.rs
@@ -35,7 +35,7 @@ impl uint_utils for usize {
 
 trait vec_utils<T> {
     fn length_(&self, ) -> usize;
-    fn iter_<F>(&self, f: F) where F: FnMut(&T);
+    fn iter_<F>(&self, f: F) where F: FnMut(&T); //~ WARN method `iter_` is never used
     fn map_<U, F>(&self, f: F) -> Vec<U> where F: FnMut(&T) -> U;
 }
 
diff --git a/tests/ui/statics/static-impl.stderr b/tests/ui/statics/static-impl.stderr
new file mode 100644
index 00000000000..83c3ffbefe1
--- /dev/null
+++ b/tests/ui/statics/static-impl.stderr
@@ -0,0 +1,13 @@
+warning: method `iter_` is never used
+  --> $DIR/static-impl.rs:38:8
+   |
+LL | trait vec_utils<T> {
+   |       --------- method in this trait
+LL |     fn length_(&self, ) -> usize;
+LL |     fn iter_<F>(&self, f: F) where F: FnMut(&T);
+   |        ^^^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/stdlib-unit-tests/raw-fat-ptr.rs b/tests/ui/stdlib-unit-tests/raw-fat-ptr.rs
index 0f535523dcc..4a8289cb242 100644
--- a/tests/ui/stdlib-unit-tests/raw-fat-ptr.rs
+++ b/tests/ui/stdlib-unit-tests/raw-fat-ptr.rs
@@ -32,7 +32,7 @@ fn assert_inorder<T: PartialEq + PartialOrd>(a: &[T]) {
     }
 }
 
-trait Foo { fn foo(&self) -> usize; }
+trait Foo { fn foo(&self) -> usize; } //~ WARN method `foo` is never used
 impl<T> Foo for T {
     fn foo(&self) -> usize {
         mem::size_of::<T>()
diff --git a/tests/ui/stdlib-unit-tests/raw-fat-ptr.stderr b/tests/ui/stdlib-unit-tests/raw-fat-ptr.stderr
new file mode 100644
index 00000000000..670fa5bb922
--- /dev/null
+++ b/tests/ui/stdlib-unit-tests/raw-fat-ptr.stderr
@@ -0,0 +1,12 @@
+warning: method `foo` is never used
+  --> $DIR/raw-fat-ptr.rs:35:16
+   |
+LL | trait Foo { fn foo(&self) -> usize; }
+   |       ---      ^^^
+   |       |
+   |       method in this trait
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/structs-enums/enum-null-pointer-opt.rs b/tests/ui/structs-enums/enum-null-pointer-opt.rs
index 356f8a6dd36..21564eeec29 100644
--- a/tests/ui/structs-enums/enum-null-pointer-opt.rs
+++ b/tests/ui/structs-enums/enum-null-pointer-opt.rs
@@ -7,7 +7,7 @@ use std::ptr::NonNull;
 use std::rc::Rc;
 use std::sync::Arc;
 
-trait Trait { fn dummy(&self) { } }
+trait Trait { fn dummy(&self) { } } //~ WARN method `dummy` is never used
 trait Mirror { type Image; }
 impl<T> Mirror for T { type Image = T; }
 struct ParamTypeStruct<T>(#[allow(dead_code)] T);
diff --git a/tests/ui/structs-enums/enum-null-pointer-opt.stderr b/tests/ui/structs-enums/enum-null-pointer-opt.stderr
new file mode 100644
index 00000000000..64e93ffaffd
--- /dev/null
+++ b/tests/ui/structs-enums/enum-null-pointer-opt.stderr
@@ -0,0 +1,12 @@
+warning: method `dummy` is never used
+  --> $DIR/enum-null-pointer-opt.rs:10:18
+   |
+LL | trait Trait { fn dummy(&self) { } }
+   |       -----      ^^^^^
+   |       |
+   |       method in this trait
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
index 3065f83ea3d..dc4ec5d3ee2 100644
--- a/tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
+++ b/tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
@@ -18,25 +18,21 @@ help: use parentheses to call this function
 LL |     bar(foo());
    |            ++
 
-error[E0277]: `{closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33}` is not a future
+error[E0277]: `{coroutine-closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33}` is not a future
   --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:12:9
    |
 LL |     bar(async_closure);
-   |     --- ^^^^^^^^^^^^^ `{closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33}` is not a future
+   |     --- ^^^^^^^^^^^^^ `{coroutine-closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33}` is not a future
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `Future` is not implemented for closure `{closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33}`
-   = note: {closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33} must be a future or must implement `IntoFuture` to be awaited
+   = help: the trait `Future` is not implemented for `{coroutine-closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33}`
+   = note: {coroutine-closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33} must be a future or must implement `IntoFuture` to be awaited
 note: required by a bound in `bar`
   --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:7:16
    |
 LL | fn bar(f: impl Future<Output=()>) {}
    |                ^^^^^^^^^^^^^^^^^ required by this bound in `bar`
-help: use parentheses to call this closure
-   |
-LL |     bar(async_closure());
-   |                      ++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/suggestions/bound-suggestions.fixed b/tests/ui/suggestions/bound-suggestions.fixed
index 17a019c6984..ef61fb9ad32 100644
--- a/tests/ui/suggestions/bound-suggestions.fixed
+++ b/tests/ui/suggestions/bound-suggestions.fixed
@@ -40,26 +40,31 @@ fn test_many_bounds_where<X>(x: X) where X: Sized + std::fmt::Debug, X: Sized {
     //~^ ERROR doesn't implement
 }
 
+#[allow(dead_code)]
 trait Foo<T>: Sized {
     const SIZE: usize = core::mem::size_of::<Self>();
     //~^ ERROR the size for values of type `Self` cannot be known at compilation time
 }
 
+#[allow(dead_code)]
 trait Bar: std::fmt::Display + Sized {
     const SIZE: usize = core::mem::size_of::<Self>();
     //~^ ERROR the size for values of type `Self` cannot be known at compilation time
 }
 
+#[allow(dead_code)]
 trait Baz: Sized where Self: std::fmt::Display {
     const SIZE: usize = core::mem::size_of::<Self>();
     //~^ ERROR the size for values of type `Self` cannot be known at compilation time
 }
 
+#[allow(dead_code)]
 trait Qux<T>: Sized where Self: std::fmt::Display {
     const SIZE: usize = core::mem::size_of::<Self>();
     //~^ ERROR the size for values of type `Self` cannot be known at compilation time
 }
 
+#[allow(dead_code)]
 trait Bat<T>: std::fmt::Display + Sized {
     const SIZE: usize = core::mem::size_of::<Self>();
     //~^ ERROR the size for values of type `Self` cannot be known at compilation time
diff --git a/tests/ui/suggestions/bound-suggestions.rs b/tests/ui/suggestions/bound-suggestions.rs
index 86f708d42f5..6d17fae6a08 100644
--- a/tests/ui/suggestions/bound-suggestions.rs
+++ b/tests/ui/suggestions/bound-suggestions.rs
@@ -40,26 +40,31 @@ fn test_many_bounds_where<X>(x: X) where X: Sized, X: Sized {
     //~^ ERROR doesn't implement
 }
 
+#[allow(dead_code)]
 trait Foo<T> {
     const SIZE: usize = core::mem::size_of::<Self>();
     //~^ ERROR the size for values of type `Self` cannot be known at compilation time
 }
 
+#[allow(dead_code)]
 trait Bar: std::fmt::Display {
     const SIZE: usize = core::mem::size_of::<Self>();
     //~^ ERROR the size for values of type `Self` cannot be known at compilation time
 }
 
+#[allow(dead_code)]
 trait Baz where Self: std::fmt::Display {
     const SIZE: usize = core::mem::size_of::<Self>();
     //~^ ERROR the size for values of type `Self` cannot be known at compilation time
 }
 
+#[allow(dead_code)]
 trait Qux<T> where Self: std::fmt::Display {
     const SIZE: usize = core::mem::size_of::<Self>();
     //~^ ERROR the size for values of type `Self` cannot be known at compilation time
 }
 
+#[allow(dead_code)]
 trait Bat<T>: std::fmt::Display {
     const SIZE: usize = core::mem::size_of::<Self>();
     //~^ ERROR the size for values of type `Self` cannot be known at compilation time
diff --git a/tests/ui/suggestions/bound-suggestions.stderr b/tests/ui/suggestions/bound-suggestions.stderr
index 7e58ccd461d..4965e7439f8 100644
--- a/tests/ui/suggestions/bound-suggestions.stderr
+++ b/tests/ui/suggestions/bound-suggestions.stderr
@@ -71,7 +71,7 @@ LL | fn test_many_bounds_where<X>(x: X) where X: Sized + std::fmt::Debug, X: Siz
    |                                                   +++++++++++++++++
 
 error[E0277]: the size for values of type `Self` cannot be known at compilation time
-  --> $DIR/bound-suggestions.rs:44:46
+  --> $DIR/bound-suggestions.rs:45:46
    |
 LL |     const SIZE: usize = core::mem::size_of::<Self>();
    |                                              ^^^^ doesn't have a size known at compile-time
@@ -84,7 +84,7 @@ LL | trait Foo<T>: Sized {
    |             +++++++
 
 error[E0277]: the size for values of type `Self` cannot be known at compilation time
-  --> $DIR/bound-suggestions.rs:49:46
+  --> $DIR/bound-suggestions.rs:51:46
    |
 LL |     const SIZE: usize = core::mem::size_of::<Self>();
    |                                              ^^^^ doesn't have a size known at compile-time
@@ -97,7 +97,7 @@ LL | trait Bar: std::fmt::Display + Sized {
    |                              +++++++
 
 error[E0277]: the size for values of type `Self` cannot be known at compilation time
-  --> $DIR/bound-suggestions.rs:54:46
+  --> $DIR/bound-suggestions.rs:57:46
    |
 LL |     const SIZE: usize = core::mem::size_of::<Self>();
    |                                              ^^^^ doesn't have a size known at compile-time
@@ -110,7 +110,7 @@ LL | trait Baz: Sized where Self: std::fmt::Display {
    |          +++++++
 
 error[E0277]: the size for values of type `Self` cannot be known at compilation time
-  --> $DIR/bound-suggestions.rs:59:46
+  --> $DIR/bound-suggestions.rs:63:46
    |
 LL |     const SIZE: usize = core::mem::size_of::<Self>();
    |                                              ^^^^ doesn't have a size known at compile-time
@@ -123,7 +123,7 @@ LL | trait Qux<T>: Sized where Self: std::fmt::Display {
    |             +++++++
 
 error[E0277]: the size for values of type `Self` cannot be known at compilation time
-  --> $DIR/bound-suggestions.rs:64:46
+  --> $DIR/bound-suggestions.rs:69:46
    |
 LL |     const SIZE: usize = core::mem::size_of::<Self>();
    |                                              ^^^^ doesn't have a size known at compile-time
diff --git a/tests/ui/suggestions/constrain-trait.fixed b/tests/ui/suggestions/constrain-trait.fixed
index f292f27f0f3..f7360efe4c5 100644
--- a/tests/ui/suggestions/constrain-trait.fixed
+++ b/tests/ui/suggestions/constrain-trait.fixed
@@ -1,5 +1,6 @@
 // run-rustfix
 // check-only
+#![allow(dead_code)]
 
 #[derive(Debug)]
 struct Demo {
diff --git a/tests/ui/suggestions/constrain-trait.rs b/tests/ui/suggestions/constrain-trait.rs
index 99ccf7a7f3b..799100669b6 100644
--- a/tests/ui/suggestions/constrain-trait.rs
+++ b/tests/ui/suggestions/constrain-trait.rs
@@ -1,5 +1,6 @@
 // run-rustfix
 // check-only
+#![allow(dead_code)]
 
 #[derive(Debug)]
 struct Demo {
diff --git a/tests/ui/suggestions/constrain-trait.stderr b/tests/ui/suggestions/constrain-trait.stderr
index a26f86917bc..b28972ecde0 100644
--- a/tests/ui/suggestions/constrain-trait.stderr
+++ b/tests/ui/suggestions/constrain-trait.stderr
@@ -1,5 +1,5 @@
 error[E0599]: no method named `get_a` found for reference `&Self` in the current scope
-  --> $DIR/constrain-trait.rs:15:31
+  --> $DIR/constrain-trait.rs:16:31
    |
 LL |         println!("{:?}", self.get_a());
    |                               ^^^^^ method not found in `&Self`
@@ -11,7 +11,7 @@ LL | trait UseString: std::fmt::Debug + GetString {
    |                                  +++++++++++
 
 error[E0599]: no method named `get_a` found for reference `&Self` in the current scope
-  --> $DIR/constrain-trait.rs:21:31
+  --> $DIR/constrain-trait.rs:22:31
    |
 LL |         println!("{:?}", self.get_a());
    |                               ^^^^^ method not found in `&Self`
diff --git a/tests/ui/suggestions/issue-109195.rs b/tests/ui/suggestions/issue-109195.rs
new file mode 100644
index 00000000000..cc499b0d776
--- /dev/null
+++ b/tests/ui/suggestions/issue-109195.rs
@@ -0,0 +1,20 @@
+fn main() {
+    String::from::utf8;
+    //~^ ERROR ambiguous associated type [E0223]
+    //~| HELP there is an associated function with a similar name: `from_utf8`
+    String::from::utf8();
+    //~^ ERROR ambiguous associated type [E0223]
+    //~| HELP there is an associated function with a similar name: `from_utf8`
+    String::from::utf16();
+    //~^ ERROR ambiguous associated type [E0223]
+    //~| HELP there is an associated function with a similar name: `from_utf16`
+    String::from::method_that_doesnt_exist();
+    //~^ ERROR ambiguous associated type [E0223]
+    //~| HELP if there were a trait named `Example` with associated type `from`
+    str::from::utf8();
+    //~^ ERROR ambiguous associated type [E0223]
+    //~| HELP if there were a trait named `Example` with associated type `from`
+    str::from::utf8_mut();
+    //~^ ERROR ambiguous associated type [E0223]
+    //~| HELP if there were a trait named `Example` with associated type `from`
+}
diff --git a/tests/ui/suggestions/issue-109195.stderr b/tests/ui/suggestions/issue-109195.stderr
new file mode 100644
index 00000000000..10cf9cfd28c
--- /dev/null
+++ b/tests/ui/suggestions/issue-109195.stderr
@@ -0,0 +1,69 @@
+error[E0223]: ambiguous associated type
+  --> $DIR/issue-109195.rs:2:5
+   |
+LL |     String::from::utf8;
+   |     ^^^^^^^^^^^^
+   |
+help: there is an associated function with a similar name: `from_utf8`
+   |
+LL |     String::from_utf8;
+   |             ~~~~~~~~~
+
+error[E0223]: ambiguous associated type
+  --> $DIR/issue-109195.rs:5:5
+   |
+LL |     String::from::utf8();
+   |     ^^^^^^^^^^^^
+   |
+help: there is an associated function with a similar name: `from_utf8`
+   |
+LL |     String::from_utf8();
+   |             ~~~~~~~~~
+
+error[E0223]: ambiguous associated type
+  --> $DIR/issue-109195.rs:8:5
+   |
+LL |     String::from::utf16();
+   |     ^^^^^^^^^^^^
+   |
+help: there is an associated function with a similar name: `from_utf16`
+   |
+LL |     String::from_utf16();
+   |             ~~~~~~~~~~
+
+error[E0223]: ambiguous associated type
+  --> $DIR/issue-109195.rs:11:5
+   |
+LL |     String::from::method_that_doesnt_exist();
+   |     ^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `from` implemented for `String`, you could use the fully-qualified path
+   |
+LL |     <String as Example>::from::method_that_doesnt_exist();
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0223]: ambiguous associated type
+  --> $DIR/issue-109195.rs:14:5
+   |
+LL |     str::from::utf8();
+   |     ^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `from` implemented for `str`, you could use the fully-qualified path
+   |
+LL |     <str as Example>::from::utf8();
+   |     ~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0223]: ambiguous associated type
+  --> $DIR/issue-109195.rs:17:5
+   |
+LL |     str::from::utf8_mut();
+   |     ^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `from` implemented for `str`, you could use the fully-qualified path
+   |
+LL |     <str as Example>::from::utf8_mut();
+   |     ~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0223`.
diff --git a/tests/ui/suggestions/lifetimes/type-param-bound-scope.fixed b/tests/ui/suggestions/lifetimes/type-param-bound-scope.fixed
index 3257ea04c69..d4a8381fcb1 100644
--- a/tests/ui/suggestions/lifetimes/type-param-bound-scope.fixed
+++ b/tests/ui/suggestions/lifetimes/type-param-bound-scope.fixed
@@ -1,6 +1,7 @@
 // Make sure we suggest the bound `T: 'a` in the correct scope:
 // trait, impl or associated fn.
 // run-rustfix
+#![allow(dead_code)]
 
 struct Inv<'a>(#[allow(dead_code)] Option<*mut &'a u8>);
 
diff --git a/tests/ui/suggestions/lifetimes/type-param-bound-scope.rs b/tests/ui/suggestions/lifetimes/type-param-bound-scope.rs
index fcc13aad996..dc43e2df6dd 100644
--- a/tests/ui/suggestions/lifetimes/type-param-bound-scope.rs
+++ b/tests/ui/suggestions/lifetimes/type-param-bound-scope.rs
@@ -1,6 +1,7 @@
 // Make sure we suggest the bound `T: 'a` in the correct scope:
 // trait, impl or associated fn.
 // run-rustfix
+#![allow(dead_code)]
 
 struct Inv<'a>(#[allow(dead_code)] Option<*mut &'a u8>);
 
diff --git a/tests/ui/suggestions/lifetimes/type-param-bound-scope.stderr b/tests/ui/suggestions/lifetimes/type-param-bound-scope.stderr
index d3ca2cc1162..91054472c04 100644
--- a/tests/ui/suggestions/lifetimes/type-param-bound-scope.stderr
+++ b/tests/ui/suggestions/lifetimes/type-param-bound-scope.stderr
@@ -1,5 +1,5 @@
 error[E0309]: the parameter type `Self` may not live long enough
-  --> $DIR/type-param-bound-scope.rs:11:9
+  --> $DIR/type-param-bound-scope.rs:12:9
    |
 LL | trait Trait1<'a>: Sized {
    |              -- the parameter type `Self` must be valid for the lifetime `'a` as defined here...
@@ -13,7 +13,7 @@ LL | trait Trait1<'a>: Sized where Self: 'a {
    |                         ++++++++++++++
 
 error[E0309]: the parameter type `Self` may not live long enough
-  --> $DIR/type-param-bound-scope.rs:18:9
+  --> $DIR/type-param-bound-scope.rs:19:9
    |
 LL |     fn foo<'a>(self, lt: Inv<'a>) {
    |            -- the parameter type `Self` must be valid for the lifetime `'a` as defined here...
@@ -26,7 +26,7 @@ LL |     fn foo<'a>(self, lt: Inv<'a>) where Self: 'a {
    |                                   ++++++++++++++
 
 error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/type-param-bound-scope.rs:25:9
+  --> $DIR/type-param-bound-scope.rs:26:9
    |
 LL |     fn foo<'a>(arg: T, lt: Inv<'a>) {
    |            -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
@@ -39,7 +39,7 @@ LL |     fn foo<'a>(arg: T, lt: Inv<'a>) where T: 'a {
    |                                     +++++++++++
 
 error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/type-param-bound-scope.rs:32:9
+  --> $DIR/type-param-bound-scope.rs:33:9
    |
 LL | trait Trait4<'a> {
    |              -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
@@ -53,7 +53,7 @@ LL |     fn foo<T: 'a>(arg: T, lt: Inv<'a>) {
    |             ++++
 
 error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/type-param-bound-scope.rs:42:9
+  --> $DIR/type-param-bound-scope.rs:43:9
    |
 LL | impl<'a, T> Trait5<'a> for T {
    |      -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
diff --git a/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.fixed b/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.fixed
index f32c61a99bb..90bc10d34c6 100644
--- a/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.fixed
+++ b/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.fixed
@@ -1,4 +1,5 @@
 // run-rustfix
+#![allow(dead_code)]
 
 #[derive(Clone)]
 struct Wrapper<T>(T);
diff --git a/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.rs b/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.rs
index d7725f4a374..34673852a9b 100644
--- a/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.rs
+++ b/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.rs
@@ -1,4 +1,5 @@
 // run-rustfix
+#![allow(dead_code)]
 
 #[derive(Clone)]
 struct Wrapper<T>(T);
diff --git a/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.stderr b/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.stderr
index 6dc512223d1..23a75154f20 100644
--- a/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.stderr
+++ b/tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.stderr
@@ -1,5 +1,5 @@
 error[E0204]: the trait `Copy` cannot be implemented for this type
-  --> $DIR/missing-bound-in-manual-copy-impl-2.rs:16:18
+  --> $DIR/missing-bound-in-manual-copy-impl-2.rs:17:18
    |
 LL | struct Wrapper<T>(T);
    |                   - this field does not implement `Copy`
@@ -8,7 +8,7 @@ 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
+  --> $DIR/missing-bound-in-manual-copy-impl-2.rs:5:19
    |
 LL | struct Wrapper<T>(T);
    |                   ^
diff --git a/tests/ui/suggestions/missing-bound-in-manual-copy-impl.fixed b/tests/ui/suggestions/missing-bound-in-manual-copy-impl.fixed
index 1139b315313..ff84e42c947 100644
--- a/tests/ui/suggestions/missing-bound-in-manual-copy-impl.fixed
+++ b/tests/ui/suggestions/missing-bound-in-manual-copy-impl.fixed
@@ -1,4 +1,5 @@
 // run-rustfix
+#![allow(dead_code)]
 
 #[derive(Clone)]
 struct Wrapper<T>(T);
diff --git a/tests/ui/suggestions/missing-bound-in-manual-copy-impl.rs b/tests/ui/suggestions/missing-bound-in-manual-copy-impl.rs
index 19549248efc..35d0a9dda79 100644
--- a/tests/ui/suggestions/missing-bound-in-manual-copy-impl.rs
+++ b/tests/ui/suggestions/missing-bound-in-manual-copy-impl.rs
@@ -1,4 +1,5 @@
 // run-rustfix
+#![allow(dead_code)]
 
 #[derive(Clone)]
 struct Wrapper<T>(T);
diff --git a/tests/ui/suggestions/missing-bound-in-manual-copy-impl.stderr b/tests/ui/suggestions/missing-bound-in-manual-copy-impl.stderr
index fd38d4c64b4..c9f277fb350 100644
--- a/tests/ui/suggestions/missing-bound-in-manual-copy-impl.stderr
+++ b/tests/ui/suggestions/missing-bound-in-manual-copy-impl.stderr
@@ -1,5 +1,5 @@
 error[E0204]: the trait `Copy` cannot be implemented for this type
-  --> $DIR/missing-bound-in-manual-copy-impl.rs:6:18
+  --> $DIR/missing-bound-in-manual-copy-impl.rs:7:18
    |
 LL | struct Wrapper<T>(T);
    |                   - this field does not implement `Copy`
diff --git a/tests/ui/suggestions/missing-trait-item.fixed b/tests/ui/suggestions/missing-trait-item.fixed
index a1cf359ec91..ded4ec19760 100644
--- a/tests/ui/suggestions/missing-trait-item.fixed
+++ b/tests/ui/suggestions/missing-trait-item.fixed
@@ -1,4 +1,5 @@
 // run-rustfix
+#![allow(dead_code)]
 
 trait T {
     unsafe fn foo(a: &usize, b: &usize) -> usize;
diff --git a/tests/ui/suggestions/missing-trait-item.rs b/tests/ui/suggestions/missing-trait-item.rs
index b4fca25ba2f..de8974037ac 100644
--- a/tests/ui/suggestions/missing-trait-item.rs
+++ b/tests/ui/suggestions/missing-trait-item.rs
@@ -1,4 +1,5 @@
 // run-rustfix
+#![allow(dead_code)]
 
 trait T {
     unsafe fn foo(a: &usize, b: &usize) -> usize;
diff --git a/tests/ui/suggestions/missing-trait-item.stderr b/tests/ui/suggestions/missing-trait-item.stderr
index 4a9d7b472c9..298d0d16438 100644
--- a/tests/ui/suggestions/missing-trait-item.stderr
+++ b/tests/ui/suggestions/missing-trait-item.stderr
@@ -1,5 +1,5 @@
 error[E0046]: not all trait items implemented, missing: `foo`, `bar`
-  --> $DIR/missing-trait-item.rs:10:5
+  --> $DIR/missing-trait-item.rs:11:5
    |
 LL |     unsafe fn foo(a: &usize, b: &usize) -> usize;
    |     --------------------------------------------- `foo` from trait
@@ -10,7 +10,7 @@ LL |     impl T for () {}
    |     ^^^^^^^^^^^^^ missing `foo`, `bar` in implementation
 
 error[E0046]: not all trait items implemented, missing: `foo`, `bar`
-  --> $DIR/missing-trait-item.rs:12:5
+  --> $DIR/missing-trait-item.rs:13:5
    |
 LL |     unsafe fn foo(a: &usize, b: &usize) -> usize;
    |     --------------------------------------------- `foo` from trait
diff --git a/tests/ui/symbol-names/basic.legacy.stderr b/tests/ui/symbol-names/basic.legacy.stderr
index 61d27ec69f4..c1cbefac828 100644
--- a/tests/ui/symbol-names/basic.legacy.stderr
+++ b/tests/ui/symbol-names/basic.legacy.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_ZN5basic4main17h9308686d0228fa1dE)
+error: symbol-name(_ZN5basic4main17h6fc0c8d27b1a289fE)
   --> $DIR/basic.rs:8:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(basic::main::h9308686d0228fa1d)
+error: demangling(basic::main::h6fc0c8d27b1a289f)
   --> $DIR/basic.rs:8:1
    |
 LL | #[rustc_symbol_name]
diff --git a/tests/ui/symbol-names/issue-60925.legacy.stderr b/tests/ui/symbol-names/issue-60925.legacy.stderr
index eb65f3b58ff..7dd68e6e3a8 100644
--- a/tests/ui/symbol-names/issue-60925.legacy.stderr
+++ b/tests/ui/symbol-names/issue-60925.legacy.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h84ab5dafbd2a1508E)
+error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17hab58a402db4ebf3aE)
   --> $DIR/issue-60925.rs:21:9
    |
 LL |         #[rustc_symbol_name]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h84ab5dafbd2a1508)
+error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::hab58a402db4ebf3a)
   --> $DIR/issue-60925.rs:21:9
    |
 LL |         #[rustc_symbol_name]
diff --git a/tests/ui/threads-sendsync/sync-send-atomics.rs b/tests/ui/threads-sendsync/sync-send-atomics.rs
index 0466f4f0e9d..6b260311a50 100644
--- a/tests/ui/threads-sendsync/sync-send-atomics.rs
+++ b/tests/ui/threads-sendsync/sync-send-atomics.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 // pretty-expanded FIXME #23616
 
diff --git a/tests/ui/traits/alias/bounds.rs b/tests/ui/traits/alias/bounds.rs
index b97eb38c5af..7b1920bc8f2 100644
--- a/tests/ui/traits/alias/bounds.rs
+++ b/tests/ui/traits/alias/bounds.rs
@@ -4,7 +4,7 @@
 
 use std::marker::PhantomData;
 
-trait Empty {}
+trait Empty {} //~ WARN trait `Empty` is never used
 trait EmptyAlias = Empty;
 trait CloneDefault = Clone + Default;
 trait SendSyncAlias = Send + Sync;
diff --git a/tests/ui/traits/alias/bounds.stderr b/tests/ui/traits/alias/bounds.stderr
new file mode 100644
index 00000000000..7fb8e918da3
--- /dev/null
+++ b/tests/ui/traits/alias/bounds.stderr
@@ -0,0 +1,10 @@
+warning: trait `Empty` is never used
+  --> $DIR/bounds.rs:7:7
+   |
+LL | trait Empty {}
+   |       ^^^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/traits/alias/syntax.rs b/tests/ui/traits/alias/syntax.rs
index 17557a51aa7..50c77d33c6b 100644
--- a/tests/ui/traits/alias/syntax.rs
+++ b/tests/ui/traits/alias/syntax.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 #![feature(trait_alias)]
 
diff --git a/tests/ui/traits/bound/impl-comparison-duplicates.rs b/tests/ui/traits/bound/impl-comparison-duplicates.rs
index de6c2afa2bb..a59662c2797 100644
--- a/tests/ui/traits/bound/impl-comparison-duplicates.rs
+++ b/tests/ui/traits/bound/impl-comparison-duplicates.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 // Tests that type parameter bounds on an implementation need not match the
 // trait exactly, as long as the implementation doesn't demand *more* bounds
 // than the trait.
diff --git a/tests/ui/traits/bound/recursion.rs b/tests/ui/traits/bound/recursion.rs
index 0023ff654e8..767040dff3f 100644
--- a/tests/ui/traits/bound/recursion.rs
+++ b/tests/ui/traits/bound/recursion.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 // pretty-expanded FIXME #23616
 
 trait I { fn i(&self) -> Self; }
diff --git a/tests/ui/traits/composition-trivial.rs b/tests/ui/traits/composition-trivial.rs
index 90e5dcd68e8..41e6a556074 100644
--- a/tests/ui/traits/composition-trivial.rs
+++ b/tests/ui/traits/composition-trivial.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 // pretty-expanded FIXME #23616
 
 trait Foo {
diff --git a/tests/ui/traits/cycle-generic-bound.rs b/tests/ui/traits/cycle-generic-bound.rs
index 9241f3789d7..77685c26da2 100644
--- a/tests/ui/traits/cycle-generic-bound.rs
+++ b/tests/ui/traits/cycle-generic-bound.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 // Regression test for #15477. This test just needs to compile.
 
 // pretty-expanded FIXME #23616
diff --git a/tests/ui/traits/default-method/bound-subst4.rs b/tests/ui/traits/default-method/bound-subst4.rs
index ef133064582..6bc4cf0ef80 100644
--- a/tests/ui/traits/default-method/bound-subst4.rs
+++ b/tests/ui/traits/default-method/bound-subst4.rs
@@ -4,7 +4,7 @@
 
 trait A<T> {
     fn g(&self, x: usize) -> usize { x }
-    fn h(&self, x: T) { }
+    fn h(&self, x: T) { } //~ WARN method `h` is never used
 }
 
 impl<T> A<T> for isize { }
diff --git a/tests/ui/traits/default-method/bound-subst4.stderr b/tests/ui/traits/default-method/bound-subst4.stderr
new file mode 100644
index 00000000000..548c46f1233
--- /dev/null
+++ b/tests/ui/traits/default-method/bound-subst4.stderr
@@ -0,0 +1,13 @@
+warning: method `h` is never used
+  --> $DIR/bound-subst4.rs:7:8
+   |
+LL | trait A<T> {
+   |       - method in this trait
+LL |     fn g(&self, x: usize) -> usize { x }
+LL |     fn h(&self, x: T) { }
+   |        ^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/traits/default-method/mut.rs b/tests/ui/traits/default-method/mut.rs
index 5f8e983b09c..3294b96561f 100644
--- a/tests/ui/traits/default-method/mut.rs
+++ b/tests/ui/traits/default-method/mut.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 #![allow(unused_assignments)]
 // pretty-expanded FIXME #23616
 
diff --git a/tests/ui/traits/impl-inherent-prefer-over-trait.rs b/tests/ui/traits/impl-inherent-prefer-over-trait.rs
index 82760788897..f03e730d091 100644
--- a/tests/ui/traits/impl-inherent-prefer-over-trait.rs
+++ b/tests/ui/traits/impl-inherent-prefer-over-trait.rs
@@ -3,7 +3,7 @@
 struct Foo;
 
 trait Trait {
-    fn bar(&self);
+    fn bar(&self); //~ WARN method `bar` is never used
 }
 
 // Inherent impls should be preferred over trait ones.
diff --git a/tests/ui/traits/impl-inherent-prefer-over-trait.stderr b/tests/ui/traits/impl-inherent-prefer-over-trait.stderr
new file mode 100644
index 00000000000..f0bb21402d8
--- /dev/null
+++ b/tests/ui/traits/impl-inherent-prefer-over-trait.stderr
@@ -0,0 +1,12 @@
+warning: method `bar` is never used
+  --> $DIR/impl-inherent-prefer-over-trait.rs:6:8
+   |
+LL | trait Trait {
+   |       ----- method in this trait
+LL |     fn bar(&self);
+   |        ^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/traits/impl-object-overlap-issue-23853.rs b/tests/ui/traits/impl-object-overlap-issue-23853.rs
index e490967b690..c0d3af11443 100644
--- a/tests/ui/traits/impl-object-overlap-issue-23853.rs
+++ b/tests/ui/traits/impl-object-overlap-issue-23853.rs
@@ -5,7 +5,7 @@
 // including `Bar`, but the object type `Bar` also implicitly supplies
 // this context.
 
-trait Foo { fn dummy(&self) { } }
+trait Foo { fn dummy(&self) { } } //~ WARN method `dummy` is never used
 
 trait Bar: Foo { }
 
diff --git a/tests/ui/traits/impl-object-overlap-issue-23853.stderr b/tests/ui/traits/impl-object-overlap-issue-23853.stderr
new file mode 100644
index 00000000000..9fa7a36816e
--- /dev/null
+++ b/tests/ui/traits/impl-object-overlap-issue-23853.stderr
@@ -0,0 +1,12 @@
+warning: method `dummy` is never used
+  --> $DIR/impl-object-overlap-issue-23853.rs:8:16
+   |
+LL | trait Foo { fn dummy(&self) { } }
+   |       ---      ^^^^^
+   |       |
+   |       method in this trait
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/traits/impl.rs b/tests/ui/traits/impl.rs
index f512d91ebeb..7bec1b6c9ff 100644
--- a/tests/ui/traits/impl.rs
+++ b/tests/ui/traits/impl.rs
@@ -9,7 +9,7 @@ use traitimpl::Bar;
 static mut COUNT: usize = 1;
 
 trait T {
-    fn t(&self) {}
+    fn t(&self) {} //~ WARN method `t` is never used
 }
 
 impl<'a> dyn T+'a {
diff --git a/tests/ui/traits/impl.stderr b/tests/ui/traits/impl.stderr
new file mode 100644
index 00000000000..98b6fb03d83
--- /dev/null
+++ b/tests/ui/traits/impl.stderr
@@ -0,0 +1,12 @@
+warning: method `t` is never used
+  --> $DIR/impl.rs:12:8
+   |
+LL | trait T {
+   |       - method in this trait
+LL |     fn t(&self) {}
+   |        ^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/traits/issue-38033.rs b/tests/ui/traits/issue-38033.rs
index 16b867ec88f..4d76df1e8d5 100644
--- a/tests/ui/traits/issue-38033.rs
+++ b/tests/ui/traits/issue-38033.rs
@@ -19,7 +19,7 @@ trait IntoFuture {
     type Item;
     type Error;
 
-    fn into_future(self) -> Self::Future;
+    fn into_future(self) -> Self::Future; //~ WARN method `into_future` is never used
 }
 
 impl<F: Future> IntoFuture for F {
diff --git a/tests/ui/traits/issue-38033.stderr b/tests/ui/traits/issue-38033.stderr
new file mode 100644
index 00000000000..05385e8cf4d
--- /dev/null
+++ b/tests/ui/traits/issue-38033.stderr
@@ -0,0 +1,13 @@
+warning: method `into_future` is never used
+  --> $DIR/issue-38033.rs:22:8
+   |
+LL | trait IntoFuture {
+   |       ---------- method in this trait
+...
+LL |     fn into_future(self) -> Self::Future;
+   |        ^^^^^^^^^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/traits/issue-56488.rs b/tests/ui/traits/issue-56488.rs
index e2f3996927b..8b68f314c04 100644
--- a/tests/ui/traits/issue-56488.rs
+++ b/tests/ui/traits/issue-56488.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 #![feature(trait_alias)]
 
diff --git a/tests/ui/traits/issue-59029-2.rs b/tests/ui/traits/issue-59029-2.rs
index 2bdb128d8c4..fca9f1f13c9 100644
--- a/tests/ui/traits/issue-59029-2.rs
+++ b/tests/ui/traits/issue-59029-2.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 #![feature(trait_alias)]
 
 trait Svc<Req> { type Res; }
diff --git a/tests/ui/traits/issue-6128.rs b/tests/ui/traits/issue-6128.rs
index 07d92f8f8a0..f5fa0de809a 100644
--- a/tests/ui/traits/issue-6128.rs
+++ b/tests/ui/traits/issue-6128.rs
@@ -3,7 +3,7 @@
 use std::collections::HashMap;
 
 trait Graph<Node, Edge> {
-    fn f(&self, _: Edge);
+    fn f(&self, _: Edge); //~ WARN methods `f` and `g` are never used
     fn g(&self, _: Node);
 }
 
diff --git a/tests/ui/traits/issue-6128.stderr b/tests/ui/traits/issue-6128.stderr
new file mode 100644
index 00000000000..c9518ea41ea
--- /dev/null
+++ b/tests/ui/traits/issue-6128.stderr
@@ -0,0 +1,14 @@
+warning: methods `f` and `g` are never used
+  --> $DIR/issue-6128.rs:6:8
+   |
+LL | trait Graph<Node, Edge> {
+   |       ----- methods in this trait
+LL |     fn f(&self, _: Edge);
+   |        ^
+LL |     fn g(&self, _: Node);
+   |        ^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/traits/method-on-unbounded-type-param.rs b/tests/ui/traits/method-on-unbounded-type-param.rs
new file mode 100644
index 00000000000..8505eb41e98
--- /dev/null
+++ b/tests/ui/traits/method-on-unbounded-type-param.rs
@@ -0,0 +1,15 @@
+fn f<T>(a: T, b: T) -> std::cmp::Ordering {
+    a.cmp(&b) //~ ERROR E0599
+}
+fn g<T>(a: T, b: T) -> std::cmp::Ordering {
+    (&a).cmp(&b) //~ ERROR E0599
+}
+fn h<T>(a: &T, b: T) -> std::cmp::Ordering {
+    a.cmp(&b) //~ ERROR E0599
+}
+trait T {}
+impl<X: std::cmp::Ord> T for X {}
+fn main() {
+    let x: Box<dyn T> = Box::new(0);
+    x.cmp(&x); //~ ERROR E0599
+}
diff --git a/tests/ui/traits/method-on-unbounded-type-param.stderr b/tests/ui/traits/method-on-unbounded-type-param.stderr
new file mode 100644
index 00000000000..0d8bd8ee964
--- /dev/null
+++ b/tests/ui/traits/method-on-unbounded-type-param.stderr
@@ -0,0 +1,84 @@
+error[E0599]: no method named `cmp` found for type parameter `T` in the current scope
+  --> $DIR/method-on-unbounded-type-param.rs:2:7
+   |
+LL | fn f<T>(a: T, b: T) -> std::cmp::Ordering {
+   |      - method `cmp` not found for this type parameter
+LL |     a.cmp(&b)
+   |       ^^^ method cannot be called on `T` due to unsatisfied trait bounds
+   |
+   = help: items from traits can only be used if the type parameter is bounded by the trait
+help: the following traits define an item `cmp`, perhaps you need to restrict type parameter `T` with one of them:
+   |
+LL | fn f<T: Ord>(a: T, b: T) -> std::cmp::Ordering {
+   |       +++++
+LL | fn f<T: Iterator>(a: T, b: T) -> std::cmp::Ordering {
+   |       ++++++++++
+
+error[E0599]: the method `cmp` exists for reference `&T`, but its trait bounds were not satisfied
+  --> $DIR/method-on-unbounded-type-param.rs:5:10
+   |
+LL |     (&a).cmp(&b)
+   |          ^^^ method cannot be called on `&T` due to unsatisfied trait bounds
+   |
+   = note: the following trait bounds were not satisfied:
+           `T: Ord`
+           which is required by `&T: Ord`
+           `&T: Iterator`
+           which is required by `&mut &T: Iterator`
+           `T: Iterator`
+           which is required by `&mut T: Iterator`
+   = help: items from traits can only be used if the type parameter is bounded by the trait
+help: the following traits define an item `cmp`, perhaps you need to restrict type parameter `T` with one of them:
+   |
+LL | fn g<T: Ord>(a: T, b: T) -> std::cmp::Ordering {
+   |       +++++
+LL | fn g<T: Iterator>(a: T, b: T) -> std::cmp::Ordering {
+   |       ++++++++++
+
+error[E0599]: the method `cmp` exists for reference `&T`, but its trait bounds were not satisfied
+  --> $DIR/method-on-unbounded-type-param.rs:8:7
+   |
+LL |     a.cmp(&b)
+   |       ^^^ method cannot be called on `&T` due to unsatisfied trait bounds
+   |
+   = note: the following trait bounds were not satisfied:
+           `T: Ord`
+           which is required by `&T: Ord`
+           `&T: Iterator`
+           which is required by `&mut &T: Iterator`
+           `T: Iterator`
+           which is required by `&mut T: Iterator`
+   = help: items from traits can only be used if the type parameter is bounded by the trait
+help: the following traits define an item `cmp`, perhaps you need to restrict type parameter `T` with one of them:
+   |
+LL | fn h<T: Ord>(a: &T, b: T) -> std::cmp::Ordering {
+   |       +++++
+LL | fn h<T: Iterator>(a: &T, b: T) -> std::cmp::Ordering {
+   |       ++++++++++
+
+error[E0599]: the method `cmp` exists for struct `Box<dyn T>`, but its trait bounds were not satisfied
+  --> $DIR/method-on-unbounded-type-param.rs:14:7
+   |
+LL | trait T {}
+   | ------- doesn't satisfy `dyn T: Iterator` or `dyn T: Ord`
+...
+LL |     x.cmp(&x);
+   |       ^^^ method cannot be called on `Box<dyn T>` due to unsatisfied trait bounds
+   |
+   = note: the following trait bounds were not satisfied:
+           `dyn T: Iterator`
+           which is required by `Box<dyn T>: Iterator`
+           `dyn T: Ord`
+           which is required by `Box<dyn T>: Ord`
+           `Box<dyn T>: Iterator`
+           which is required by `&mut Box<dyn T>: Iterator`
+           `dyn T: Iterator`
+           which is required by `&mut dyn T: Iterator`
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following traits define an item `cmp`, perhaps you need to implement one of them:
+           candidate #1: `Ord`
+           candidate #2: `Iterator`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/traits/multidispatch-conditional-impl-not-considered.rs b/tests/ui/traits/multidispatch-conditional-impl-not-considered.rs
index f845e198aa5..e9ae8ab012a 100644
--- a/tests/ui/traits/multidispatch-conditional-impl-not-considered.rs
+++ b/tests/ui/traits/multidispatch-conditional-impl-not-considered.rs
@@ -6,7 +6,7 @@
 
 use std::cell::RefCell;
 
-trait Foo {
+trait Foo { //~ WARN trait `Foo` is never used
     fn foo(&self) {}
 }
 
diff --git a/tests/ui/traits/multidispatch-conditional-impl-not-considered.stderr b/tests/ui/traits/multidispatch-conditional-impl-not-considered.stderr
new file mode 100644
index 00000000000..25313a477f7
--- /dev/null
+++ b/tests/ui/traits/multidispatch-conditional-impl-not-considered.stderr
@@ -0,0 +1,10 @@
+warning: trait `Foo` is never used
+  --> $DIR/multidispatch-conditional-impl-not-considered.rs:9:7
+   |
+LL | trait Foo {
+   |       ^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/traits/multidispatch-infer-convert-target.rs b/tests/ui/traits/multidispatch-infer-convert-target.rs
index 626e1ae71bc..a3653dea2cb 100644
--- a/tests/ui/traits/multidispatch-infer-convert-target.rs
+++ b/tests/ui/traits/multidispatch-infer-convert-target.rs
@@ -5,7 +5,7 @@
 use std::mem;
 
 trait Convert<Target> {
-    fn convert(&self) -> Target;
+    fn convert(&self) -> Target; //~ WARN method `convert` is never used
 }
 
 impl Convert<u32> for i16 {
diff --git a/tests/ui/traits/multidispatch-infer-convert-target.stderr b/tests/ui/traits/multidispatch-infer-convert-target.stderr
new file mode 100644
index 00000000000..c8c1b642719
--- /dev/null
+++ b/tests/ui/traits/multidispatch-infer-convert-target.stderr
@@ -0,0 +1,12 @@
+warning: method `convert` is never used
+  --> $DIR/multidispatch-infer-convert-target.rs:8:8
+   |
+LL | trait Convert<Target> {
+   |       ------- method in this trait
+LL |     fn convert(&self) -> Target;
+   |        ^^^^^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/traits/negative-impls/negative-specializes-negative.rs b/tests/ui/traits/negative-impls/negative-specializes-negative.rs
index 35297ab124e..01829e41301 100644
--- a/tests/ui/traits/negative-impls/negative-specializes-negative.rs
+++ b/tests/ui/traits/negative-impls/negative-specializes-negative.rs
@@ -3,7 +3,7 @@
 
 // Test a negative impl that "specializes" another negative impl.
 //
-// run-pass
+// check-pass
 
 trait MyTrait {}
 
diff --git a/tests/ui/traits/next-solver/normalize-region-obligations.rs b/tests/ui/traits/next-solver/normalize-region-obligations.rs
index 13c86b630f6..d189e4893a3 100644
--- a/tests/ui/traits/next-solver/normalize-region-obligations.rs
+++ b/tests/ui/traits/next-solver/normalize-region-obligations.rs
@@ -1,4 +1,4 @@
-// revisions: normalize_param_env normalize_obligation
+// revisions: normalize_param_env normalize_obligation hrtb
 // check-pass
 // compile-flags: -Znext-solver
 
@@ -7,16 +7,23 @@ trait Foo {
     type Gat<'a> where <Self as Mirror>::Assoc: 'a;
     #[cfg(normalize_obligation)]
     type Gat<'a> where Self: 'a;
+    #[cfg(hrtb)]
+    type Gat<'b> where for<'a> <Self as MirrorRegion<'a>>::Assoc: 'b;
 }
 
 trait Mirror { type Assoc: ?Sized; }
 impl<T: ?Sized> Mirror for T { type Assoc = T; }
 
+trait MirrorRegion<'a> { type Assoc: ?Sized; }
+impl<'a, T> MirrorRegion<'a> for T { type Assoc = T; }
+
 impl<T> Foo for T {
     #[cfg(normalize_param_env)]
     type Gat<'a> = i32 where T: 'a;
     #[cfg(normalize_obligation)]
     type Gat<'a> = i32 where <T as Mirror>::Assoc: 'a;
+    #[cfg(hrtb)]
+    type Gat<'b> = i32 where Self: 'b;
 }
 
 fn main() {}
diff --git a/tests/ui/traits/next-solver/normalize-type-outlives-in-param-env.rs b/tests/ui/traits/next-solver/normalize-type-outlives-in-param-env.rs
new file mode 100644
index 00000000000..7477c56cd54
--- /dev/null
+++ b/tests/ui/traits/next-solver/normalize-type-outlives-in-param-env.rs
@@ -0,0 +1,18 @@
+// check-pass
+// compile-flags: -Znext-solver
+
+trait Mirror {
+    type Assoc;
+}
+
+impl<T> Mirror for T {
+    type Assoc = T;
+}
+
+fn is_static<T: 'static>() {}
+
+fn test<T>() where <T as Mirror>::Assoc: 'static {
+    is_static::<T>();
+}
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/normalize-type-outlives.rs b/tests/ui/traits/next-solver/normalize-type-outlives.rs
new file mode 100644
index 00000000000..f50eb6326e2
--- /dev/null
+++ b/tests/ui/traits/next-solver/normalize-type-outlives.rs
@@ -0,0 +1,13 @@
+// check-pass
+
+trait Tr<'a> {
+    type Assoc;
+}
+
+fn outlives<'o, T: 'o>() {}
+
+fn foo<'a, 'b, T: Tr<'a, Assoc = ()>>() {
+    outlives::<'b, T::Assoc>();
+}
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/specialization-transmute.rs b/tests/ui/traits/next-solver/specialization-transmute.rs
index 6f93a1d3f40..d96936f60f7 100644
--- a/tests/ui/traits/next-solver/specialization-transmute.rs
+++ b/tests/ui/traits/next-solver/specialization-transmute.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Znext-solver
-//~^ ERROR cannot normalize `<T as Default>::Id`
+//~^ ERROR cannot normalize `<T as Default>::Id: '_`
 
 #![feature(specialization)]
 //~^ WARN the feature `specialization` is incomplete
diff --git a/tests/ui/traits/next-solver/specialization-transmute.stderr b/tests/ui/traits/next-solver/specialization-transmute.stderr
index 946a7cbaa80..ea1ae387f56 100644
--- a/tests/ui/traits/next-solver/specialization-transmute.stderr
+++ b/tests/ui/traits/next-solver/specialization-transmute.stderr
@@ -8,7 +8,7 @@ LL | #![feature(specialization)]
    = help: consider using `min_specialization` instead, which is more stable and complete
    = note: `#[warn(incomplete_features)]` on by default
 
-error: cannot normalize `<T as Default>::Id`
+error: cannot normalize `<T as Default>::Id: '_`
 
 error[E0284]: type annotations needed: cannot satisfy `<T as Default>::Id == _`
   --> $DIR/specialization-transmute.rs:16:23
diff --git a/tests/ui/traits/trait-upcasting/lifetime.rs b/tests/ui/traits/trait-upcasting/lifetime.rs
index 9825158c2dd..6486ec3891c 100644
--- a/tests/ui/traits/trait-upcasting/lifetime.rs
+++ b/tests/ui/traits/trait-upcasting/lifetime.rs
@@ -7,7 +7,7 @@ trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
         10
     }
 
-    fn z(&self) -> i32 {
+    fn z(&self) -> i32 { //~ WARN methods `z` and `y` are never used
         11
     }
 
@@ -21,7 +21,7 @@ trait Bar: Foo {
         20
     }
 
-    fn w(&self) -> i32 {
+    fn w(&self) -> i32 { //~ WARN method `w` is never used
         21
     }
 }
diff --git a/tests/ui/traits/trait-upcasting/lifetime.stderr b/tests/ui/traits/trait-upcasting/lifetime.stderr
new file mode 100644
index 00000000000..ca8f9cf63f3
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/lifetime.stderr
@@ -0,0 +1,25 @@
+warning: methods `z` and `y` are never used
+  --> $DIR/lifetime.rs:10:8
+   |
+LL | trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
+   |       --- methods in this trait
+...
+LL |     fn z(&self) -> i32 {
+   |        ^
+...
+LL |     fn y(&self) -> i32 {
+   |        ^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: method `w` is never used
+  --> $DIR/lifetime.rs:24:8
+   |
+LL | trait Bar: Foo {
+   |       --- method in this trait
+...
+LL |     fn w(&self) -> i32 {
+   |        ^
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/traits/trait-upcasting/replace-vptr.rs b/tests/ui/traits/trait-upcasting/replace-vptr.rs
index 9ccfc9306ac..5ef65786bb7 100644
--- a/tests/ui/traits/trait-upcasting/replace-vptr.rs
+++ b/tests/ui/traits/trait-upcasting/replace-vptr.rs
@@ -3,7 +3,7 @@
 #![feature(trait_upcasting)]
 
 trait A {
-    fn foo_a(&self);
+    fn foo_a(&self); //~ WARN method `foo_a` is never used
 }
 
 trait B {
@@ -11,7 +11,7 @@ trait B {
 }
 
 trait C: A + B {
-    fn foo_c(&self);
+    fn foo_c(&self); //~ WARN method `foo_c` is never used
 }
 
 struct S(i32);
diff --git a/tests/ui/traits/trait-upcasting/replace-vptr.stderr b/tests/ui/traits/trait-upcasting/replace-vptr.stderr
new file mode 100644
index 00000000000..823094761b3
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/replace-vptr.stderr
@@ -0,0 +1,20 @@
+warning: method `foo_a` is never used
+  --> $DIR/replace-vptr.rs:6:8
+   |
+LL | trait A {
+   |       - method in this trait
+LL |     fn foo_a(&self);
+   |        ^^^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: method `foo_c` is never used
+  --> $DIR/replace-vptr.rs:14:8
+   |
+LL | trait C: A + B {
+   |       - method in this trait
+LL |     fn foo_c(&self);
+   |        ^^^^^
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/traits/use-before-def.rs b/tests/ui/traits/use-before-def.rs
index 1ee2b941909..e52dc53fbab 100644
--- a/tests/ui/traits/use-before-def.rs
+++ b/tests/ui/traits/use-before-def.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 #![allow(non_camel_case_types)]
 
 // Issue #1761
diff --git a/tests/ui/traits/wf-object/reverse-order.rs b/tests/ui/traits/wf-object/reverse-order.rs
index 74b2ef48533..e90c8763d65 100644
--- a/tests/ui/traits/wf-object/reverse-order.rs
+++ b/tests/ui/traits/wf-object/reverse-order.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 // Ensure that `dyn $($AutoTrait)+ ObjSafe` is well-formed.
 
diff --git a/tests/ui/trivial_casts-rpass.rs b/tests/ui/trivial_casts-rpass.rs
index 8e49468bf0c..4653a8df802 100644
--- a/tests/ui/trivial_casts-rpass.rs
+++ b/tests/ui/trivial_casts-rpass.rs
@@ -4,7 +4,7 @@
 #![allow(trivial_casts, trivial_numeric_casts)]
 
 trait Foo {
-    fn foo(&self) {}
+    fn foo(&self) {} //~ WARN method `foo` is never used
 }
 
 pub struct Bar;
diff --git a/tests/ui/trivial_casts-rpass.stderr b/tests/ui/trivial_casts-rpass.stderr
new file mode 100644
index 00000000000..74698b61ab4
--- /dev/null
+++ b/tests/ui/trivial_casts-rpass.stderr
@@ -0,0 +1,12 @@
+warning: method `foo` is never used
+  --> $DIR/trivial_casts-rpass.rs:7:8
+   |
+LL | trait Foo {
+   |       --- method in this trait
+LL |     fn foo(&self) {}
+   |        ^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/type-alias-impl-trait/issue-58887.rs b/tests/ui/type-alias-impl-trait/issue-58887.rs
index 9675867656a..68d85ed6b0f 100644
--- a/tests/ui/type-alias-impl-trait/issue-58887.rs
+++ b/tests/ui/type-alias-impl-trait/issue-58887.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 
 #![feature(impl_trait_in_assoc_type)]
 
diff --git a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr
index d92bafce142..fd76526644b 100644
--- a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr
+++ b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr
@@ -1,4 +1,4 @@
-note: no errors encountered even though `span_delayed_bug` issued
+note: no errors encountered even though delayed bugs were created
 
 note: those delayed bugs will now be shown as internal compiler errors
 
diff --git a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.fixed b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.fixed
index 5be6ff8e7e1..700e4f25423 100644
--- a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.fixed
+++ b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.fixed
@@ -1,4 +1,5 @@
 // run-rustfix
+#![allow(dead_code)]
 
 trait WithType<T> {}
 trait WithRegion<'a> { }
diff --git a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.rs b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.rs
index d7072aa1181..66ba9b24dac 100644
--- a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.rs
+++ b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.rs
@@ -1,4 +1,5 @@
 // run-rustfix
+#![allow(dead_code)]
 
 trait WithType<T> {}
 trait WithRegion<'a> { }
diff --git a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.stderr b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.stderr
index 54e62f34fba..f012120e550 100644
--- a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.stderr
+++ b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2015.stderr
@@ -1,5 +1,5 @@
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/where-clause-inherent-impl-ampersand-rust2015.rs:13:17
+  --> $DIR/where-clause-inherent-impl-ampersand-rust2015.rs:14:17
    |
 LL |     T: WithType<&u32>
    |                 ^ explicit lifetime name needed here
diff --git a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.fixed b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.fixed
index 0f1be586589..56682db3b0b 100644
--- a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.fixed
+++ b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.fixed
@@ -1,5 +1,6 @@
 // edition:2018
 // run-rustfix
+#![allow(dead_code)]
 
 trait WithType<T> {}
 trait WithRegion<'a> { }
diff --git a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.rs b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.rs
index 59f7e472e2d..5302b2f1576 100644
--- a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.rs
+++ b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.rs
@@ -1,5 +1,6 @@
 // edition:2018
 // run-rustfix
+#![allow(dead_code)]
 
 trait WithType<T> {}
 trait WithRegion<'a> { }
diff --git a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.stderr b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.stderr
index 36f3e9ef145..7d675dd41e9 100644
--- a/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.stderr
+++ b/tests/ui/underscore-lifetime/where-clause-inherent-impl-ampersand-rust2018.stderr
@@ -1,5 +1,5 @@
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/where-clause-inherent-impl-ampersand-rust2018.rs:14:17
+  --> $DIR/where-clause-inherent-impl-ampersand-rust2018.rs:15:17
    |
 LL |     T: WithType<&u32>
    |                 ^ explicit lifetime name needed here
diff --git a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.fixed b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.fixed
index 55c7470960e..f3adc7e7fad 100644
--- a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.fixed
+++ b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.fixed
@@ -1,4 +1,5 @@
 // run-rustfix
+#![allow(dead_code)]
 
 trait WithType<T> {}
 trait WithRegion<'a> { }
diff --git a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.rs b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.rs
index 42a35b02161..1e084e9ad41 100644
--- a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.rs
+++ b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.rs
@@ -1,4 +1,5 @@
 // run-rustfix
+#![allow(dead_code)]
 
 trait WithType<T> {}
 trait WithRegion<'a> { }
diff --git a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.stderr b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.stderr
index 92b7a9c2af8..8aa0e52c688 100644
--- a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.stderr
+++ b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2015.stderr
@@ -1,5 +1,5 @@
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/where-clause-trait-impl-region-2015.rs:10:17
+  --> $DIR/where-clause-trait-impl-region-2015.rs:11:17
    |
 LL |     T: WithType<&u32>
    |                 ^ explicit lifetime name needed here
diff --git a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.fixed b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.fixed
index 09b96fe5ea4..dd8074abed7 100644
--- a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.fixed
+++ b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.fixed
@@ -1,6 +1,8 @@
 // run-rustfix
 // edition:2018
 
+#![allow(dead_code)]
+
 trait WithType<T> {}
 trait WithRegion<'a> { }
 
diff --git a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.rs b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.rs
index 445f38cbee1..4fc9c71b179 100644
--- a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.rs
+++ b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.rs
@@ -1,6 +1,8 @@
 // run-rustfix
 // edition:2018
 
+#![allow(dead_code)]
+
 trait WithType<T> {}
 trait WithRegion<'a> { }
 
diff --git a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.stderr b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.stderr
index 63d8b99ed18..22940d0b0b1 100644
--- a/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.stderr
+++ b/tests/ui/underscore-lifetime/where-clause-trait-impl-region-2018.stderr
@@ -1,5 +1,5 @@
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/where-clause-trait-impl-region-2018.rs:11:17
+  --> $DIR/where-clause-trait-impl-region-2018.rs:13:17
    |
 LL |     T: WithType<&u32>
    |                 ^ explicit lifetime name needed here
diff --git a/tests/ui/where-clauses/issue-50825-1.rs b/tests/ui/where-clauses/issue-50825-1.rs
index ee4316029a8..2ee34ad714e 100644
--- a/tests/ui/where-clauses/issue-50825-1.rs
+++ b/tests/ui/where-clauses/issue-50825-1.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 // regression test for issue #50825
 // Make sure that the `impl` bound (): X<T = ()> is preferred over
 // the (): X bound in the where clause.
diff --git a/tests/ui/where-clauses/where-clause-bounds-inconsistency.rs b/tests/ui/where-clauses/where-clause-bounds-inconsistency.rs
index ea60fa70876..65fd2f3096c 100644
--- a/tests/ui/where-clauses/where-clause-bounds-inconsistency.rs
+++ b/tests/ui/where-clauses/where-clause-bounds-inconsistency.rs
@@ -1,4 +1,4 @@
-// run-pass
+// check-pass
 // pretty-expanded FIXME #23616
 
 trait Bound {
diff --git a/tests/ui/where-clauses/where-clause-early-bound-lifetimes.rs b/tests/ui/where-clauses/where-clause-early-bound-lifetimes.rs
index 6fc570b9b5b..a7ce0590fcd 100644
--- a/tests/ui/where-clauses/where-clause-early-bound-lifetimes.rs
+++ b/tests/ui/where-clauses/where-clause-early-bound-lifetimes.rs
@@ -3,7 +3,7 @@
 
 // pretty-expanded FIXME #23616
 
-trait TheTrait { fn dummy(&self) { } }
+trait TheTrait { fn dummy(&self) { } } //~ WARN method `dummy` is never used
 
 impl TheTrait for &'static isize { }
 
diff --git a/tests/ui/where-clauses/where-clause-early-bound-lifetimes.stderr b/tests/ui/where-clauses/where-clause-early-bound-lifetimes.stderr
new file mode 100644
index 00000000000..a9fe11ea6b3
--- /dev/null
+++ b/tests/ui/where-clauses/where-clause-early-bound-lifetimes.stderr
@@ -0,0 +1,12 @@
+warning: method `dummy` is never used
+  --> $DIR/where-clause-early-bound-lifetimes.rs:6:21
+   |
+LL | trait TheTrait { fn dummy(&self) { } }
+   |       --------      ^^^^^
+   |       |
+   |       method in this trait
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/where-clauses/where-clause-method-substituion-rpass.rs b/tests/ui/where-clauses/where-clause-method-substituion-rpass.rs
index daa3c8dd8e3..8f9c6fbff3d 100644
--- a/tests/ui/where-clauses/where-clause-method-substituion-rpass.rs
+++ b/tests/ui/where-clauses/where-clause-method-substituion-rpass.rs
@@ -2,7 +2,7 @@
 #![allow(unused_variables)]
 // pretty-expanded FIXME #23616
 
-trait Foo<T> { fn dummy(&self, arg: T) { } }
+trait Foo<T> { fn dummy(&self, arg: T) { } } //~ WARN method `dummy` is never used
 
 trait Bar<A> {
     fn method<B>(&self) where A: Foo<B>;
diff --git a/tests/ui/where-clauses/where-clause-method-substituion-rpass.stderr b/tests/ui/where-clauses/where-clause-method-substituion-rpass.stderr
new file mode 100644
index 00000000000..0d09cb9de3f
--- /dev/null
+++ b/tests/ui/where-clauses/where-clause-method-substituion-rpass.stderr
@@ -0,0 +1,12 @@
+warning: method `dummy` is never used
+  --> $DIR/where-clause-method-substituion-rpass.rs:5:19
+   |
+LL | trait Foo<T> { fn dummy(&self, arg: T) { } }
+   |       ---         ^^^^^
+   |       |
+   |       method in this trait
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed
index 2f47c0d91fa..4e1aa59aac0 100644
--- a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed
+++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed
@@ -1,6 +1,8 @@
 // check-pass
 // run-rustfix
 
+#![allow(dead_code)]
+
 trait Trait {
     // Fine.
     type Assoc where u32: Copy;
diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.rs b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.rs
index b20aa9398b5..05b2f8c82a4 100644
--- a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.rs
+++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.rs
@@ -1,6 +1,8 @@
 // check-pass
 // run-rustfix
 
+#![allow(dead_code)]
+
 trait Trait {
     // Fine.
     type Assoc where u32: Copy;
diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr
index b4de051845f..6ff9d2dd73b 100644
--- a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr
+++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr
@@ -1,5 +1,5 @@
 warning: where clause not allowed here
-  --> $DIR/where-clause-placement-assoc-type-in-impl.rs:13:16
+  --> $DIR/where-clause-placement-assoc-type-in-impl.rs:15:16
    |
 LL |     type Assoc where u32: Copy = ();
    |                ^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ LL +     type Assoc  = () where u32: Copy;
    |
 
 warning: where clause not allowed here
-  --> $DIR/where-clause-placement-assoc-type-in-impl.rs:16:17
+  --> $DIR/where-clause-placement-assoc-type-in-impl.rs:18:17
    |
 LL |     type Assoc2 where u32: Copy = () where i32: Copy;
    |                 ^^^^^^^^^^^^^^^
@@ -26,7 +26,7 @@ LL +     type Assoc2  = () where i32: Copy, u32: Copy;
    |
 
 warning: where clause not allowed here
-  --> $DIR/where-clause-placement-assoc-type-in-impl.rs:24:17
+  --> $DIR/where-clause-placement-assoc-type-in-impl.rs:26:17
    |
 LL |     type Assoc2 where u32: Copy, i32: Copy = ();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.fixed b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.fixed
index d171eba50b7..940e2cc8e97 100644
--- a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.fixed
+++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.fixed
@@ -1,6 +1,7 @@
 // check-pass
 // run-rustfix
 
+#![allow(dead_code)]
 #![feature(associated_type_defaults)]
 
 trait Trait {
diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.rs b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.rs
index 59afee65794..7001a9245a5 100644
--- a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.rs
+++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.rs
@@ -1,6 +1,7 @@
 // check-pass
 // run-rustfix
 
+#![allow(dead_code)]
 #![feature(associated_type_defaults)]
 
 trait Trait {
diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.stderr b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.stderr
index a81cb8c8cd6..9e9967ef739 100644
--- a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.stderr
+++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-trait.stderr
@@ -1,5 +1,5 @@
 warning: where clause not allowed here
-  --> $DIR/where-clause-placement-assoc-type-in-trait.rs:8:16
+  --> $DIR/where-clause-placement-assoc-type-in-trait.rs:9:16
    |
 LL |     type Assoc where u32: Copy = ();
    |                ^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ LL +     type Assoc  = () where u32: Copy;
    |
 
 warning: where clause not allowed here
-  --> $DIR/where-clause-placement-assoc-type-in-trait.rs:11:17
+  --> $DIR/where-clause-placement-assoc-type-in-trait.rs:12:17
    |
 LL |     type Assoc2 where u32: Copy = () where i32: Copy;
    |                 ^^^^^^^^^^^^^^^
diff --git a/triagebot.toml b/triagebot.toml
index 68c863bb919..eba8e283815 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -658,7 +658,6 @@ compiler-team = [
 ]
 compiler-team-contributors = [
     "@TaKO8Ki",
-    "@b-naber",
     "@nnethercote",
     "@fmease",
 ]