about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2024-12-09 08:19:26 +0000
committerGitHub <noreply@github.com>2024-12-09 08:19:26 +0000
commitac667ef3032799bd549579e6aebc5b7f7dafa430 (patch)
tree81ea977a43fdb53b757b9e27b848284138d90200
parenta33b4b1ca0c172125ba832144591370cc09e4360 (diff)
parentc498e7f5195379bc949fa57e82c0e0228575f12c (diff)
downloadrust-ac667ef3032799bd549579e6aebc5b7f7dafa430.tar.gz
rust-ac667ef3032799bd549579e6aebc5b7f7dafa430.zip
Merge pull request #4082 from RalfJung/rustup
Rustup
-rw-r--r--Cargo.lock4
-rw-r--r--RELEASES.md8
-rw-r--r--compiler/rustc_ast/src/ast.rs11
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs4
-rw-r--r--compiler/rustc_ast/src/visit.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/pat.rs2
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs1
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs8
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs7
-rw-r--r--compiler/rustc_codegen_cranelift/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs166
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs11
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs56
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/backend.rs10
-rw-r--r--compiler/rustc_const_eval/src/check_consts/ops.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs45
-rw-r--r--compiler/rustc_driver_impl/src/args.rs10
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs73
-rw-r--r--compiler/rustc_driver_impl/src/pretty.rs4
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0751.md2
-rw-r--r--compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs3
-rw-r--r--compiler/rustc_errors/src/emitter.rs9
-rw-r--r--compiler/rustc_errors/src/json.rs20
-rw-r--r--compiler/rustc_errors/src/lib.rs34
-rw-r--r--compiler/rustc_expand/src/expand.rs2
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs8
-rw-r--r--compiler/rustc_incremental/src/persist/fs.rs33
-rw-r--r--compiler/rustc_incremental/src/persist/load.rs22
-rw-r--r--compiler/rustc_interface/src/interface.rs50
-rw-r--r--compiler/rustc_interface/src/passes.rs31
-rw-r--r--compiler/rustc_interface/src/queries.rs51
-rw-r--r--compiler/rustc_lint/messages.ftl13
-rw-r--r--compiler/rustc_lint/src/early.rs2
-rw-r--r--compiler/rustc_lint/src/hidden_unicode_codepoints.rs1
-rw-r--r--compiler/rustc_lint/src/lints.rs45
-rw-r--r--compiler/rustc_lint/src/types.rs372
-rw-r--r--compiler/rustc_lint/src/unused.rs2
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs1
-rw-r--r--compiler/rustc_middle/src/query/mod.rs2
-rw-r--r--compiler/rustc_middle/src/query/on_disk_cache.rs23
-rw-r--r--compiler/rustc_middle/src/query/plumbing.rs2
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs126
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/graphviz.rs183
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/mod.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/results.rs184
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/mod.rs4
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs58
-rw-r--r--compiler/rustc_parse/src/parser/nonterminal.rs2
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs54
-rw-r--r--compiler/rustc_parse/src/parser/path.rs2
-rw-r--r--compiler/rustc_passes/src/input_stats.rs1
-rw-r--r--compiler/rustc_query_impl/src/lib.rs6
-rw-r--r--compiler/rustc_session/src/session.rs15
-rw-r--r--compiler/rustc_smir/src/rustc_internal/mod.rs5
-rw-r--r--compiler/rustc_span/src/lib.rs5
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs134
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs4
-rw-r--r--library/core/src/bool.rs1
-rw-r--r--library/core/src/intrinsics/mod.rs66
-rw-r--r--library/std/src/env.rs7
-rw-r--r--library/std/src/thread/local.rs2
-rw-r--r--src/etc/lldb_commands23
-rw-r--r--src/librustdoc/core.rs14
-rw-r--r--src/librustdoc/doctest.rs22
-rw-r--r--src/librustdoc/lib.rs38
-rw-r--r--src/librustdoc/passes/lint/check_code_block_syntax.rs3
-rw-r--r--src/librustdoc/scrape_examples.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs2
-rw-r--r--src/tools/clippy/src/driver.rs8
-rw-r--r--src/tools/compiletest/src/lib.rs17
-rw-r--r--src/tools/compiletest/src/runtest.rs136
-rw-r--r--src/tools/compiletest/src/runtest/coverage.rs16
-rw-r--r--src/tools/compiletest/src/runtest/ui.rs2
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/bin/miri.rs3
-rw-r--r--src/tools/rustfmt/src/parse/session.rs29
-rw-r--r--src/tools/rustfmt/src/patterns.rs6
-rw-r--r--src/tools/rustfmt/tests/target/guard_patterns.rs12
-rw-r--r--tests/crashes/121363.rs2
-rw-r--r--tests/crashes/128094.rs2
-rw-r--r--tests/crashes/129095.rs2
-rw-r--r--tests/crashes/129109.rs2
-rw-r--r--tests/crashes/130970.rs2
-rw-r--r--tests/crashes/131347.rs2
-rw-r--r--tests/crashes/131451.rs9
-rw-r--r--tests/crashes/131507.rs2
-rw-r--r--tests/incremental/circular-dependencies.rs16
-rw-r--r--tests/run-make/crate-loading-crate-depends-on-itself/foo.stderr2
-rw-r--r--tests/run-make/crate-loading/multiple-dep-versions-1.rs3
-rw-r--r--tests/run-make/crate-loading/multiple-dep-versions-2.rs4
-rw-r--r--tests/run-make/crate-loading/multiple-dep-versions-3.rs2
-rw-r--r--tests/run-make/crate-loading/multiple-dep-versions.rs6
-rw-r--r--tests/run-make/crate-loading/multiple-dep-versions.stderr80
-rw-r--r--tests/run-make/missing-unstable-trait-bound/missing-bound.rs4
-rw-r--r--tests/run-make/missing-unstable-trait-bound/missing-bound.stderr12
-rw-r--r--tests/run-make/missing-unstable-trait-bound/rmake.rs24
-rw-r--r--tests/rustdoc-ui/issues/issue-96287.stderr4
-rw-r--r--tests/rustdoc-ui/synthetic-auto-trait-impls/projections-in-super-trait-bound-unsatisfied.stderr4
-rw-r--r--tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs22
-rw-r--r--tests/ui-fulldeps/compiler-calls.rs7
-rw-r--r--tests/ui-fulldeps/obtain-borrowck.rs3
-rw-r--r--tests/ui-fulldeps/run-compiler-twice.rs9
-rw-r--r--tests/ui/assign-imm-local-twice.rs13
-rw-r--r--tests/ui/assoc-lang-items.rs21
-rw-r--r--tests/ui/assoc-oddities-3.rs13
-rw-r--r--tests/ui/associated-types/associated-types-no-suitable-bound.stderr4
-rw-r--r--tests/ui/associated-types/defaults-suitability.current.stderr4
-rw-r--r--tests/ui/associated-types/defaults-suitability.next.stderr4
-rw-r--r--tests/ui/associated-types/hr-associated-type-bound-param-6.stderr2
-rw-r--r--tests/ui/associated-types/issue-27675-unchecked-bounds.stderr2
-rw-r--r--tests/ui/associated-types/issue-43784-associated-type.stderr2
-rw-r--r--tests/ui/associated-types/issue-59324.stderr8
-rw-r--r--tests/ui/async-await/issue-70818.stderr2
-rw-r--r--tests/ui/async-await/issue-86507.stderr2
-rw-r--r--tests/ui/atomic-from-mut-not-available.rs7
-rw-r--r--tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr2
-rw-r--r--tests/ui/binop/binop-consume-args.stderr40
-rw-r--r--tests/ui/binop/binop-move-semantics.stderr4
-rw-r--r--tests/ui/binop/issue-93927.stderr2
-rw-r--r--tests/ui/borrowck/assign-imm-local-twice.fixed21
-rw-r--r--tests/ui/borrowck/assign-imm-local-twice.rs21
-rw-r--r--tests/ui/borrowck/assign-imm-local-twice.stderr (renamed from tests/ui/assign-imm-local-twice.stderr)4
-rw-r--r--tests/ui/borrowck/clone-on-ref.stderr4
-rw-r--r--tests/ui/borrowck/move-error-suggest-clone-panic-issue-127915.stderr2
-rw-r--r--tests/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr4
-rw-r--r--tests/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr2
-rw-r--r--tests/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr2
-rw-r--r--tests/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr4
-rw-r--r--tests/ui/closures/closure-bounds-subtype.stderr2
-rw-r--r--tests/ui/closures/issue-67123.stderr2
-rw-r--r--tests/ui/codegen/assign-expr-unit-type.rs (renamed from tests/ui/assign-assign.rs)13
-rw-r--r--tests/ui/coherence/fuzzing/best-obligation-ICE.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-61336-2.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-61336.stderr2
-rw-r--r--tests/ui/consts/ct-var-in-collect_all_mismatches.stderr2
-rw-r--r--tests/ui/consts/fn_trait_refs.stderr12
-rw-r--r--tests/ui/consts/unstable-const-fn-in-libcore.stderr4
-rw-r--r--tests/ui/dropck/explicit-drop-bounds.bad1.stderr4
-rw-r--r--tests/ui/dropck/explicit-drop-bounds.bad2.stderr4
-rw-r--r--tests/ui/error-codes/E0229.stderr4
-rw-r--r--tests/ui/errors/trait-bound-error-spans/blame-trait-error.stderr30
-rw-r--r--tests/ui/errors/traits/blame-trait-error-spans-on-exprs.stderr28
-rw-r--r--tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr2
-rw-r--r--tests/ui/extern/extern-C-str-arg-ice-80125.stderr2
-rw-r--r--tests/ui/feature-gates/feature-gate-guard-patterns.rs46
-rw-r--r--tests/ui/feature-gates/feature-gate-guard-patterns.stderr119
-rw-r--r--tests/ui/generic-associated-types/generic-associated-types-where.stderr2
-rw-r--r--tests/ui/generic-associated-types/impl_bounds.stderr4
-rw-r--r--tests/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr2
-rw-r--r--tests/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr2
-rw-r--r--tests/ui/generic-associated-types/issue-68643-broken-mir.stderr2
-rw-r--r--tests/ui/generic-associated-types/issue-68644-codegen-selection.stderr2
-rw-r--r--tests/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr2
-rw-r--r--tests/ui/generic-associated-types/issue-74824.current.stderr2
-rw-r--r--tests/ui/generic-associated-types/issue-74824.next.stderr2
-rw-r--r--tests/ui/generic-associated-types/missing-bounds.stderr2
-rw-r--r--tests/ui/higher-ranked/structually-relate-aliases.stderr2
-rw-r--r--tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr2
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-85455.stderr4
-rw-r--r--tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr10
-rw-r--r--tests/ui/impl-trait/issue-55872-1.stderr4
-rw-r--r--tests/ui/impl-trait/normalize-tait-in-const.stderr4
-rw-r--r--tests/ui/issues/issue-6738.stderr2
-rw-r--r--tests/ui/kindck/kindck-impl-type-params.stderr8
-rw-r--r--tests/ui/lang-items/assoc-lang-items.rs35
-rw-r--r--tests/ui/lang-items/assoc-lang-items.stderr (renamed from tests/ui/assoc-lang-items.stderr)8
-rw-r--r--tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.stderr10
-rw-r--r--tests/ui/lazy-type-alias/unsatisfied-bounds-type-alias-body.stderr2
-rw-r--r--tests/ui/lint/extern-C-fnptr-lints-slices.rs2
-rw-r--r--tests/ui/lint/extern-C-fnptr-lints-slices.stderr7
-rw-r--r--tests/ui/lint/lint-ctypes-73249-2.stderr1
-rw-r--r--tests/ui/lint/lint-ctypes-94223.stderr26
-rw-r--r--tests/ui/lint/lint-ctypes-cstr.rs4
-rw-r--r--tests/ui/lint/lint-ctypes-cstr.stderr11
-rw-r--r--tests/ui/lint/lint-ctypes-fn.rs6
-rw-r--r--tests/ui/lint/lint-ctypes-fn.stderr22
-rw-r--r--tests/ui/lint/lint-ctypes.rs35
-rw-r--r--tests/ui/lint/lint-ctypes.stderr123
-rw-r--r--tests/ui/methods/filter-relevant-fn-bounds.stderr8
-rw-r--r--tests/ui/mir/validate/validate-unsize-cast.stderr2
-rw-r--r--tests/ui/mismatched_types/similar_paths_primitive.rs16
-rw-r--r--tests/ui/mismatched_types/similar_paths_primitive.stderr14
-rw-r--r--tests/ui/missing-trait-bounds/missing-trait-bound-for-op.stderr2
-rw-r--r--tests/ui/moves/issue-34721.stderr2
-rw-r--r--tests/ui/moves/use_of_moved_value_copy_suggestions.fixed6
-rw-r--r--tests/ui/moves/use_of_moved_value_copy_suggestions.rs6
-rw-r--r--tests/ui/moves/use_of_moved_value_copy_suggestions.stderr20
-rw-r--r--tests/ui/parser/assoc/assoc-oddities-3.rs41
-rw-r--r--tests/ui/parser/issues/issue-72373.rs2
-rw-r--r--tests/ui/parser/issues/issue-72373.stderr4
-rw-r--r--tests/ui/parser/misspelled-keywords/ref.stderr4
-rw-r--r--tests/ui/parser/pat-lt-bracket-7.rs2
-rw-r--r--tests/ui/parser/pat-lt-bracket-7.stderr4
-rw-r--r--tests/ui/parser/recover/recover-pat-exprs.rs6
-rw-r--r--tests/ui/parser/recover/recover-pat-exprs.stderr12
-rw-r--r--tests/ui/parser/recover/recover-pat-wildcards.rs4
-rw-r--r--tests/ui/parser/recover/recover-pat-wildcards.stderr8
-rw-r--r--tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr4
-rw-r--r--tests/ui/pattern/rfc-3637-guard-patterns/macro-rules.rs20
-rw-r--r--tests/ui/phantom-auto-trait.stderr4
-rw-r--r--tests/ui/recursion/issue-83150.rs3
-rw-r--r--tests/ui/recursion/issue-83150.stderr8
-rw-r--r--tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr4
-rw-r--r--tests/ui/resolve/issue-55673.stderr2
-rw-r--r--tests/ui/rust-2024/gen-kw.e2015.stderr40
-rw-r--r--tests/ui/rust-2024/gen-kw.e2018.stderr40
-rw-r--r--tests/ui/rust-2024/gen-kw.rs16
-rw-r--r--tests/ui/specialization/default-generic-associated-type-bound.stderr2
-rw-r--r--tests/ui/specialization/defaultimpl/specialization-wfcheck.stderr2
-rw-r--r--tests/ui/specialization/issue-33017.stderr2
-rw-r--r--tests/ui/specialization/min_specialization/issue-79224.stderr8
-rw-r--r--tests/ui/stdlib-unit-tests/atomic-from-mut-not-available.alignment_matches.stderr13
-rw-r--r--tests/ui/stdlib-unit-tests/atomic-from-mut-not-available.alignment_mismatch.stderr (renamed from tests/ui/atomic-from-mut-not-available.stderr)2
-rw-r--r--tests/ui/stdlib-unit-tests/atomic-from-mut-not-available.rs27
-rw-r--r--tests/ui/suggestions/assoc-const-as-fn.stderr2
-rw-r--r--tests/ui/suggestions/bound-suggestions.stderr12
-rw-r--r--tests/ui/suggestions/clone-bounds-121524.rs2
-rw-r--r--tests/ui/suggestions/clone-bounds-121524.stderr2
-rw-r--r--tests/ui/suggestions/clone-on-unconstrained-borrowed-type-param.stderr2
-rw-r--r--tests/ui/suggestions/derive-clone-for-eq.stderr2
-rw-r--r--tests/ui/suggestions/derive-macro-missing-bounds.stderr8
-rw-r--r--tests/ui/suggestions/issue-106443-sugg-clone-for-bound.stderr2
-rw-r--r--tests/ui/suggestions/issue-97677.stderr2
-rw-r--r--tests/ui/suggestions/missing-bound-in-derive-copy-impl-2.stderr8
-rw-r--r--tests/ui/suggestions/missing-bound-in-derive-copy-impl-3.stderr8
-rw-r--r--tests/ui/suggestions/missing-bound-in-derive-copy-impl.stderr16
-rw-r--r--tests/ui/suggestions/missing-bound-in-manual-copy-impl-2.stderr2
-rw-r--r--tests/ui/suggestions/missing-bound-in-manual-copy-impl.stderr2
-rw-r--r--tests/ui/suggestions/restrict-type-argument.stderr12
-rw-r--r--tests/ui/suggestions/trait-impl-bound-suggestions.stderr8
-rw-r--r--tests/ui/trait-bounds/unstable-trait-suggestion.rs19
-rw-r--r--tests/ui/trait-bounds/unstable-trait-suggestion.stderr34
-rw-r--r--tests/ui/traits/alias/wf.stderr2
-rw-r--r--tests/ui/traits/bad-method-typaram-kind.stderr2
-rw-r--r--tests/ui/traits/bound/on-structs-and-enums.stderr6
-rw-r--r--tests/ui/traits/const-traits/call-generic-method-chain.stderr4
-rw-r--r--tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr8
-rw-r--r--tests/ui/traits/const-traits/call-generic-method-fail.stderr4
-rw-r--r--tests/ui/traits/const-traits/call-generic-method-pass.stderr4
-rw-r--r--tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr4
-rw-r--r--tests/ui/traits/const-traits/const-closure-trait-method.stderr4
-rw-r--r--tests/ui/traits/const-traits/const-closures.stderr12
-rw-r--r--tests/ui/traits/const-traits/trait-where-clause.stderr4
-rw-r--r--tests/ui/traits/copy-impl-cannot-normalize.stderr2
-rw-r--r--tests/ui/traits/copy-is-not-modulo-regions.not_static.stderr2
-rw-r--r--tests/ui/traits/inductive-overflow/two-traits.stderr2
-rw-r--r--tests/ui/traits/inheritance/repeated-supertrait-ambig.stderr4
-rw-r--r--tests/ui/traits/issue-21837.stderr2
-rw-r--r--tests/ui/traits/issue-43784-supertrait.stderr2
-rw-r--r--tests/ui/traits/next-solver/diagnostics/projection-trait-ref.stderr2
-rw-r--r--tests/ui/traits/next-solver/dyn-incompatibility.stderr4
-rw-r--r--tests/ui/traits/next-solver/global-cache-and-parallel-frontend.stderr2
-rw-r--r--tests/ui/traits/next-solver/issue-118950-root-region.stderr2
-rw-r--r--tests/ui/tuple/builtin-fail.stderr2
-rw-r--r--tests/ui/type-alias-impl-trait/bounds-are-checked-2.stderr2
-rw-r--r--tests/ui/type-alias-impl-trait/bounds-are-checked3.stderr2
-rw-r--r--tests/ui/type-alias-impl-trait/future.stderr2
-rw-r--r--tests/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr2
-rw-r--r--tests/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr2
-rw-r--r--tests/ui/type-alias-impl-trait/generic_underconstrained.stderr4
-rw-r--r--tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr8
-rw-r--r--tests/ui/type-alias-impl-trait/issue-52843.stderr2
-rw-r--r--tests/ui/type-alias-impl-trait/issue-53092.stderr2
-rw-r--r--tests/ui/type-alias-impl-trait/issue-89686.stderr2
-rw-r--r--tests/ui/type-alias-impl-trait/issue-90400-1.stderr2
-rw-r--r--tests/ui/type-alias-impl-trait/issue-90400-2.stderr2
-rw-r--r--tests/ui/type-alias-impl-trait/not_well_formed.stderr4
-rw-r--r--tests/ui/type-alias-impl-trait/self-referential-3.rs2
-rw-r--r--tests/ui/type-alias-impl-trait/self-referential-3.stderr2
-rw-r--r--tests/ui/type-alias-impl-trait/self-referential-4.rs2
-rw-r--r--tests/ui/type-alias-impl-trait/self-referential-4.stderr6
-rw-r--r--tests/ui/type-alias-impl-trait/self-referential.rs2
-rw-r--r--tests/ui/type-alias-impl-trait/self-referential.stderr6
-rw-r--r--tests/ui/type-alias-impl-trait/underconstrained_generic.stderr2
-rw-r--r--tests/ui/type-alias-impl-trait/wf-check-fn-def.stderr2
-rw-r--r--tests/ui/type-alias-impl-trait/wf_check_closures.stderr2
-rw-r--r--tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.lazy.stderr6
-rw-r--r--tests/ui/type/auxiliary/crate_a1.rs2
-rw-r--r--tests/ui/type/auxiliary/crate_a2.rs2
-rw-r--r--tests/ui/type/type-check-defaults.stderr2
-rw-r--r--tests/ui/type/type-check/missing_trait_impl.stderr8
-rw-r--r--tests/ui/type/type-mismatch-same-crate-name.rs27
-rw-r--r--tests/ui/type/type-mismatch-same-crate-name.stderr45
-rw-r--r--tests/ui/typeck/bad-index-due-to-nested.stderr4
-rw-r--r--tests/ui/typeck/issue-90164.stderr2
-rw-r--r--tests/ui/typeck/typeck-default-trait-impl-send-param.stderr2
-rw-r--r--tests/ui/union/issue-81199.stderr2
-rw-r--r--tests/ui/unop/unop-move-semantics.stderr2
-rw-r--r--tests/ui/wf/issue-96810.stderr2
-rw-r--r--tests/ui/wf/wf-enum-bound.stderr2
-rw-r--r--tests/ui/wf/wf-enum-fields-struct-variant.stderr2
-rw-r--r--tests/ui/wf/wf-enum-fields.stderr2
-rw-r--r--tests/ui/wf/wf-fn-where-clause.stderr2
-rw-r--r--tests/ui/wf/wf-impl-associated-type-trait.stderr2
-rw-r--r--tests/ui/wf/wf-in-fn-arg.stderr2
-rw-r--r--tests/ui/wf/wf-in-fn-ret.stderr2
-rw-r--r--tests/ui/wf/wf-in-fn-type-arg.stderr2
-rw-r--r--tests/ui/wf/wf-in-fn-type-ret.stderr2
-rw-r--r--tests/ui/wf/wf-in-fn-where-clause.stderr2
-rw-r--r--tests/ui/wf/wf-in-obj-type-trait.stderr2
-rw-r--r--tests/ui/wf/wf-inherent-impl-method-where-clause.stderr2
-rw-r--r--tests/ui/wf/wf-inherent-impl-where-clause.stderr2
-rw-r--r--tests/ui/wf/wf-struct-bound.stderr2
-rw-r--r--tests/ui/wf/wf-struct-field.stderr2
-rw-r--r--tests/ui/wf/wf-trait-associated-type-bound.stderr2
-rw-r--r--tests/ui/wf/wf-trait-bound.stderr2
-rw-r--r--tests/ui/wf/wf-trait-superbound.stderr2
-rw-r--r--tests/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr2
-rw-r--r--tests/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr2
-rw-r--r--triagebot.toml12
313 files changed, 2694 insertions, 1526 deletions
diff --git a/Cargo.lock b/Cargo.lock
index e4e080b9457..12970dd1ebf 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2814,9 +2814,9 @@ dependencies = [
 
 [[package]]
 name = "psm"
-version = "0.1.23"
+version = "0.1.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa37f80ca58604976033fae9515a8a2989fc13797d953f7c04fb8fa36a11f205"
+checksum = "200b9ff220857e53e184257720a14553b2f4aa02577d2ed9842d45d4b9654810"
 dependencies = [
  "cc",
 ]
diff --git a/RELEASES.md b/RELEASES.md
index 8702bb02118..99733bade32 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -503,7 +503,7 @@ Compatibility Notes
 * We have renamed `std::panic::PanicInfo` to `std::panic::PanicHookInfo`. The old name will continue to work as an alias, but will result in a deprecation warning starting in Rust 1.82.0.
 
   `core::panic::PanicInfo` will remain unchanged, however, as this is now a *different type*.
- 
+
   The reason is that these types have different roles: `std::panic::PanicHookInfo` is the argument to the [panic hook](https://doc.rust-lang.org/stable/std/panic/fn.set_hook.html) in std context (where panics can have an arbitrary payload), while `core::panic::PanicInfo` is the argument to the [`#[panic_handler]`](https://doc.rust-lang.org/nomicon/panic-handler.html) in no_std context (where panics always carry a formatted *message*). Separating these types allows us to add more useful methods to these types, such as `std::panic::PanicHookInfo::payload_as_str()` and `core::panic::PanicInfo::message()`.
 
 * The new sort implementations may panic if a type's implementation of [`Ord`](https://doc.rust-lang.org/std/cmp/trait.Ord.html) (or the given comparison function) does not implement a [total order](https://en.wikipedia.org/wiki/Total_order) as the trait requires. `Ord`'s supertraits (`PartialOrd`, `Eq`, and `PartialEq`) must also be consistent. The previous implementations would not "notice" any problem, but the new implementations have a good chance of detecting inconsistencies, throwing a panic rather than returning knowingly unsorted data.
@@ -584,7 +584,7 @@ Stabilized APIs
 - [`impl Default for Arc<CStr>`](https://doc.rust-lang.org/beta/alloc/sync/struct.Arc.html#impl-Default-for-Arc%3CCStr%3E)
 - [`impl Default for Arc<[T]>`](https://doc.rust-lang.org/beta/alloc/sync/struct.Arc.html#impl-Default-for-Arc%3C%5BT%5D%3E)
 - [`impl IntoIterator for Box<[T]>`](https://doc.rust-lang.org/beta/alloc/boxed/struct.Box.html#impl-IntoIterator-for-Box%3C%5BI%5D,+A%3E)
-- [`impl FromIterator<String> for Box<str>`](https://doc.rust-lang.org/beta/alloc/boxed/struct.Box.html#impl-FromIterator%3CString%3E-for-Box%3Cstr%3E) 
+- [`impl FromIterator<String> for Box<str>`](https://doc.rust-lang.org/beta/alloc/boxed/struct.Box.html#impl-FromIterator%3CString%3E-for-Box%3Cstr%3E)
 - [`impl FromIterator<char> for Box<str>`](https://doc.rust-lang.org/beta/alloc/boxed/struct.Box.html#impl-FromIterator%3Cchar%3E-for-Box%3Cstr%3E)
 - [`LazyCell`](https://doc.rust-lang.org/beta/core/cell/struct.LazyCell.html)
 - [`LazyLock`](https://doc.rust-lang.org/beta/std/sync/struct.LazyLock.html)
@@ -1816,7 +1816,7 @@ Compiler
 - [Detect uninhabited types early in const eval](https://github.com/rust-lang/rust/pull/109435/)
 - [Switch to LLD as default linker for {arm,thumb}v4t-none-eabi](https://github.com/rust-lang/rust/pull/109721/)
 - [Add tier 3 target `loongarch64-unknown-linux-gnu`](https://github.com/rust-lang/rust/pull/96971)
-- [Add tier 3 target for `i586-pc-nto-qnx700` (QNX Neutrino RTOS, version 7.0)](https://github.com/rust-lang/rust/pull/109173/), 
+- [Add tier 3 target for `i586-pc-nto-qnx700` (QNX Neutrino RTOS, version 7.0)](https://github.com/rust-lang/rust/pull/109173/),
 - [Insert alignment checks for pointer dereferences as debug assertions](https://github.com/rust-lang/rust/pull/98112)
   This catches undefined behavior at runtime, and may cause existing code to fail.
 
@@ -2023,7 +2023,7 @@ Compatibility Notes
   If `tools = [...]` is set in config.toml, we will respect a missing rustdoc in that list. By
   default rustdoc remains included. To retain the prior behavior explicitly add `"rustdoc"` to the
   list.
-  
+
 <a id="1.69.0-Internal-Changes"></a>
 
 Internal Changes
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 2f55a9eaeda..69ba78282f9 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -627,9 +627,11 @@ impl Pat {
             | PatKind::Or(s) => s.iter().for_each(|p| p.walk(it)),
 
             // Trivial wrappers over inner patterns.
-            PatKind::Box(s) | PatKind::Deref(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => {
-                s.walk(it)
-            }
+            PatKind::Box(s)
+            | PatKind::Deref(s)
+            | PatKind::Ref(s, _)
+            | PatKind::Paren(s)
+            | PatKind::Guard(s, _) => s.walk(it),
 
             // These patterns do not contain subpatterns, skip.
             PatKind::Wild
@@ -839,6 +841,9 @@ pub enum PatKind {
     // A never pattern `!`.
     Never,
 
+    /// A guard pattern (e.g., `x if guard(x)`).
+    Guard(P<Pat>, P<Expr>),
+
     /// Parentheses in patterns used for grouping (i.e., `(PAT)`).
     Paren(P<Pat>),
 
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 622c260868e..3a4a8ce266e 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -1525,6 +1525,10 @@ pub fn walk_pat<T: MutVisitor>(vis: &mut T, pat: &mut P<Pat>) {
             visit_opt(e2, |e| vis.visit_expr(e));
             vis.visit_span(span);
         }
+        PatKind::Guard(p, e) => {
+            vis.visit_pat(p);
+            vis.visit_expr(e);
+        }
         PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => {
             visit_thin_vec(elems, |elem| vis.visit_pat(elem))
         }
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 2f6998783fa..0b000c8cef8 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -682,6 +682,10 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res
             visit_opt!(visitor, visit_expr, lower_bound);
             visit_opt!(visitor, visit_expr, upper_bound);
         }
+        PatKind::Guard(subpattern, guard_condition) => {
+            try_visit!(visitor.visit_pat(subpattern));
+            try_visit!(visitor.visit_expr(guard_condition));
+        }
         PatKind::Wild | PatKind::Rest | PatKind::Never => {}
         PatKind::Err(_guar) => {}
         PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => {
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index ace7bfb5c73..c4bae084a3f 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -114,6 +114,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             self.lower_range_end(end, e2.is_some()),
                         );
                     }
+                    // FIXME(guard_patterns): lower pattern guards to HIR
+                    PatKind::Guard(inner, _) => pattern = inner,
                     PatKind::Slice(pats) => break self.lower_pat_slice(pats),
                     PatKind::Rest => {
                         // If we reach here the `..` pattern is not semantically allowed.
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 89311516081..390a575a186 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -556,6 +556,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
     gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
     gate_all!(explicit_tail_calls, "`become` expression is experimental");
     gate_all!(generic_const_items, "generic const items are experimental");
+    gate_all!(guard_patterns, "guard patterns are experimental", "consider using match arm guards");
     gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
     gate_all!(postfix_match, "postfix match is experimental");
     gate_all!(mut_ref, "mutable by-reference bindings are experimental");
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 479677b0a5a..49e4a559e73 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1709,6 +1709,14 @@ impl<'a> State<'a> {
                     self.print_expr(e, FixupContext::default());
                 }
             }
+            PatKind::Guard(subpat, condition) => {
+                self.popen();
+                self.print_pat(subpat);
+                self.space();
+                self.word_space("if");
+                self.print_expr(condition, FixupContext::default());
+                self.pclose();
+            }
             PatKind::Slice(elts) => {
                 self.word("[");
                 self.commasep(Inconsistent, elts, |s, p| s.print_pat(p));
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index c11103af476..b42c99e1a6d 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -1450,6 +1450,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                         ty::Param(param_ty) => Ok((
                             generics.type_param(param_ty, tcx),
                             predicate.trait_ref.print_trait_sugared().to_string(),
+                            Some(predicate.trait_ref.def_id),
                         )),
                         _ => Err(()),
                     }
@@ -1463,9 +1464,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 tcx,
                 hir_generics,
                 err,
-                predicates
-                    .iter()
-                    .map(|(param, constraint)| (param.name.as_str(), &**constraint, None)),
+                predicates.iter().map(|(param, constraint, def_id)| {
+                    (param.name.as_str(), &**constraint, *def_id)
+                }),
                 None,
             );
         }
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index c9486a730e1..9f552b3feb9 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -227,8 +227,6 @@ impl CodegenBackend for CraneliftCodegenBackend {
         sess: &Session,
         outputs: &OutputFilenames,
     ) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) {
-        let _timer = sess.timer("finish_ongoing_codegen");
-
         ongoing_codegen.downcast::<driver::aot::OngoingCodegen>().unwrap().join(sess, outputs)
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index d8b055137b3..c38c5d4c644 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -352,84 +352,84 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
             | sym::saturating_add
             | sym::saturating_sub => {
                 let ty = arg_tys[0];
-                match int_type_width_signed(ty, self) {
-                    Some((width, signed)) => match name {
-                        sym::ctlz | sym::cttz => {
-                            let y = self.const_bool(false);
-                            let ret = self.call_intrinsic(&format!("llvm.{name}.i{width}"), &[
-                                args[0].immediate(),
-                                y,
-                            ]);
-
-                            self.intcast(ret, llret_ty, false)
-                        }
-                        sym::ctlz_nonzero => {
-                            let y = self.const_bool(true);
-                            let llvm_name = &format!("llvm.ctlz.i{width}");
-                            let ret = self.call_intrinsic(llvm_name, &[args[0].immediate(), y]);
-                            self.intcast(ret, llret_ty, false)
-                        }
-                        sym::cttz_nonzero => {
-                            let y = self.const_bool(true);
-                            let llvm_name = &format!("llvm.cttz.i{width}");
-                            let ret = self.call_intrinsic(llvm_name, &[args[0].immediate(), y]);
-                            self.intcast(ret, llret_ty, false)
-                        }
-                        sym::ctpop => {
-                            let ret = self.call_intrinsic(&format!("llvm.ctpop.i{width}"), &[args
-                                [0]
-                            .immediate()]);
-                            self.intcast(ret, llret_ty, false)
-                        }
-                        sym::bswap => {
-                            if width == 8 {
-                                args[0].immediate() // byte swap a u8/i8 is just a no-op
-                            } else {
-                                self.call_intrinsic(&format!("llvm.bswap.i{width}"), &[
-                                    args[0].immediate()
-                                ])
-                            }
-                        }
-                        sym::bitreverse => self
-                            .call_intrinsic(&format!("llvm.bitreverse.i{width}"), &[
+                if !ty.is_integral() {
+                    tcx.dcx().emit_err(InvalidMonomorphization::BasicIntegerType {
+                        span,
+                        name,
+                        ty,
+                    });
+                    return Ok(());
+                }
+                let (size, signed) = ty.int_size_and_signed(self.tcx);
+                let width = size.bits();
+                match name {
+                    sym::ctlz | sym::cttz => {
+                        let y = self.const_bool(false);
+                        let ret = self.call_intrinsic(&format!("llvm.{name}.i{width}"), &[
+                            args[0].immediate(),
+                            y,
+                        ]);
+
+                        self.intcast(ret, llret_ty, false)
+                    }
+                    sym::ctlz_nonzero => {
+                        let y = self.const_bool(true);
+                        let llvm_name = &format!("llvm.ctlz.i{width}");
+                        let ret = self.call_intrinsic(llvm_name, &[args[0].immediate(), y]);
+                        self.intcast(ret, llret_ty, false)
+                    }
+                    sym::cttz_nonzero => {
+                        let y = self.const_bool(true);
+                        let llvm_name = &format!("llvm.cttz.i{width}");
+                        let ret = self.call_intrinsic(llvm_name, &[args[0].immediate(), y]);
+                        self.intcast(ret, llret_ty, false)
+                    }
+                    sym::ctpop => {
+                        let ret = self.call_intrinsic(&format!("llvm.ctpop.i{width}"), &[
+                            args[0].immediate()
+                        ]);
+                        self.intcast(ret, llret_ty, false)
+                    }
+                    sym::bswap => {
+                        if width == 8 {
+                            args[0].immediate() // byte swap a u8/i8 is just a no-op
+                        } else {
+                            self.call_intrinsic(&format!("llvm.bswap.i{width}"), &[
                                 args[0].immediate()
-                            ]),
-                        sym::rotate_left | sym::rotate_right => {
-                            let is_left = name == sym::rotate_left;
-                            let val = args[0].immediate();
-                            let raw_shift = args[1].immediate();
-                            // rotate = funnel shift with first two args the same
-                            let llvm_name =
-                                &format!("llvm.fsh{}.i{}", if is_left { 'l' } else { 'r' }, width);
-
-                            // llvm expects shift to be the same type as the values, but rust
-                            // always uses `u32`.
-                            let raw_shift = self.intcast(raw_shift, self.val_ty(val), false);
-
-                            self.call_intrinsic(llvm_name, &[val, val, raw_shift])
+                            ])
                         }
-                        sym::saturating_add | sym::saturating_sub => {
-                            let is_add = name == sym::saturating_add;
-                            let lhs = args[0].immediate();
-                            let rhs = args[1].immediate();
-                            let llvm_name = &format!(
-                                "llvm.{}{}.sat.i{}",
-                                if signed { 's' } else { 'u' },
-                                if is_add { "add" } else { "sub" },
-                                width
-                            );
-                            self.call_intrinsic(llvm_name, &[lhs, rhs])
-                        }
-                        _ => bug!(),
-                    },
-                    None => {
-                        tcx.dcx().emit_err(InvalidMonomorphization::BasicIntegerType {
-                            span,
-                            name,
-                            ty,
-                        });
-                        return Ok(());
                     }
+                    sym::bitreverse => self
+                        .call_intrinsic(&format!("llvm.bitreverse.i{width}"), &[
+                            args[0].immediate()
+                        ]),
+                    sym::rotate_left | sym::rotate_right => {
+                        let is_left = name == sym::rotate_left;
+                        let val = args[0].immediate();
+                        let raw_shift = args[1].immediate();
+                        // rotate = funnel shift with first two args the same
+                        let llvm_name =
+                            &format!("llvm.fsh{}.i{}", if is_left { 'l' } else { 'r' }, width);
+
+                        // llvm expects shift to be the same type as the values, but rust
+                        // always uses `u32`.
+                        let raw_shift = self.intcast(raw_shift, self.val_ty(val), false);
+
+                        self.call_intrinsic(llvm_name, &[val, val, raw_shift])
+                    }
+                    sym::saturating_add | sym::saturating_sub => {
+                        let is_add = name == sym::saturating_add;
+                        let lhs = args[0].immediate();
+                        let rhs = args[1].immediate();
+                        let llvm_name = &format!(
+                            "llvm.{}{}.sat.i{}",
+                            if signed { 's' } else { 'u' },
+                            if is_add { "add" } else { "sub" },
+                            width
+                        );
+                        self.call_intrinsic(llvm_name, &[lhs, rhs])
+                    }
+                    _ => bug!(),
                 }
             }
 
@@ -2531,19 +2531,3 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
 
     span_bug!(span, "unknown SIMD intrinsic");
 }
-
-// Returns the width of an int Ty, and if it's signed or not
-// Returns None if the type is not an integer
-// FIXME: there’s multiple of this functions, investigate using some of the already existing
-// stuffs.
-fn int_type_width_signed(ty: Ty<'_>, cx: &CodegenCx<'_, '_>) -> Option<(u64, bool)> {
-    match ty.kind() {
-        ty::Int(t) => {
-            Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.pointer_width)), true))
-        }
-        ty::Uint(t) => {
-            Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.pointer_width)), false))
-        }
-        _ => None,
-    }
-}
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 3dfb86d422d..5235891a18d 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -36,7 +36,7 @@ use rustc_codegen_ssa::back::write::{
 use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
 use rustc_data_structures::fx::FxIndexMap;
-use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, FatalError};
+use rustc_errors::{DiagCtxtHandle, FatalError};
 use rustc_metadata::EncodedMetadata;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_middle::ty::TyCtxt;
@@ -370,19 +370,14 @@ impl CodegenBackend for LlvmCodegenBackend {
         (codegen_results, work_products)
     }
 
-    fn link(
-        &self,
-        sess: &Session,
-        codegen_results: CodegenResults,
-        outputs: &OutputFilenames,
-    ) -> Result<(), ErrorGuaranteed> {
+    fn link(&self, sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames) {
         use rustc_codegen_ssa::back::link::link_binary;
 
         use crate::back::archive::LlvmArchiveBuilderBuilder;
 
         // Run the linker on any artifacts that resulted from the LLVM run.
         // This should produce either a finished executable or library.
-        link_binary(sess, &LlvmArchiveBuilderBuilder, codegen_results, outputs)
+        link_binary(sess, &LlvmArchiveBuilderBuilder, codegen_results, outputs);
     }
 }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index ad81ff272c6..f8b3ba79c0d 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -15,7 +15,7 @@ use rustc_ast::CRATE_NODE_ID;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::temp_dir::MaybeTempDir;
-use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, FatalError};
+use rustc_errors::{DiagCtxtHandle, FatalError};
 use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize};
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc_metadata::fs::{METADATA_FILENAME, copy_to_stdout, emit_wrapper_file};
@@ -71,7 +71,7 @@ pub fn link_binary(
     archive_builder_builder: &dyn ArchiveBuilderBuilder,
     codegen_results: CodegenResults,
     outputs: &OutputFilenames,
-) -> Result<(), ErrorGuaranteed> {
+) {
     let _timer = sess.timer("link_binary");
     let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata);
     let mut tempfiles_for_stdout_output: Vec<PathBuf> = Vec::new();
@@ -119,7 +119,7 @@ pub fn link_binary(
                         &codegen_results,
                         RlibFlavor::Normal,
                         &path,
-                    )?
+                    )
                     .build(&out_filename);
                 }
                 CrateType::Staticlib => {
@@ -129,7 +129,7 @@ pub fn link_binary(
                         &codegen_results,
                         &out_filename,
                         &path,
-                    )?;
+                    );
                 }
                 _ => {
                     link_natively(
@@ -139,7 +139,7 @@ pub fn link_binary(
                         &out_filename,
                         &codegen_results,
                         path.as_ref(),
-                    )?;
+                    );
                 }
             }
             if sess.opts.json_artifact_notifications {
@@ -225,8 +225,6 @@ pub fn link_binary(
             maybe_remove_temps_from_module(preserve_objects, preserve_dwarf_objects, module);
         }
     });
-
-    Ok(())
 }
 
 // Crate type is not passed when calculating the dylibs to include for LTO. In that case all
@@ -298,7 +296,7 @@ fn link_rlib<'a>(
     codegen_results: &CodegenResults,
     flavor: RlibFlavor,
     tmpdir: &MaybeTempDir,
-) -> Result<Box<dyn ArchiveBuilder + 'a>, ErrorGuaranteed> {
+) -> Box<dyn ArchiveBuilder + 'a> {
     let mut ab = archive_builder_builder.new_archive_builder(sess);
 
     let trailing_metadata = match flavor {
@@ -374,7 +372,7 @@ fn link_rlib<'a>(
         {
             let path = find_native_static_library(filename.as_str(), true, sess);
             let src = read(path)
-                .map_err(|e| sess.dcx().emit_fatal(errors::ReadFileError { message: e }))?;
+                .unwrap_or_else(|e| sess.dcx().emit_fatal(errors::ReadFileError { message: e }));
             let (data, _) = create_wrapper_file(sess, ".bundled_lib".to_string(), &src);
             let wrapper_file = emit_wrapper_file(sess, &data, tmpdir, filename.as_str());
             packed_bundled_libs.push(wrapper_file);
@@ -392,7 +390,7 @@ fn link_rlib<'a>(
         codegen_results.crate_info.used_libraries.iter(),
         tmpdir.as_ref(),
         true,
-    )? {
+    ) {
         ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|error| {
             sess.dcx().emit_fatal(errors::AddNativeLibrary { library_path: output_path, error });
         });
@@ -433,7 +431,7 @@ fn link_rlib<'a>(
         ab.add_file(&lib)
     }
 
-    Ok(ab)
+    ab
 }
 
 /// Extract all symbols defined in raw-dylib libraries, collated by library name.
@@ -445,7 +443,7 @@ fn link_rlib<'a>(
 fn collate_raw_dylibs<'a>(
     sess: &Session,
     used_libraries: impl IntoIterator<Item = &'a NativeLib>,
-) -> Result<Vec<(String, Vec<DllImport>)>, ErrorGuaranteed> {
+) -> Vec<(String, Vec<DllImport>)> {
     // Use index maps to preserve original order of imports and libraries.
     let mut dylib_table = FxIndexMap::<String, FxIndexMap<Symbol, &DllImport>>::default();
 
@@ -469,15 +467,13 @@ fn collate_raw_dylibs<'a>(
             }
         }
     }
-    if let Some(guar) = sess.dcx().has_errors() {
-        return Err(guar);
-    }
-    Ok(dylib_table
+    sess.dcx().abort_if_errors();
+    dylib_table
         .into_iter()
         .map(|(name, imports)| {
             (name, imports.into_iter().map(|(_, import)| import.clone()).collect())
         })
-        .collect())
+        .collect()
 }
 
 fn create_dll_import_libs<'a>(
@@ -486,8 +482,8 @@ fn create_dll_import_libs<'a>(
     used_libraries: impl IntoIterator<Item = &'a NativeLib>,
     tmpdir: &Path,
     is_direct_dependency: bool,
-) -> Result<Vec<PathBuf>, ErrorGuaranteed> {
-    Ok(collate_raw_dylibs(sess, used_libraries)?
+) -> Vec<PathBuf> {
+    collate_raw_dylibs(sess, used_libraries)
         .into_iter()
         .map(|(raw_dylib_name, raw_dylib_imports)| {
             let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" };
@@ -537,7 +533,7 @@ fn create_dll_import_libs<'a>(
 
             output_path
         })
-        .collect())
+        .collect()
 }
 
 /// Create a static archive.
@@ -557,7 +553,7 @@ fn link_staticlib(
     codegen_results: &CodegenResults,
     out_filename: &Path,
     tempdir: &MaybeTempDir,
-) -> Result<(), ErrorGuaranteed> {
+) {
     info!("preparing staticlib to {:?}", out_filename);
     let mut ab = link_rlib(
         sess,
@@ -565,7 +561,7 @@ fn link_staticlib(
         codegen_results,
         RlibFlavor::StaticlibBase,
         tempdir,
-    )?;
+    );
     let mut all_native_libs = vec![];
 
     let res = each_linked_rlib(
@@ -656,8 +652,6 @@ fn link_staticlib(
             print_native_static_libs(sess, &print.out, &all_native_libs, &all_rust_dylibs);
         }
     }
-
-    Ok(())
 }
 
 /// Use `thorin` (rust implementation of a dwarf packaging utility) to link DWARF objects into a
@@ -773,7 +767,7 @@ fn link_natively(
     out_filename: &Path,
     codegen_results: &CodegenResults,
     tmpdir: &Path,
-) -> Result<(), ErrorGuaranteed> {
+) {
     info!("preparing {:?} to {:?}", crate_type, out_filename);
     let (linker_path, flavor) = linker_and_flavor(sess);
     let self_contained_components = self_contained_components(sess, crate_type);
@@ -797,7 +791,7 @@ fn link_natively(
         temp_filename,
         codegen_results,
         self_contained_components,
-    )?;
+    );
 
     linker::disable_localization(&mut cmd);
 
@@ -1177,8 +1171,6 @@ fn link_natively(
         ab.add_file(temp_filename);
         ab.build(out_filename);
     }
-
-    Ok(())
 }
 
 fn strip_symbols_with_external_utility(
@@ -2232,7 +2224,7 @@ fn linker_with_args(
     out_filename: &Path,
     codegen_results: &CodegenResults,
     self_contained_components: LinkSelfContainedComponents,
-) -> Result<Command, ErrorGuaranteed> {
+) -> Command {
     let self_contained_crt_objects = self_contained_components.is_crt_objects_enabled();
     let cmd = &mut *super::linker::get_linker(
         sess,
@@ -2356,7 +2348,7 @@ fn linker_with_args(
         codegen_results.crate_info.used_libraries.iter(),
         tmpdir,
         true,
-    )? {
+    ) {
         cmd.add_object(&output_path);
     }
     // As with add_upstream_native_libraries, we need to add the upstream raw-dylib symbols in case
@@ -2388,7 +2380,7 @@ fn linker_with_args(
         native_libraries_from_nonstatics,
         tmpdir,
         false,
-    )? {
+    ) {
         cmd.add_object(&output_path);
     }
 
@@ -2435,7 +2427,7 @@ fn linker_with_args(
     // to it and remove the option. Currently the last holdout is wasm32-unknown-emscripten.
     add_post_link_args(cmd, sess, flavor);
 
-    Ok(cmd.take_cmd())
+    cmd.take_cmd()
 }
 
 fn add_order_independent_options(
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 7c0e9cfd5a7..90d48d6ee7e 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -1883,7 +1883,11 @@ impl Translate for SharedEmitter {
 }
 
 impl Emitter for SharedEmitter {
-    fn emit_diagnostic(&mut self, mut diag: rustc_errors::DiagInner) {
+    fn emit_diagnostic(
+        &mut self,
+        mut diag: rustc_errors::DiagInner,
+        _registry: &rustc_errors::registry::Registry,
+    ) {
         // Check that we aren't missing anything interesting when converting to
         // the cut-down local `DiagInner`.
         assert_eq!(diag.span, MultiSpan::new());
@@ -2028,8 +2032,6 @@ pub struct OngoingCodegen<B: ExtraBackendMethods> {
 
 impl<B: ExtraBackendMethods> OngoingCodegen<B> {
     pub fn join(self, sess: &Session) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) {
-        let _timer = sess.timer("finish_ongoing_codegen");
-
         self.shared_emitter_main.check(sess, true);
         let compiled_modules = sess.time("join_worker_thread", || match self.coordinator.join() {
             Ok(Ok(compiled_modules)) => compiled_modules,
diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs
index 7eab889edf0..5b4a51fc301 100644
--- a/compiler/rustc_codegen_ssa/src/traits/backend.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs
@@ -4,7 +4,6 @@ use std::hash::Hash;
 use rustc_ast::expand::allocator::AllocatorKind;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::sync::{DynSend, DynSync};
-use rustc_errors::ErrorGuaranteed;
 use rustc_metadata::EncodedMetadata;
 use rustc_metadata::creader::MetadataLoaderDyn;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
@@ -84,13 +83,8 @@ pub trait CodegenBackend {
     ) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>);
 
     /// This is called on the returned [`CodegenResults`] from [`join_codegen`](Self::join_codegen).
-    fn link(
-        &self,
-        sess: &Session,
-        codegen_results: CodegenResults,
-        outputs: &OutputFilenames,
-    ) -> Result<(), ErrorGuaranteed> {
-        link_binary(sess, &ArArchiveBuilderBuilder, codegen_results, outputs)
+    fn link(&self, sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames) {
+        link_binary(sess, &ArArchiveBuilderBuilder, codegen_results, outputs);
     }
 
     /// Returns `true` if this backend can be safely called from multiple threads.
diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs
index 489bb54a6f9..23f2aa4d029 100644
--- a/compiler/rustc_const_eval/src/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/check_consts/ops.rs
@@ -140,7 +140,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
                             err,
                             param_ty.name.as_str(),
                             &constraint,
-                            None,
+                            Some(trait_ref.def_id),
                             None,
                         );
                     }
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 2beec544fad..f54a932e1b6 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -1018,29 +1018,48 @@ where
         self.allocate_dyn(layout, kind, MemPlaceMeta::None)
     }
 
-    /// Returns a wide MPlace of type `str` to a new 1-aligned allocation.
-    /// Immutable strings are deduplicated and stored in global memory.
-    pub fn allocate_str(
+    /// Allocates a sequence of bytes in the interpreter's memory.
+    /// For immutable allocations, uses deduplication to reuse existing memory.
+    /// For mutable allocations, creates a new unique allocation.
+    pub fn allocate_bytes(
         &mut self,
-        str: &str,
+        bytes: &[u8],
+        align: Align,
         kind: MemoryKind<M::MemoryKind>,
         mutbl: Mutability,
-    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
-        let tcx = self.tcx.tcx;
-
+    ) -> InterpResult<'tcx, Pointer<M::Provenance>> {
         // Use cache for immutable strings.
-        let ptr = if mutbl.is_not() {
+        if mutbl.is_not() {
             // Use dedup'd allocation function.
             let salt = M::get_global_alloc_salt(self, None);
-            let id = tcx.allocate_bytes_dedup(str.as_bytes(), salt);
+            let id = self.tcx.allocate_bytes_dedup(bytes, salt);
 
             // Turn untagged "global" pointers (obtained via `tcx`) into the machine pointer to the allocation.
-            M::adjust_alloc_root_pointer(&self, Pointer::from(id), Some(kind))?
+            M::adjust_alloc_root_pointer(&self, Pointer::from(id), Some(kind))
         } else {
-            self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl)?
-        };
-        let meta = Scalar::from_target_usize(u64::try_from(str.len()).unwrap(), self);
+            // Allocate new memory for mutable data.
+            self.allocate_bytes_ptr(bytes, align, kind, mutbl)
+        }
+    }
+
+    /// Allocates a string in the interpreter's memory with metadata for length.
+    /// Uses `allocate_bytes` internally but adds string-specific metadata handling.
+    pub fn allocate_str(
+        &mut self,
+        str: &str,
+        kind: MemoryKind<M::MemoryKind>,
+        mutbl: Mutability,
+    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
+        let bytes = str.as_bytes();
+        let ptr = self.allocate_bytes(bytes, Align::ONE, kind, mutbl)?;
+
+        // Create length metadata for the string.
+        let meta = Scalar::from_target_usize(u64::try_from(bytes.len()).unwrap(), self);
+
+        // Get layout for Rust's str type.
         let layout = self.layout_of(self.tcx.types.str_).unwrap();
+
+        // Combine pointer and metadata into a wide pointer.
         interp_ok(self.ptr_with_meta_to_mplace(
             ptr.into(),
             MemPlaceMeta::Meta(meta),
diff --git a/compiler/rustc_driver_impl/src/args.rs b/compiler/rustc_driver_impl/src/args.rs
index 28574457389..2fc767b3750 100644
--- a/compiler/rustc_driver_impl/src/args.rs
+++ b/compiler/rustc_driver_impl/src/args.rs
@@ -99,10 +99,7 @@ impl Expander {
 /// If this function is intended to be used with command line arguments,
 /// `argv[0]` must be removed prior to calling it manually.
 #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
-pub fn arg_expand_all(
-    early_dcx: &EarlyDiagCtxt,
-    at_args: &[String],
-) -> Result<Vec<String>, ErrorGuaranteed> {
+pub fn arg_expand_all(early_dcx: &EarlyDiagCtxt, at_args: &[String]) -> Vec<String> {
     let mut expander = Expander::default();
     let mut result = Ok(());
     for arg in at_args {
@@ -110,7 +107,10 @@ pub fn arg_expand_all(
             result = Err(early_dcx.early_err(format!("failed to load argument file: {err}")));
         }
     }
-    result.map(|()| expander.finish())
+    if let Err(guar) = result {
+        guar.raise_fatal();
+    }
+    expander.finish()
 }
 
 /// Gets the raw unprocessed command-line arguments as Unicode strings, without doing any further
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index b7d64f75bf3..2e01c385a66 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -42,9 +42,7 @@ use rustc_data_structures::profiling::{
 };
 use rustc_errors::emitter::stderr_destination;
 use rustc_errors::registry::Registry;
-use rustc_errors::{
-    ColorConfig, DiagCtxt, ErrCode, ErrorGuaranteed, FatalError, PResult, markdown,
-};
+use rustc_errors::{ColorConfig, DiagCtxt, ErrCode, FatalError, PResult, markdown};
 use rustc_feature::find_gated_cfg;
 use rustc_interface::util::{self, get_codegen_backend};
 use rustc_interface::{Linker, Queries, interface, passes};
@@ -271,14 +269,14 @@ impl<'a> RunCompiler<'a> {
     }
 
     /// Parse args and run the compiler.
-    pub fn run(self) -> interface::Result<()> {
+    pub fn run(self) {
         run_compiler(
             self.at_args,
             self.callbacks,
             self.file_loader,
             self.make_codegen_backend,
             self.using_internal_features,
-        )
+        );
     }
 }
 
@@ -290,7 +288,7 @@ fn run_compiler(
         Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
     >,
     using_internal_features: Arc<std::sync::atomic::AtomicBool>,
-) -> interface::Result<()> {
+) {
     let mut default_early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default());
 
     // Throw away the first argument, the name of the binary.
@@ -303,9 +301,11 @@ fn run_compiler(
     // the compiler with @empty_file as argv[0] and no more arguments.
     let at_args = at_args.get(1..).unwrap_or_default();
 
-    let args = args::arg_expand_all(&default_early_dcx, at_args)?;
+    let args = args::arg_expand_all(&default_early_dcx, at_args);
 
-    let Some(matches) = handle_options(&default_early_dcx, &args) else { return Ok(()) };
+    let Some(matches) = handle_options(&default_early_dcx, &args) else {
+        return;
+    };
 
     let sopts = config::build_session_options(&mut default_early_dcx, &matches);
     // fully initialize ice path static once unstable options are available as context
@@ -313,7 +313,7 @@ fn run_compiler(
 
     if let Some(ref code) = matches.opt_str("explain") {
         handle_explain(&default_early_dcx, diagnostics_registry(), code, sopts.color);
-        return Ok(());
+        return;
     }
 
     let (odir, ofile) = make_output(&matches);
@@ -338,7 +338,7 @@ fn run_compiler(
         expanded_args: args,
     };
 
-    let has_input = match make_input(&default_early_dcx, &matches.free)? {
+    let has_input = match make_input(&default_early_dcx, &matches.free) {
         Some(input) => {
             config.input = input;
             true // has input: normal compilation
@@ -358,7 +358,7 @@ fn run_compiler(
         // printing some information without compiling, or exiting immediately
         // after parsing, etc.
         let early_exit = || {
-            if let Some(guar) = sess.dcx().has_errors() { Err(guar) } else { Ok(()) }
+            sess.dcx().abort_if_errors();
         };
 
         // This implements `-Whelp`. It should be handled very early, like
@@ -389,22 +389,25 @@ fn run_compiler(
         }
 
         let linker = compiler.enter(|queries| {
-            let early_exit = || early_exit().map(|_| None);
+            let early_exit = || {
+                sess.dcx().abort_if_errors();
+                None
+            };
 
             // Parse the crate root source code (doesn't parse submodules yet)
             // Everything else is parsed during macro expansion.
-            queries.parse()?;
+            queries.parse();
 
             // If pretty printing is requested: Figure out the representation, print it and exit
             if let Some(pp_mode) = sess.opts.pretty {
                 if pp_mode.needs_ast_map() {
-                    queries.global_ctxt()?.enter(|tcx| {
+                    queries.global_ctxt().enter(|tcx| {
                         tcx.ensure().early_lint_checks(());
                         pretty::print(sess, pp_mode, pretty::PrintExtra::NeedsAstMap { tcx });
                         passes::write_dep_info(tcx);
                     });
                 } else {
-                    let krate = queries.parse()?;
+                    let krate = queries.parse();
                     pretty::print(sess, pp_mode, pretty::PrintExtra::AfterParsing {
                         krate: &*krate.borrow(),
                     });
@@ -423,17 +426,17 @@ fn run_compiler(
             }
 
             // Make sure name resolution and macro expansion is run.
-            queries.global_ctxt()?.enter(|tcx| tcx.resolver_for_lowering());
+            queries.global_ctxt().enter(|tcx| tcx.resolver_for_lowering());
 
             if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir {
-                queries.global_ctxt()?.enter(|tcxt| dump_feature_usage_metrics(tcxt, metrics_dir));
+                queries.global_ctxt().enter(|tcxt| dump_feature_usage_metrics(tcxt, metrics_dir));
             }
 
             if callbacks.after_expansion(compiler, queries) == Compilation::Stop {
                 return early_exit();
             }
 
-            queries.global_ctxt()?.enter(|tcx| {
+            queries.global_ctxt().enter(|tcx| {
                 passes::write_dep_info(tcx);
 
                 if sess.opts.output_types.contains_key(&OutputType::DepInfo)
@@ -446,24 +449,21 @@ fn run_compiler(
                     return early_exit();
                 }
 
-                tcx.analysis(())?;
+                tcx.ensure().analysis(());
 
                 if callbacks.after_analysis(compiler, tcx) == Compilation::Stop {
                     return early_exit();
                 }
 
-                Ok(Some(Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend)?))
+                Some(Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend))
             })
-        })?;
+        });
 
         // Linking is done outside the `compiler.enter()` so that the
         // `GlobalCtxt` within `Queries` can be freed as early as possible.
         if let Some(linker) = linker {
-            let _timer = sess.timer("link");
-            linker.link(sess, codegen_backend)?
+            linker.link(sess, codegen_backend);
         }
-
-        Ok(())
     })
 }
 
@@ -496,21 +496,17 @@ fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<OutFileNa
 
 /// Extract input (string or file and optional path) from matches.
 /// This handles reading from stdin if `-` is provided.
-fn make_input(
-    early_dcx: &EarlyDiagCtxt,
-    free_matches: &[String],
-) -> Result<Option<Input>, ErrorGuaranteed> {
+fn make_input(early_dcx: &EarlyDiagCtxt, free_matches: &[String]) -> Option<Input> {
     match free_matches {
-        [] => Ok(None), // no input: we will exit early,
+        [] => None, // no input: we will exit early,
         [ifile] if ifile == "-" => {
             // read from stdin as `Input::Str`
             let mut input = String::new();
             if io::stdin().read_to_string(&mut input).is_err() {
                 // Immediately stop compilation if there was an issue reading
                 // the input (for example if the input stream is not UTF-8).
-                let reported = early_dcx
-                    .early_err("couldn't read from stdin, as it did not contain valid UTF-8");
-                return Err(reported);
+                early_dcx
+                    .early_fatal("couldn't read from stdin, as it did not contain valid UTF-8");
             }
 
             let name = match env::var("UNSTABLE_RUSTDOC_TEST_PATH") {
@@ -526,9 +522,9 @@ fn make_input(
                 Err(_) => FileName::anon_source_code(&input),
             };
 
-            Ok(Some(Input::Str { name, input }))
+            Some(Input::Str { name, input })
         }
-        [ifile] => Ok(Some(Input::File(PathBuf::from(ifile)))),
+        [ifile] => Some(Input::File(PathBuf::from(ifile))),
         [ifile1, ifile2, ..] => early_dcx.early_fatal(format!(
             "multiple input filenames provided (first two filenames are `{}` and `{}`)",
             ifile1, ifile2
@@ -663,9 +659,7 @@ fn process_rlink(sess: &Session, compiler: &interface::Compiler) {
                 };
             }
         };
-        if compiler.codegen_backend.link(sess, codegen_results, &outputs).is_err() {
-            FatalError.raise();
-        }
+        compiler.codegen_backend.link(sess, codegen_results, &outputs);
     } else {
         dcx.emit_fatal(RlinkNotAFile {});
     }
@@ -1608,7 +1602,8 @@ pub fn main() -> ! {
     let exit_code = catch_with_exit_code(|| {
         RunCompiler::new(&args::raw_args(&early_dcx)?, &mut callbacks)
             .set_using_internal_features(using_internal_features)
-            .run()
+            .run();
+        Ok(())
     });
 
     if let Some(format) = callbacks.time_passes {
diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs
index 0733b8c0b98..5df960be307 100644
--- a/compiler/rustc_driver_impl/src/pretty.rs
+++ b/compiler/rustc_driver_impl/src/pretty.rs
@@ -222,8 +222,8 @@ impl<'tcx> PrintExtra<'tcx> {
 }
 
 pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) {
-    if ppm.needs_analysis() && ex.tcx().analysis(()).is_err() {
-        FatalError.raise();
+    if ppm.needs_analysis() {
+        ex.tcx().ensure().analysis(());
     }
 
     let (src, src_name) = get_source(sess);
diff --git a/compiler/rustc_error_codes/src/error_codes/E0751.md b/compiler/rustc_error_codes/src/error_codes/E0751.md
index 8794f7868f3..825809b229a 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0751.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0751.md
@@ -9,4 +9,4 @@ impl !MyTrait for i32 { } // error!
 ```
 
 Negative implementations are a promise that the trait will never be implemented
-for the given types. Therefore, both cannot exists at the same time.
+for the given types. Therefore, both cannot exist at the same time.
diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
index b4a651b10b1..b337e279400 100644
--- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
+++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
@@ -12,6 +12,7 @@ use rustc_span::SourceFile;
 use rustc_span::source_map::SourceMap;
 
 use crate::emitter::FileWithAnnotatedLines;
+use crate::registry::Registry;
 use crate::snippet::Line;
 use crate::translation::{Translate, to_fluent_args};
 use crate::{
@@ -45,7 +46,7 @@ impl Translate for AnnotateSnippetEmitter {
 
 impl Emitter for AnnotateSnippetEmitter {
     /// The entry point for the diagnostics generation
-    fn emit_diagnostic(&mut self, mut diag: DiagInner) {
+    fn emit_diagnostic(&mut self, mut diag: DiagInner, _registry: &Registry) {
         let fluent_args = to_fluent_args(diag.args.iter());
 
         let mut suggestions = diag.suggestions.unwrap_tag();
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index a386129e814..1b6c6edcc61 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -27,6 +27,7 @@ use termcolor::{Buffer, BufferWriter, Color, ColorChoice, ColorSpec, StandardStr
 use tracing::{debug, instrument, trace, warn};
 
 use crate::diagnostic::DiagLocation;
+use crate::registry::Registry;
 use crate::snippet::{
     Annotation, AnnotationColumn, AnnotationType, Line, MultilineAnnotation, Style, StyledString,
 };
@@ -181,7 +182,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: DiagInner);
+    fn emit_diagnostic(&mut self, diag: DiagInner, registry: &Registry);
 
     /// Emit a notification that an artifact has been output.
     /// Currently only supported for the JSON format.
@@ -189,7 +190,7 @@ pub trait Emitter: Translate {
 
     /// Emit a report about future breakage.
     /// Currently only supported for the JSON format.
-    fn emit_future_breakage_report(&mut self, _diags: Vec<DiagInner>) {}
+    fn emit_future_breakage_report(&mut self, _diags: Vec<DiagInner>, _registry: &Registry) {}
 
     /// Emit list of unused externs.
     /// Currently only supported for the JSON format.
@@ -500,7 +501,7 @@ impl Emitter for HumanEmitter {
         self.sm.as_deref()
     }
 
-    fn emit_diagnostic(&mut self, mut diag: DiagInner) {
+    fn emit_diagnostic(&mut self, mut diag: DiagInner, _registry: &Registry) {
         let fluent_args = to_fluent_args(diag.args.iter());
 
         let mut suggestions = diag.suggestions.unwrap_tag();
@@ -561,7 +562,7 @@ impl Emitter for SilentEmitter {
         None
     }
 
-    fn emit_diagnostic(&mut self, mut diag: DiagInner) {
+    fn emit_diagnostic(&mut self, mut diag: DiagInner, _registry: &Registry) {
         if self.emit_fatal_diagnostic && diag.level == Level::Fatal {
             if let Some(fatal_note) = &self.fatal_note {
                 diag.sub(Level::Note, fatal_note.clone(), MultiSpan::new());
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index e3b6dcea892..97df7f9265a 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -44,7 +44,6 @@ mod tests;
 pub struct JsonEmitter {
     #[setters(skip)]
     dst: IntoDynSyncSend<Box<dyn Write + Send>>,
-    registry: Option<Registry>,
     #[setters(skip)]
     sm: Lrc<SourceMap>,
     fluent_bundle: Option<Lrc<FluentBundle>>,
@@ -74,7 +73,6 @@ impl JsonEmitter {
     ) -> JsonEmitter {
         JsonEmitter {
             dst: IntoDynSyncSend(dst),
-            registry: None,
             sm,
             fluent_bundle: None,
             fallback_bundle,
@@ -121,8 +119,8 @@ impl Translate for JsonEmitter {
 }
 
 impl Emitter for JsonEmitter {
-    fn emit_diagnostic(&mut self, diag: crate::DiagInner) {
-        let data = Diagnostic::from_errors_diagnostic(diag, self);
+    fn emit_diagnostic(&mut self, diag: crate::DiagInner, registry: &Registry) {
+        let data = Diagnostic::from_errors_diagnostic(diag, self, registry);
         let result = self.emit(EmitTyped::Diagnostic(data));
         if let Err(e) = result {
             panic!("failed to print diagnostics: {e:?}");
@@ -137,7 +135,7 @@ impl Emitter for JsonEmitter {
         }
     }
 
-    fn emit_future_breakage_report(&mut self, diags: Vec<crate::DiagInner>) {
+    fn emit_future_breakage_report(&mut self, diags: Vec<crate::DiagInner>, registry: &Registry) {
         let data: Vec<FutureBreakageItem<'_>> = diags
             .into_iter()
             .map(|mut diag| {
@@ -151,7 +149,7 @@ impl Emitter for JsonEmitter {
                 }
                 FutureBreakageItem {
                     diagnostic: EmitTyped::Diagnostic(Diagnostic::from_errors_diagnostic(
-                        diag, self,
+                        diag, self, registry,
                     )),
                 }
             })
@@ -291,7 +289,11 @@ struct UnusedExterns<'a> {
 
 impl Diagnostic {
     /// Converts from `rustc_errors::DiagInner` to `Diagnostic`.
-    fn from_errors_diagnostic(diag: crate::DiagInner, je: &JsonEmitter) -> Diagnostic {
+    fn from_errors_diagnostic(
+        diag: crate::DiagInner,
+        je: &JsonEmitter,
+        registry: &Registry,
+    ) -> Diagnostic {
         let args = to_fluent_args(diag.args.iter());
         let sugg_to_diag = |sugg: &CodeSuggestion| {
             let translated_message =
@@ -344,7 +346,7 @@ impl Diagnostic {
         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(),
+                explanation: registry.try_find_description(code).ok(),
             })
         } else if let Some(IsLint { name, .. }) = &diag.is_lint {
             Some(DiagnosticCode { code: name.to_string(), explanation: None })
@@ -382,7 +384,7 @@ impl Diagnostic {
             } else {
                 OutputTheme::Ascii
             })
-            .emit_diagnostic(diag);
+            .emit_diagnostic(diag, registry);
         let buf = Arc::try_unwrap(buf.0).unwrap().into_inner().unwrap();
         let buf = String::from_utf8(buf).unwrap();
 
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 98200c367f9..6232c875ee8 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -55,7 +55,6 @@ pub use diagnostic_impls::{
 };
 pub use emitter::ColorConfig;
 use emitter::{DynEmitter, Emitter, is_case_difference, is_different};
-use registry::Registry;
 use rustc_data_structures::AtomicRef;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::stable_hasher::{Hash128, StableHasher};
@@ -77,6 +76,8 @@ pub use snippet::Style;
 pub use termcolor::{Color, ColorSpec, WriteColor};
 use tracing::debug;
 
+use crate::registry::Registry;
+
 pub mod annotate_snippet_emitter_writer;
 pub mod codes;
 mod diagnostic;
@@ -483,6 +484,8 @@ impl<'a> std::ops::Deref for DiagCtxtHandle<'a> {
 struct DiagCtxtInner {
     flags: DiagCtxtFlags,
 
+    registry: Registry,
+
     /// The error guarantees from all emitted errors. The length gives the error count.
     err_guars: Vec<ErrorGuaranteed>,
     /// The error guarantee from all emitted lint errors. The length gives the
@@ -619,9 +622,7 @@ impl Drop for DiagCtxtInner {
         // Important: it is sound to produce an `ErrorGuaranteed` when emitting
         // delayed bugs because they are guaranteed to be emitted here if
         // necessary.
-        if self.err_guars.is_empty() {
-            self.flush_delayed()
-        }
+        self.flush_delayed();
 
         // Sanity check: did we use some of the expensive `trimmed_def_paths` functions
         // unexpectedly, that is, without producing diagnostics? If so, for debugging purposes, we
@@ -664,6 +665,11 @@ impl DiagCtxt {
         self
     }
 
+    pub fn with_registry(mut self, registry: Registry) -> Self {
+        self.inner.get_mut().registry = registry;
+        self
+    }
+
     pub fn new(emitter: Box<DynEmitter>) -> Self {
         Self { inner: Lock::new(DiagCtxtInner::new(emitter)) }
     }
@@ -694,7 +700,7 @@ impl DiagCtxt {
         struct FalseEmitter;
 
         impl Emitter for FalseEmitter {
-            fn emit_diagnostic(&mut self, _: DiagInner) {
+            fn emit_diagnostic(&mut self, _: DiagInner, _: &Registry) {
                 unimplemented!("false emitter must only used during `wrap_emitter`")
             }
 
@@ -759,6 +765,7 @@ impl DiagCtxt {
         let mut inner = self.inner.borrow_mut();
         let DiagCtxtInner {
             flags: _,
+            registry: _,
             err_guars,
             lint_err_guars,
             delayed_bugs,
@@ -964,7 +971,7 @@ impl<'a> DiagCtxtHandle<'a> {
         self.inner.borrow().has_errors_or_delayed_bugs()
     }
 
-    pub fn print_error_count(&self, registry: &Registry) {
+    pub fn print_error_count(&self) {
         let mut inner = self.inner.borrow_mut();
 
         // Any stashed diagnostics should have been handled by
@@ -1014,7 +1021,7 @@ impl<'a> DiagCtxtHandle<'a> {
                 .emitted_diagnostic_codes
                 .iter()
                 .filter_map(|&code| {
-                    if registry.try_find_description(code).is_ok() {
+                    if inner.registry.try_find_description(code).is_ok() {
                         Some(code.to_string())
                     } else {
                         None
@@ -1075,10 +1082,10 @@ impl<'a> DiagCtxtHandle<'a> {
     }
 
     pub fn emit_future_breakage_report(&self) {
-        let mut inner = self.inner.borrow_mut();
+        let inner = &mut *self.inner.borrow_mut();
         let diags = std::mem::take(&mut inner.future_breakage_diagnostics);
         if !diags.is_empty() {
-            inner.emitter.emit_future_breakage_report(diags);
+            inner.emitter.emit_future_breakage_report(diags, &inner.registry);
         }
     }
 
@@ -1409,6 +1416,7 @@ impl DiagCtxtInner {
     fn new(emitter: Box<DynEmitter>) -> Self {
         Self {
             flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
+            registry: Registry::new(&[]),
             err_guars: Vec::new(),
             lint_err_guars: Vec::new(),
             delayed_bugs: Vec::new(),
@@ -1582,7 +1590,7 @@ impl DiagCtxtInner {
                 }
                 self.has_printed = true;
 
-                self.emitter.emit_diagnostic(diagnostic);
+                self.emitter.emit_diagnostic(diagnostic, &self.registry);
             }
 
             if is_error {
@@ -1695,7 +1703,13 @@ impl DiagCtxtInner {
         // eventually happened.
         assert!(self.stashed_diagnostics.is_empty());
 
+        if !self.err_guars.is_empty() {
+            // If an error happened already. We shouldn't expose delayed bugs.
+            return;
+        }
+
         if self.delayed_bugs.is_empty() {
+            // Nothing to do.
             return;
         }
 
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index e5500c8bba1..6a6496f9827 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -990,7 +990,7 @@ pub fn parse_ast_fragment<'a>(
             }
         }
         AstFragmentKind::Ty => AstFragment::Ty(this.parse_ty()?),
-        AstFragmentKind::Pat => AstFragment::Pat(this.parse_pat_allow_top_alt(
+        AstFragmentKind::Pat => AstFragment::Pat(this.parse_pat_allow_top_guard(
             None,
             RecoverComma::No,
             RecoverColon::Yes,
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index abc7200699c..bf26b5d25d2 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -505,6 +505,8 @@ declare_features! (
     (incomplete, generic_const_items, "1.73.0", Some(113521)),
     /// Allows registering static items globally, possibly across crates, to iterate over at runtime.
     (unstable, global_registration, "1.80.0", Some(125119)),
+    /// Allows using guards in patterns.
+    (incomplete, guard_patterns, "CURRENT_RUSTC_VERSION", Some(129967)),
     /// Allows using `..=X` as a patterns in slices.
     (unstable, half_open_range_patterns_in_slices, "1.66.0", Some(67264)),
     /// Allows `if let` guard in match arms.
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index ff449a858d6..2e227ead14a 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -279,7 +279,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     } else {
                         let mut err = self.dcx().create_err(err);
                         if suggest_constraining_type_param(
-                            tcx, generics, &mut err, &qself_str, &trait_ref, None, None,
+                            tcx,
+                            generics,
+                            &mut err,
+                            &qself_str,
+                            &trait_ref,
+                            Some(best_trait),
+                            None,
                         ) && !identically_named
                         {
                             // We suggested constraining a type parameter, but the associated item on it
diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs
index f6c3e8ebbcb..4ea171ab4a9 100644
--- a/compiler/rustc_incremental/src/persist/fs.rs
+++ b/compiler/rustc_incremental/src/persist/fs.rs
@@ -114,7 +114,6 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_data_structures::{base_n, flock};
-use rustc_errors::ErrorGuaranteed;
 use rustc_fs_util::{LinkOrCopy, link_or_copy, try_canonicalize};
 use rustc_middle::bug;
 use rustc_session::config::CrateType;
@@ -212,9 +211,9 @@ pub fn in_incr_comp_dir(incr_comp_session_dir: &Path, file_name: &str) -> PathBu
 /// The garbage collection will take care of it.
 ///
 /// [`rustc_interface::queries::dep_graph`]: ../../rustc_interface/struct.Queries.html#structfield.dep_graph
-pub(crate) fn prepare_session_directory(sess: &Session) -> Result<(), ErrorGuaranteed> {
+pub(crate) fn prepare_session_directory(sess: &Session) {
     if sess.opts.incremental.is_none() {
-        return Ok(());
+        return;
     }
 
     let _timer = sess.timer("incr_comp_prepare_session_directory");
@@ -224,7 +223,7 @@ pub(crate) fn prepare_session_directory(sess: &Session) -> Result<(), ErrorGuara
     // {incr-comp-dir}/{crate-name-and-disambiguator}
     let crate_dir = crate_path(sess);
     debug!("crate-dir: {}", crate_dir.display());
-    create_dir(sess, &crate_dir, "crate")?;
+    create_dir(sess, &crate_dir, "crate");
 
     // Hack: canonicalize the path *after creating the directory*
     // because, on windows, long paths can cause problems;
@@ -233,7 +232,7 @@ pub(crate) fn prepare_session_directory(sess: &Session) -> Result<(), ErrorGuara
     let crate_dir = match try_canonicalize(&crate_dir) {
         Ok(v) => v,
         Err(err) => {
-            return Err(sess.dcx().emit_err(errors::CanonicalizePath { path: crate_dir, err }));
+            sess.dcx().emit_fatal(errors::CanonicalizePath { path: crate_dir, err });
         }
     };
 
@@ -248,11 +247,11 @@ pub(crate) fn prepare_session_directory(sess: &Session) -> Result<(), ErrorGuara
 
         // Lock the new session directory. If this fails, return an
         // error without retrying
-        let (directory_lock, lock_file_path) = lock_directory(sess, &session_dir)?;
+        let (directory_lock, lock_file_path) = lock_directory(sess, &session_dir);
 
         // Now that we have the lock, we can actually create the session
         // directory
-        create_dir(sess, &session_dir, "session")?;
+        create_dir(sess, &session_dir, "session");
 
         // Find a suitable source directory to copy from. Ignore those that we
         // have already tried before.
@@ -266,7 +265,7 @@ pub(crate) fn prepare_session_directory(sess: &Session) -> Result<(), ErrorGuara
             );
 
             sess.init_incr_comp_session(session_dir, directory_lock);
-            return Ok(());
+            return;
         };
 
         debug!("attempting to copy data from source: {}", source_directory.display());
@@ -280,7 +279,7 @@ pub(crate) fn prepare_session_directory(sess: &Session) -> Result<(), ErrorGuara
             }
 
             sess.init_incr_comp_session(session_dir, directory_lock);
-            return Ok(());
+            return;
         } else {
             debug!("copying failed - trying next directory");
 
@@ -459,21 +458,17 @@ fn generate_session_dir_path(crate_dir: &Path) -> PathBuf {
     directory_path
 }
 
-fn create_dir(sess: &Session, path: &Path, dir_tag: &str) -> Result<(), ErrorGuaranteed> {
+fn create_dir(sess: &Session, path: &Path, dir_tag: &str) {
     match std_fs::create_dir_all(path) {
         Ok(()) => {
             debug!("{} directory created successfully", dir_tag);
-            Ok(())
         }
-        Err(err) => Err(sess.dcx().emit_err(errors::CreateIncrCompDir { tag: dir_tag, path, err })),
+        Err(err) => sess.dcx().emit_fatal(errors::CreateIncrCompDir { tag: dir_tag, path, err }),
     }
 }
 
 /// Allocate the lock-file and lock it.
-fn lock_directory(
-    sess: &Session,
-    session_dir: &Path,
-) -> Result<(flock::Lock, PathBuf), ErrorGuaranteed> {
+fn lock_directory(sess: &Session, session_dir: &Path) -> (flock::Lock, PathBuf) {
     let lock_file_path = lock_file_path(session_dir);
     debug!("lock_directory() - lock_file: {}", lock_file_path.display());
 
@@ -484,15 +479,15 @@ fn lock_directory(
         true,
     ) {
         // the lock should be exclusive
-        Ok(lock) => Ok((lock, lock_file_path)),
+        Ok(lock) => (lock, lock_file_path),
         Err(lock_err) => {
             let is_unsupported_lock = flock::Lock::error_unsupported(&lock_err);
-            Err(sess.dcx().emit_err(errors::CreateLock {
+            sess.dcx().emit_fatal(errors::CreateLock {
                 lock_err,
                 session_dir,
                 is_unsupported_lock,
                 is_cargo: rustc_session::utils::was_invoked_from_cargo(),
-            }))
+            });
         }
     }
 }
diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs
index c74804cc798..48df84f3d09 100644
--- a/compiler/rustc_incremental/src/persist/load.rs
+++ b/compiler/rustc_incremental/src/persist/load.rs
@@ -11,7 +11,6 @@ use rustc_serialize::Decodable;
 use rustc_serialize::opaque::MemDecoder;
 use rustc_session::Session;
 use rustc_session::config::IncrementalStateAssertion;
-use rustc_span::ErrorGuaranteed;
 use tracing::{debug, warn};
 
 use super::data::*;
@@ -182,7 +181,7 @@ fn load_dep_graph(sess: &Session) -> LoadResult<(Arc<SerializedDepGraph>, WorkPr
 /// If we are not in incremental compilation mode, returns `None`.
 /// Otherwise, tries to load the query result cache from disk,
 /// creating an empty cache if it could not be loaded.
-pub fn load_query_result_cache(sess: &Session) -> Option<OnDiskCache<'_>> {
+pub fn load_query_result_cache(sess: &Session) -> Option<OnDiskCache> {
     if sess.opts.incremental.is_none() {
         return None;
     }
@@ -194,19 +193,19 @@ pub fn load_query_result_cache(sess: &Session) -> Option<OnDiskCache<'_>> {
         LoadResult::Ok { data: (bytes, start_pos) } => {
             let cache = OnDiskCache::new(sess, bytes, start_pos).unwrap_or_else(|()| {
                 sess.dcx().emit_warn(errors::CorruptFile { path: &path });
-                OnDiskCache::new_empty(sess.source_map())
+                OnDiskCache::new_empty()
             });
             Some(cache)
         }
-        _ => Some(OnDiskCache::new_empty(sess.source_map())),
+        _ => Some(OnDiskCache::new_empty()),
     }
 }
 
 /// Setups the dependency graph by loading an existing graph from disk and set up streaming of a
 /// new graph to an incremental session directory.
-pub fn setup_dep_graph(sess: &Session) -> Result<DepGraph, ErrorGuaranteed> {
+pub fn setup_dep_graph(sess: &Session) -> DepGraph {
     // `load_dep_graph` can only be called after `prepare_session_directory`.
-    prepare_session_directory(sess)?;
+    prepare_session_directory(sess);
 
     let res = sess.opts.build_dep_graph().then(|| load_dep_graph(sess));
 
@@ -222,10 +221,9 @@ pub fn setup_dep_graph(sess: &Session) -> Result<DepGraph, ErrorGuaranteed> {
         });
     }
 
-    Ok(res
-        .and_then(|result| {
-            let (prev_graph, prev_work_products) = result.open(sess);
-            build_dep_graph(sess, prev_graph, prev_work_products)
-        })
-        .unwrap_or_else(DepGraph::new_disabled))
+    res.and_then(|result| {
+        let (prev_graph, prev_work_products) = result.open(sess);
+        build_dep_graph(sess, prev_graph, prev_work_products)
+    })
+    .unwrap_or_else(DepGraph::new_disabled)
 }
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 3920d3077d3..07ae24ee6d3 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -5,9 +5,9 @@ use std::sync::Arc;
 use rustc_ast::{LitKind, MetaItemKind, token};
 use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::jobserver;
 use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_data_structures::sync::Lrc;
-use rustc_data_structures::{defer, jobserver};
 use rustc_errors::registry::Registry;
 use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed};
 use rustc_lint::LintStore;
@@ -441,7 +441,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
                     temps_dir,
                 },
                 bundle,
-                config.registry.clone(),
+                config.registry,
                 locale_resources,
                 config.lint_caps,
                 target,
@@ -492,32 +492,34 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
 
             // There are two paths out of `f`.
             // - Normal exit.
-            // - Panic, e.g. triggered by `abort_if_errors`.
+            // - Panic, e.g. triggered by `abort_if_errors` or a fatal error.
             //
             // We must run `finish_diagnostics` in both cases.
-            let res = {
-                // If `f` panics, `finish_diagnostics` will run during
-                // unwinding because of the `defer`.
-                let sess_abort_guard = defer(|| {
-                    compiler.sess.finish_diagnostics(&config.registry);
-                });
-
-                let res = f(&compiler);
-
-                // If `f` doesn't panic, `finish_diagnostics` will run
-                // normally when `sess_abort_guard` is dropped.
-                drop(sess_abort_guard);
-
-                // If error diagnostics have been emitted, we can't return an
-                // error directly, because the return type of this function
-                // is `R`, not `Result<R, E>`. But we need to communicate the
-                // errors' existence to the caller, otherwise the caller might
-                // mistakenly think that no errors occurred and return a zero
-                // exit code. So we abort (panic) instead, similar to if `f`
-                // had panicked.
+            let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f(&compiler)));
+
+            compiler.sess.finish_diagnostics();
+
+            // If error diagnostics have been emitted, we can't return an
+            // error directly, because the return type of this function
+            // is `R`, not `Result<R, E>`. But we need to communicate the
+            // errors' existence to the caller, otherwise the caller might
+            // mistakenly think that no errors occurred and return a zero
+            // exit code. So we abort (panic) instead, similar to if `f`
+            // had panicked.
+            if res.is_ok() {
                 compiler.sess.dcx().abort_if_errors();
+            }
+
+            // Also make sure to flush delayed bugs as if we panicked, the
+            // bugs would be flushed by the Drop impl of DiagCtxt while
+            // unwinding, which would result in an abort with
+            // "panic in a destructor during cleanup".
+            compiler.sess.dcx().flush_delayed();
 
-                res
+            let res = match res {
+                Ok(res) => res,
+                // Resume unwinding if a panic happened.
+                Err(err) => std::panic::resume_unwind(err),
             };
 
             let prof = compiler.sess.prof.clone();
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index f53c7b5cc2d..62f35333015 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -33,15 +33,15 @@ use rustc_session::output::{collect_crate_types, filename_for_input, find_crate_
 use rustc_session::search_paths::PathKind;
 use rustc_session::{Limit, Session};
 use rustc_span::symbol::{Symbol, sym};
-use rustc_span::{FileName, SourceFileHash, SourceFileHashAlgorithm};
+use rustc_span::{ErrorGuaranteed, FileName, SourceFileHash, SourceFileHashAlgorithm};
 use rustc_target::spec::PanicStrategy;
 use rustc_trait_selection::traits;
 use tracing::{info, instrument};
 
-use crate::interface::{Compiler, Result};
+use crate::interface::Compiler;
 use crate::{errors, proc_macro_decls, util};
 
-pub(crate) fn parse<'a>(sess: &'a Session) -> Result<ast::Crate> {
+pub(crate) fn parse<'a>(sess: &'a Session) -> ast::Crate {
     let krate = sess
         .time("parse_crate", || {
             let mut parser = unwrap_or_emit_fatal(match &sess.io.input {
@@ -52,13 +52,16 @@ pub(crate) fn parse<'a>(sess: &'a Session) -> Result<ast::Crate> {
             });
             parser.parse_crate_mod()
         })
-        .map_err(|parse_error| parse_error.emit())?;
+        .unwrap_or_else(|parse_error| {
+            let guar: ErrorGuaranteed = parse_error.emit();
+            guar.raise_fatal();
+        });
 
     if sess.opts.unstable_opts.input_stats {
         input_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS", "ast-stats-1");
     }
 
-    Ok(krate)
+    krate
 }
 
 fn pre_expansion_lint<'a>(
@@ -712,7 +715,7 @@ pub(crate) fn create_global_ctxt<'tcx>(
     gcx_cell: &'tcx OnceLock<GlobalCtxt<'tcx>>,
     arena: &'tcx WorkerLocal<Arena<'tcx>>,
     hir_arena: &'tcx WorkerLocal<rustc_hir::Arena<'tcx>>,
-) -> Result<&'tcx GlobalCtxt<'tcx>> {
+) -> &'tcx GlobalCtxt<'tcx> {
     let sess = &compiler.sess;
 
     rustc_builtin_macros::cmdline_attrs::inject(
@@ -733,7 +736,7 @@ pub(crate) fn create_global_ctxt<'tcx>(
         sess.cfg_version,
     );
     let outputs = util::build_output_filenames(&pre_configured_attrs, sess);
-    let dep_graph = setup_dep_graph(sess)?;
+    let dep_graph = setup_dep_graph(sess);
 
     let cstore =
         FreezeLock::new(Box::new(CStore::new(compiler.codegen_backend.metadata_loader())) as _);
@@ -796,7 +799,7 @@ pub(crate) fn create_global_ctxt<'tcx>(
             feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs))));
             feed.output_filenames(Arc::new(outputs));
         });
-        Ok(qcx)
+        qcx
     })
 }
 
@@ -906,7 +909,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
 
 /// Runs the type-checking, region checking and other miscellaneous analysis
 /// passes on the crate.
-fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
+fn analysis(tcx: TyCtxt<'_>, (): ()) {
     run_required_analyses(tcx);
 
     let sess = tcx.sess;
@@ -920,7 +923,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
     // But we exclude lint errors from this, because lint errors are typically
     // less serious and we're more likely to want to continue (#87337).
     if let Some(guar) = sess.dcx().has_errors_excluding_lint_errors() {
-        return Err(guar);
+        guar.raise_fatal();
     }
 
     sess.time("misc_checking_3", || {
@@ -1048,8 +1051,6 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
             })
         }
     }
-
-    Ok(())
 }
 
 /// Check for the `#[rustc_error]` annotation, which forces an error in codegen. This is used
@@ -1091,12 +1092,12 @@ fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) {
 pub(crate) fn start_codegen<'tcx>(
     codegen_backend: &dyn CodegenBackend,
     tcx: TyCtxt<'tcx>,
-) -> Result<Box<dyn Any>> {
+) -> Box<dyn Any> {
     // Don't do code generation if there were any errors. Likewise if
     // there were any delayed bugs, because codegen will likely cause
     // more ICEs, obscuring the original problem.
     if let Some(guar) = tcx.sess.dcx().has_errors_or_delayed_bugs() {
-        return Err(guar);
+        guar.raise_fatal();
     }
 
     // Hook for UI tests.
@@ -1124,7 +1125,7 @@ pub(crate) fn start_codegen<'tcx>(
         }
     }
 
-    Ok(codegen)
+    codegen
 }
 
 fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit {
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index cd3a2fb7049..7e3a1332630 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -16,7 +16,7 @@ use rustc_session::Session;
 use rustc_session::config::{self, OutputFilenames, OutputType};
 
 use crate::errors::FailedWritingFile;
-use crate::interface::{Compiler, Result};
+use crate::interface::Compiler;
 use crate::passes;
 
 /// Represent the result of a query.
@@ -27,19 +27,17 @@ use crate::passes;
 /// [`compute`]: Self::compute
 pub struct Query<T> {
     /// `None` means no value has been computed yet.
-    result: RefCell<Option<Result<Steal<T>>>>,
+    result: RefCell<Option<Steal<T>>>,
 }
 
 impl<T> Query<T> {
-    fn compute<F: FnOnce() -> Result<T>>(&self, f: F) -> Result<QueryResult<'_, T>> {
-        RefMut::filter_map(
+    fn compute<F: FnOnce() -> T>(&self, f: F) -> QueryResult<'_, T> {
+        QueryResult(RefMut::map(
             self.result.borrow_mut(),
-            |r: &mut Option<Result<Steal<T>>>| -> Option<&mut Steal<T>> {
-                r.get_or_insert_with(|| f().map(Steal::new)).as_mut().ok()
+            |r: &mut Option<Steal<T>>| -> &mut Steal<T> {
+                r.get_or_insert_with(|| Steal::new(f()))
             },
-        )
-        .map_err(|r| *r.as_ref().unwrap().as_ref().map(|_| ()).unwrap_err())
-        .map(QueryResult)
+        ))
     }
 }
 
@@ -95,13 +93,13 @@ impl<'tcx> Queries<'tcx> {
         }
     }
 
-    pub fn parse(&self) -> Result<QueryResult<'_, ast::Crate>> {
+    pub fn parse(&self) -> QueryResult<'_, ast::Crate> {
         self.parse.compute(|| passes::parse(&self.compiler.sess))
     }
 
-    pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'tcx, &'tcx GlobalCtxt<'tcx>>> {
+    pub fn global_ctxt(&'tcx self) -> QueryResult<'tcx, &'tcx GlobalCtxt<'tcx>> {
         self.gcx.compute(|| {
-            let krate = self.parse()?.steal();
+            let krate = self.parse().steal();
 
             passes::create_global_ctxt(
                 self.compiler,
@@ -126,8 +124,8 @@ impl Linker {
     pub fn codegen_and_build_linker(
         tcx: TyCtxt<'_>,
         codegen_backend: &dyn CodegenBackend,
-    ) -> Result<Linker> {
-        let ongoing_codegen = passes::start_codegen(codegen_backend, tcx)?;
+    ) -> Linker {
+        let ongoing_codegen = passes::start_codegen(codegen_backend, tcx);
 
         // This must run after monomorphization so that all generic types
         // have been instantiated.
@@ -141,7 +139,7 @@ impl Linker {
             tcx.sess.code_stats.print_vtable_sizes(crate_name);
         }
 
-        Ok(Linker {
+        Linker {
             dep_graph: tcx.dep_graph.clone(),
             output_filenames: Arc::clone(tcx.output_filenames(())),
             crate_hash: if tcx.needs_crate_hash() {
@@ -150,16 +148,17 @@ impl Linker {
                 None
             },
             ongoing_codegen,
-        })
+        }
     }
 
-    pub fn link(self, sess: &Session, codegen_backend: &dyn CodegenBackend) -> Result<()> {
-        let (codegen_results, work_products) =
-            codegen_backend.join_codegen(self.ongoing_codegen, sess, &self.output_filenames);
+    pub fn link(self, sess: &Session, codegen_backend: &dyn CodegenBackend) {
+        let (codegen_results, work_products) = sess.time("finish_ongoing_codegen", || {
+            codegen_backend.join_codegen(self.ongoing_codegen, sess, &self.output_filenames)
+        });
 
-        if let Some(guar) = sess.dcx().has_errors() {
-            return Err(guar);
-        }
+        sess.dcx().abort_if_errors();
+
+        let _timer = sess.timer("link");
 
         sess.time("serialize_work_products", || {
             rustc_incremental::save_work_product_index(sess, &self.dep_graph, work_products)
@@ -178,7 +177,7 @@ impl Linker {
             .keys()
             .any(|&i| i == OutputType::Exe || i == OutputType::Metadata)
         {
-            return Ok(());
+            return;
         }
 
         if sess.opts.unstable_opts.no_link {
@@ -189,10 +188,10 @@ impl Linker {
                 &codegen_results,
                 &*self.output_filenames,
             )
-            .map_err(|error| {
+            .unwrap_or_else(|error| {
                 sess.dcx().emit_fatal(FailedWritingFile { path: &rlink_file, error })
-            })?;
-            return Ok(());
+            });
+            return;
         }
 
         let _timer = sess.prof.verbose_generic_activity("link_crate");
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 49e6b763590..422629cd11d 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -359,7 +359,6 @@ lint_improper_ctypes_128bit = 128-bit integers don't currently have a known stab
 lint_improper_ctypes_array_help = consider passing a pointer to the array
 
 lint_improper_ctypes_array_reason = passing raw arrays by value is not FFI-safe
-lint_improper_ctypes_box = box cannot be represented as a single pointer
 
 lint_improper_ctypes_char_help = consider using `u32` or `libc::wchar_t` instead
 
@@ -377,7 +376,9 @@ lint_improper_ctypes_enum_repr_help =
 lint_improper_ctypes_enum_repr_reason = enum has no representation hint
 lint_improper_ctypes_fnptr_help = consider using an `extern fn(...) -> ...` function pointer instead
 
+lint_improper_ctypes_fnptr_indirect_reason = the function pointer to `{$ty}` is FFI-unsafe due to `{$inner_ty}`
 lint_improper_ctypes_fnptr_reason = this function pointer has Rust-specific calling convention
+
 lint_improper_ctypes_non_exhaustive = this enum is non-exhaustive
 lint_improper_ctypes_non_exhaustive_variant = this enum has non-exhaustive variants
 
@@ -388,7 +389,11 @@ lint_improper_ctypes_opaque = opaque types have no C equivalent
 lint_improper_ctypes_pat_help = consider using the base type instead
 
 lint_improper_ctypes_pat_reason = pattern types have no C equivalent
-lint_improper_ctypes_slice_help = consider using a raw pointer instead
+
+lint_improper_ctypes_sized_ptr_to_unsafe_type =
+    this reference (`{$ty}`) is ABI-compatible with a C pointer, but `{$inner_ty}` itself does not have a C layout
+
+lint_improper_ctypes_slice_help = consider using a raw pointer to the slice's first element (and a length) instead
 
 lint_improper_ctypes_slice_reason = slices have no C equivalent
 lint_improper_ctypes_str_help = consider using `*const u8` and a length instead
@@ -414,6 +419,10 @@ lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[re
 lint_improper_ctypes_union_layout_reason = this union has unspecified layout
 lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive
 
+lint_improper_ctypes_unsized_box = this box for an unsized type contains metadata, which makes it incompatible with a C pointer
+lint_improper_ctypes_unsized_ptr = this pointer to an unsized type contains metadata, which makes it incompatible with a C pointer
+lint_improper_ctypes_unsized_ref = this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
+
 lint_incomplete_include =
     include macro expected single expression in source
 
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index 4f3184f1d7c..a68a2a7f983 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -245,6 +245,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
 
     fn visit_lifetime(&mut self, lt: &'a ast::Lifetime, _: ast_visit::LifetimeCtxt) {
         self.check_id(lt.id);
+        ast_visit::walk_lifetime(self, lt);
     }
 
     fn visit_path(&mut self, p: &'a ast::Path, id: ast::NodeId) {
@@ -259,6 +260,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
 
     fn visit_attribute(&mut self, attr: &'a ast::Attribute) {
         lint_callback!(self, check_attribute, attr);
+        ast_visit::walk_attribute(self, attr);
     }
 
     fn visit_mac_def(&mut self, mac: &'a ast::MacroDef, id: ast::NodeId) {
diff --git a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs
index 025fd452040..28368e1ab46 100644
--- a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs
+++ b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs
@@ -9,6 +9,7 @@ use crate::lints::{
 use crate::{EarlyContext, EarlyLintPass, LintContext};
 
 declare_lint! {
+    #[allow(text_direction_codepoint_in_literal)]
     /// The `text_direction_codepoint_in_literal` lint detects Unicode codepoints that change the
     /// visual representation of text on screen in a way that does not correspond to their on
     /// memory representation.
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 20822f23bf1..9fa263799eb 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -1851,13 +1851,44 @@ pub(crate) struct UnpredictableFunctionPointerComparisonsSuggestion<'a> {
     pub right: Span,
 }
 
+pub(crate) struct ImproperCTypesLayer<'a> {
+    pub ty: Ty<'a>,
+    pub inner_ty: Option<Ty<'a>>,
+    pub note: DiagMessage,
+    pub span_note: Option<Span>,
+    pub help: Option<DiagMessage>,
+}
+
+impl<'a> Subdiagnostic for ImproperCTypesLayer<'a> {
+    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
+        self,
+        diag: &mut Diag<'_, G>,
+        f: &F,
+    ) {
+        diag.arg("ty", self.ty);
+        if let Some(ty) = self.inner_ty {
+            diag.arg("inner_ty", ty);
+        }
+
+        if let Some(help) = self.help {
+            let msg = f(diag, help.into());
+            diag.help(msg);
+        }
+
+        let msg = f(diag, self.note.into());
+        diag.note(msg);
+        if let Some(note) = self.span_note {
+            let msg = f(diag, fluent::lint_note.into());
+            diag.span_note(note, msg);
+        };
+    }
+}
+
 pub(crate) struct ImproperCTypes<'a> {
     pub ty: Ty<'a>,
     pub desc: &'a str,
     pub label: Span,
-    pub help: Option<DiagMessage>,
-    pub note: DiagMessage,
-    pub span_note: Option<Span>,
+    pub reasons: Vec<ImproperCTypesLayer<'a>>,
 }
 
 // Used because of the complexity of Option<DiagMessage>, DiagMessage, and Option<Span>
@@ -1867,12 +1898,8 @@ impl<'a> LintDiagnostic<'a, ()> for ImproperCTypes<'_> {
         diag.arg("ty", self.ty);
         diag.arg("desc", self.desc);
         diag.span_label(self.label, fluent::lint_label);
-        if let Some(help) = self.help {
-            diag.help(help);
-        }
-        diag.note(self.note);
-        if let Some(note) = self.span_note {
-            diag.span_note(note, fluent::lint_note);
+        for reason in self.reasons.into_iter() {
+            diag.subdiagnostic(reason);
         }
     }
 }
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 33650be056d..90d44371ab5 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -22,10 +22,10 @@ mod improper_ctypes;
 use crate::lints::{
     AmbiguousWidePointerComparisons, AmbiguousWidePointerComparisonsAddrMetadataSuggestion,
     AmbiguousWidePointerComparisonsAddrSuggestion, AtomicOrderingFence, AtomicOrderingLoad,
-    AtomicOrderingStore, ImproperCTypes, InvalidAtomicOrderingDiag, InvalidNanComparisons,
-    InvalidNanComparisonsSuggestion, UnpredictableFunctionPointerComparisons,
-    UnpredictableFunctionPointerComparisonsSuggestion, UnusedComparisons,
-    VariantSizeDifferencesDiag,
+    AtomicOrderingStore, ImproperCTypes, ImproperCTypesLayer, InvalidAtomicOrderingDiag,
+    InvalidNanComparisons, InvalidNanComparisonsSuggestion,
+    UnpredictableFunctionPointerComparisons, UnpredictableFunctionPointerComparisonsSuggestion,
+    UnusedComparisons, VariantSizeDifferencesDiag,
 };
 use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
 
@@ -727,7 +727,109 @@ struct CTypesVisitorState<'tcx> {
 enum FfiResult<'tcx> {
     FfiSafe,
     FfiPhantom(Ty<'tcx>),
-    FfiUnsafe { ty: Ty<'tcx>, reason: DiagMessage, help: Option<DiagMessage> },
+    FfiUnsafe {
+        ty: Ty<'tcx>,
+        reason: DiagMessage,
+        help: Option<DiagMessage>,
+    },
+    FfiUnsafeWrapper {
+        ty: Ty<'tcx>,
+        reason: DiagMessage,
+        help: Option<DiagMessage>,
+        wrapped: Box<FfiResult<'tcx>>,
+    },
+}
+
+/// Determine if a type is sized or not, and wether it affects references/pointers/boxes to it
+#[derive(Clone, Copy)]
+enum TypeSizedness {
+    /// type of definite size (pointers are C-compatible)
+    Definite,
+    /// unsized type because it includes an opaque/foreign type (pointers are C-compatible)
+    UnsizedWithExternType,
+    /// unsized type for other reasons (slice, string, dyn Trait, closure, ...) (pointers are not C-compatible)
+    UnsizedWithMetadata,
+}
+
+/// Is this type unsized because it contains (or is) a foreign type?
+/// (Returns Err if the type happens to be sized after all)
+fn get_type_sizedness<'tcx, 'a>(cx: &'a LateContext<'tcx>, ty: Ty<'tcx>) -> TypeSizedness {
+    let tcx = cx.tcx;
+
+    if ty.is_sized(tcx, cx.typing_env()) {
+        TypeSizedness::Definite
+    } else {
+        match ty.kind() {
+            ty::Slice(_) => TypeSizedness::UnsizedWithMetadata,
+            ty::Str => TypeSizedness::UnsizedWithMetadata,
+            ty::Dynamic(..) => TypeSizedness::UnsizedWithMetadata,
+            ty::Foreign(..) => TypeSizedness::UnsizedWithExternType,
+            // While opaque types are checked for earlier, if a projection in a struct field
+            // normalizes to an opaque type, then it will reach this branch.
+            ty::Alias(ty::Opaque, ..) => todo!("We... don't know enough about this type yet?"),
+            ty::Adt(def, args) => {
+                // for now assume: boxes and phantoms don't mess with this
+                match def.adt_kind() {
+                    AdtKind::Union | AdtKind::Enum => {
+                        bug!("unions and enums are necessarily sized")
+                    }
+                    AdtKind::Struct => {
+                        if let Some(sym::cstring_type | sym::cstr_type) =
+                            tcx.get_diagnostic_name(def.did())
+                        {
+                            return TypeSizedness::UnsizedWithMetadata;
+                        }
+                        // FIXME: how do we deal with non-exhaustive unsized structs/unions?
+
+                        if def.non_enum_variant().fields.is_empty() {
+                            bug!("an empty struct is necessarily sized");
+                        }
+
+                        let variant = def.non_enum_variant();
+
+                        // only the last field may be unsized
+                        let n_fields = variant.fields.len();
+                        let last_field = &variant.fields[(n_fields - 1).into()];
+                        let field_ty = last_field.ty(cx.tcx, args);
+                        let field_ty = cx
+                            .tcx
+                            .try_normalize_erasing_regions(cx.typing_env(), field_ty)
+                            .unwrap_or(field_ty);
+                        match get_type_sizedness(cx, field_ty) {
+                            s @ (TypeSizedness::UnsizedWithMetadata
+                            | TypeSizedness::UnsizedWithExternType) => s,
+                            TypeSizedness::Definite => {
+                                bug!("failed to find the reason why struct `{:?}` is unsized", ty)
+                            }
+                        }
+                    }
+                }
+            }
+            ty::Tuple(tuple) => {
+                // only the last field may be unsized
+                let n_fields = tuple.len();
+                let field_ty: Ty<'tcx> = tuple[n_fields - 1];
+                //let field_ty = last_field.ty(cx.tcx, args);
+                let field_ty = cx
+                    .tcx
+                    .try_normalize_erasing_regions(cx.typing_env(), field_ty)
+                    .unwrap_or(field_ty);
+                match get_type_sizedness(cx, field_ty) {
+                    s @ (TypeSizedness::UnsizedWithMetadata
+                    | TypeSizedness::UnsizedWithExternType) => s,
+                    TypeSizedness::Definite => {
+                        bug!("failed to find the reason why tuple `{:?}` is unsized", ty)
+                    }
+                }
+            }
+            ty => {
+                bug!(
+                    "we shouldn't be trying to determine if this is unsized for a reason or another: `{:?}`",
+                    ty
+                )
+            }
+        }
+    }
 }
 
 pub(crate) fn nonnull_optimization_guaranteed<'tcx>(
@@ -764,7 +866,7 @@ fn ty_is_known_nonnull<'tcx>(
     match ty.kind() {
         ty::FnPtr(..) => true,
         ty::Ref(..) => true,
-        ty::Adt(def, _) if def.is_box() && matches!(mode, CItemKind::Definition) => true,
+        ty::Adt(def, _) if def.is_box() => true,
         ty::Adt(def, args) if def.repr().transparent() && !def.is_union() => {
             let marked_non_null = nonnull_optimization_guaranteed(tcx, *def);
 
@@ -933,12 +1035,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
     /// Check if the type is array and emit an unsafe type lint.
     fn check_for_array_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
         if let ty::Array(..) = ty.kind() {
-            self.emit_ffi_unsafe_type_lint(
+            self.emit_ffi_unsafe_type_lint(ty.clone(), sp, vec![ImproperCTypesLayer {
                 ty,
-                sp,
-                fluent::lint_improper_ctypes_array_reason,
-                Some(fluent::lint_improper_ctypes_array_help),
-            );
+                note: fluent::lint_improper_ctypes_array_reason,
+                help: Some(fluent::lint_improper_ctypes_array_help),
+                inner_ty: None,
+                span_note: None,
+            }]);
             true
         } else {
             false
@@ -995,9 +1098,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             all_phantom &= match self.check_field_type_for_ffi(acc, field, args) {
                 FfiSafe => false,
                 // `()` fields are FFI-safe!
-                FfiUnsafe { ty, .. } if ty.is_unit() => false,
+                FfiUnsafe { ty, .. } | FfiUnsafeWrapper { ty, .. } if ty.is_unit() => false,
                 FfiPhantom(..) => true,
-                r @ FfiUnsafe { .. } => return r,
+                r @ (FfiUnsafe { .. } | FfiUnsafeWrapper { .. }) => return r,
             }
         }
 
@@ -1031,16 +1134,47 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
 
         match *ty.kind() {
             ty::Adt(def, args) => {
-                if let Some(boxed) = ty.boxed_ty()
-                    && matches!(self.mode, CItemKind::Definition)
-                {
-                    if boxed.is_sized(tcx, self.cx.typing_env()) {
-                        return FfiSafe;
+                if let Some(inner_ty) = ty.boxed_ty() {
+                    if let TypeSizedness::UnsizedWithExternType | TypeSizedness::Definite =
+                        get_type_sizedness(self.cx, inner_ty)
+                    {
+                        // discussion on declaration vs definition:
+                        // see the `ty::RawPtr(inner_ty, _) | ty::Ref(_, inner_ty, _)` arm
+                        // of this `match *ty.kind()` block
+                        if matches!(self.mode, CItemKind::Definition) {
+                            return FfiSafe;
+                        } else {
+                            let inner_res = self.check_type_for_ffi(acc, inner_ty);
+                            return match inner_res {
+                                FfiUnsafe { .. } | FfiUnsafeWrapper { .. } => FfiUnsafeWrapper {
+                                    ty,
+                                    reason: fluent::lint_improper_ctypes_sized_ptr_to_unsafe_type,
+                                    wrapped: Box::new(inner_res),
+                                    help: None,
+                                },
+                                _ => inner_res,
+                            };
+                        }
                     } else {
+                        let help = match inner_ty.kind() {
+                            ty::Str => Some(fluent::lint_improper_ctypes_str_help),
+                            ty::Slice(_) => Some(fluent::lint_improper_ctypes_slice_help),
+                            ty::Adt(def, _)
+                                if matches!(def.adt_kind(), AdtKind::Struct | AdtKind::Union)
+                                    && matches!(
+                                        tcx.get_diagnostic_name(def.did()),
+                                        Some(sym::cstring_type | sym::cstr_type)
+                                    )
+                                    && !acc.base_ty.is_mutable_ptr() =>
+                            {
+                                Some(fluent::lint_improper_ctypes_cstr_help)
+                            }
+                            _ => None,
+                        };
                         return FfiUnsafe {
                             ty,
-                            reason: fluent::lint_improper_ctypes_box,
-                            help: None,
+                            reason: fluent::lint_improper_ctypes_unsized_box,
+                            help,
                         };
                     }
                 }
@@ -1196,15 +1330,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 help: Some(fluent::lint_improper_ctypes_tuple_help),
             },
 
-            ty::RawPtr(ty, _) | ty::Ref(_, ty, _)
-                if {
-                    matches!(self.mode, CItemKind::Definition)
-                        && ty.is_sized(self.cx.tcx, self.cx.typing_env())
-                } =>
-            {
-                FfiSafe
-            }
-
             ty::RawPtr(ty, _)
                 if match ty.kind() {
                     ty::Tuple(tuple) => tuple.is_empty(),
@@ -1214,7 +1339,70 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 FfiSafe
             }
 
-            ty::RawPtr(ty, _) | ty::Ref(_, ty, _) => self.check_type_for_ffi(acc, ty),
+            ty::RawPtr(inner_ty, _) | ty::Ref(_, inner_ty, _) => {
+                if let TypeSizedness::UnsizedWithExternType | TypeSizedness::Definite =
+                    get_type_sizedness(self.cx, inner_ty)
+                {
+                    // there's a nuance on what this lint should do for
+                    // function definitions (`extern "C" fn fn_name(...) {...}`)
+                    // versus declarations (`unsafe extern "C" {fn fn_name(...);}`).
+                    // This is touched upon in https://github.com/rust-lang/rust/issues/66220
+                    // and https://github.com/rust-lang/rust/pull/72700
+                    //
+                    // The big question is: what does "ABI safety" mean? if you have something translated to a C pointer
+                    // (which has a stable layout) but points to FFI-unsafe type, is it safe?
+                    // On one hand, the function's ABI will match that of a similar C-declared function API,
+                    // on the other, dereferencing the pointer on the other side of the FFI boundary will be painful.
+                    // In this code, the opinion on is split between function declarations and function definitions,
+                    // with the idea that at least one side of the FFI boundary needs to treat the pointee as an opaque type.
+                    // For declarations, we see this as unsafe, but for definitions, we see this as safe.
+                    //
+                    // For extern function declarations, the actual definition of the function is written somewhere else,
+                    // meaning the declaration is free to express this opaqueness with an extern type (opaque caller-side) or a std::ffi::c_void (opaque callee-side)
+                    // For extern function definitions, however, in the case where the type is opaque caller-side, it is not opaque callee-side,
+                    // and having the full type information is necessary to compile the function.
+                    if matches!(self.mode, CItemKind::Definition) {
+                        return FfiSafe;
+                    } else if matches!(ty.kind(), ty::RawPtr(..))
+                        && matches!(inner_ty.kind(), ty::Tuple(tuple) if tuple.is_empty())
+                    {
+                        FfiSafe
+                    } else {
+                        let inner_res = self.check_type_for_ffi(acc, inner_ty);
+                        return match inner_res {
+                            FfiSafe => inner_res,
+                            _ => FfiUnsafeWrapper {
+                                ty,
+                                reason: fluent::lint_improper_ctypes_sized_ptr_to_unsafe_type,
+                                wrapped: Box::new(inner_res),
+                                help: None,
+                            },
+                        };
+                    }
+                } else {
+                    let help = match inner_ty.kind() {
+                        ty::Str => Some(fluent::lint_improper_ctypes_str_help),
+                        ty::Slice(_) => Some(fluent::lint_improper_ctypes_slice_help),
+                        ty::Adt(def, _)
+                            if matches!(def.adt_kind(), AdtKind::Struct | AdtKind::Union)
+                                && matches!(
+                                    tcx.get_diagnostic_name(def.did()),
+                                    Some(sym::cstring_type | sym::cstr_type)
+                                )
+                                && !acc.base_ty.is_mutable_ptr() =>
+                        {
+                            Some(fluent::lint_improper_ctypes_cstr_help)
+                        }
+                        _ => None,
+                    };
+                    let reason = match ty.kind() {
+                        ty::RawPtr(..) => fluent::lint_improper_ctypes_unsized_ptr,
+                        ty::Ref(..) => fluent::lint_improper_ctypes_unsized_ref,
+                        _ => unreachable!(),
+                    };
+                    FfiUnsafe { ty, reason, help }
+                }
+            }
 
             ty::Array(inner_ty, _) => self.check_type_for_ffi(acc, inner_ty),
 
@@ -1232,7 +1420,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 for arg in sig.inputs() {
                     match self.check_type_for_ffi(acc, *arg) {
                         FfiSafe => {}
-                        r => return r,
+                        r => {
+                            return FfiUnsafeWrapper {
+                                ty,
+                                reason: fluent::lint_improper_ctypes_fnptr_indirect_reason,
+                                help: None,
+                                wrapped: Box::new(r),
+                            };
+                        }
                     }
                 }
 
@@ -1241,7 +1436,15 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                     return FfiSafe;
                 }
 
-                self.check_type_for_ffi(acc, ret_ty)
+                match self.check_type_for_ffi(acc, ret_ty) {
+                    r @ (FfiSafe | FfiPhantom(_)) => r,
+                    r => FfiUnsafeWrapper {
+                        ty: ty.clone(),
+                        reason: fluent::lint_improper_ctypes_fnptr_indirect_reason,
+                        help: None,
+                        wrapped: Box::new(r),
+                    },
+                }
             }
 
             ty::Foreign(..) => FfiSafe,
@@ -1278,8 +1481,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         &mut self,
         ty: Ty<'tcx>,
         sp: Span,
-        note: DiagMessage,
-        help: Option<DiagMessage>,
+        mut reasons: Vec<ImproperCTypesLayer<'tcx>>,
     ) {
         let lint = match self.mode {
             CItemKind::Declaration => IMPROPER_CTYPES,
@@ -1289,21 +1491,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             CItemKind::Declaration => "block",
             CItemKind::Definition => "fn",
         };
-        let span_note = if let ty::Adt(def, _) = ty.kind()
-            && let Some(sp) = self.cx.tcx.hir().span_if_local(def.did())
-        {
-            Some(sp)
-        } else {
-            None
-        };
-        self.cx.emit_span_lint(lint, sp, ImproperCTypes {
-            ty,
-            desc,
-            label: sp,
-            help,
-            note,
-            span_note,
-        });
+        for reason in reasons.iter_mut() {
+            reason.span_note = if let ty::Adt(def, _) = reason.ty.kind()
+                && let Some(sp) = self.cx.tcx.hir().span_if_local(def.did())
+            {
+                Some(sp)
+            } else {
+                None
+            };
+        }
+
+        self.cx.emit_span_lint(lint, sp, ImproperCTypes { ty, desc, label: sp, reasons });
     }
 
     fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
@@ -1332,7 +1530,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             .visit_with(&mut ProhibitOpaqueTypes)
             .break_value()
         {
-            self.emit_ffi_unsafe_type_lint(ty, sp, fluent::lint_improper_ctypes_opaque, None);
+            self.emit_ffi_unsafe_type_lint(ty.clone(), sp, vec![ImproperCTypesLayer {
+                ty,
+                note: fluent::lint_improper_ctypes_opaque,
+                span_note: Some(sp),
+                help: None,
+                inner_ty: None,
+            }]);
             true
         } else {
             false
@@ -1371,15 +1575,71 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         match self.check_type_for_ffi(&mut acc, ty) {
             FfiResult::FfiSafe => {}
             FfiResult::FfiPhantom(ty) => {
-                self.emit_ffi_unsafe_type_lint(
+                self.emit_ffi_unsafe_type_lint(ty.clone(), sp, vec![ImproperCTypesLayer {
                     ty,
-                    sp,
-                    fluent::lint_improper_ctypes_only_phantomdata,
-                    None,
-                );
+                    note: fluent::lint_improper_ctypes_only_phantomdata,
+                    span_note: None, // filled later
+                    help: None,
+                    inner_ty: None,
+                }]);
             }
             FfiResult::FfiUnsafe { ty, reason, help } => {
-                self.emit_ffi_unsafe_type_lint(ty, sp, reason, help);
+                self.emit_ffi_unsafe_type_lint(ty.clone(), sp, vec![ImproperCTypesLayer {
+                    ty,
+                    help,
+                    note: reason,
+                    span_note: None, // filled later
+                    inner_ty: None,
+                }]);
+            }
+            ffir @ FfiResult::FfiUnsafeWrapper { .. } => {
+                let mut ffiresult_recursor = ControlFlow::Continue(&ffir);
+                let mut cimproper_layers: Vec<ImproperCTypesLayer<'tcx>> = vec![];
+
+                // this whole while block converts the arbitrarily-deep
+                // FfiResult stack to an ImproperCTypesLayer Vec
+                while let ControlFlow::Continue(ref ffir_rec) = ffiresult_recursor {
+                    match ffir_rec {
+                        FfiResult::FfiPhantom(ty) => {
+                            if let Some(layer) = cimproper_layers.last_mut() {
+                                layer.inner_ty = Some(ty.clone());
+                            }
+                            cimproper_layers.push(ImproperCTypesLayer {
+                                ty: ty.clone(),
+                                inner_ty: None,
+                                help: None,
+                                note: fluent::lint_improper_ctypes_only_phantomdata,
+                                span_note: None, // filled later
+                            });
+                            ffiresult_recursor = ControlFlow::Break(());
+                        }
+                        FfiResult::FfiUnsafe { ty, reason, help }
+                        | FfiResult::FfiUnsafeWrapper { ty, reason, help, .. } => {
+                            if let Some(layer) = cimproper_layers.last_mut() {
+                                layer.inner_ty = Some(ty.clone());
+                            }
+                            cimproper_layers.push(ImproperCTypesLayer {
+                                ty: ty.clone(),
+                                inner_ty: None,
+                                help: help.clone(),
+                                note: reason.clone(),
+                                span_note: None, // filled later
+                            });
+
+                            if let FfiResult::FfiUnsafeWrapper { wrapped, .. } = ffir_rec {
+                                ffiresult_recursor = ControlFlow::Continue(wrapped.as_ref());
+                            } else {
+                                ffiresult_recursor = ControlFlow::Break(());
+                            }
+                        }
+                        FfiResult::FfiSafe => {
+                            bug!("malformed FfiResult stack: it should be unsafe all the way down")
+                        }
+                    };
+                }
+                // should always have at least one type
+                let last_ty = cimproper_layers.last().unwrap().ty.clone();
+                self.emit_ffi_unsafe_type_lint(last_ty, sp, cimproper_layers);
             }
         }
     }
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index b775cd37409..9cad5d98562 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -1235,7 +1235,7 @@ impl EarlyLintPass for UnusedParens {
                 self.check_unused_parens_pat(cx, &f.pat, false, false, keep_space);
             },
             // Avoid linting on `i @ (p0 | .. | pn)` and `box (p0 | .. | pn)`, #64106.
-            Ident(.., Some(p)) | Box(p) | Deref(p) => self.check_unused_parens_pat(cx, p, true, false, keep_space),
+            Ident(.., Some(p)) | Box(p) | Deref(p) | Guard(p, _) => self.check_unused_parens_pat(cx, p, true, false, keep_space),
             // Avoid linting on `&(mut x)` as `&mut x` has a different meaning, #55342.
             // Also avoid linting on `& mut? (p0 | .. | pn)`, #64106.
             Ref(p, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not, keep_space),
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index d2b7ae620e2..54e927df3c4 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -3929,6 +3929,7 @@ declare_lint! {
 }
 
 declare_lint! {
+    #[allow(text_direction_codepoint_in_literal)]
     /// The `text_direction_codepoint_in_comment` lint detects Unicode codepoints in comments that
     /// change the visual representation of text on screen in a way that does not correspond to
     /// their on memory representation.
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index d04876d0bef..a3976c3dda1 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -276,7 +276,7 @@ rustc_queries! {
     }
 
     /// The root query triggering all analysis passes like typeck or borrowck.
-    query analysis(key: ()) -> Result<(), ErrorGuaranteed> {
+    query analysis(key: ()) {
         eval_always
         desc { "running analysis passes on this crate" }
     }
diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs
index 3849cb72668..119a99e1bf7 100644
--- a/compiler/rustc_middle/src/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/query/on_disk_cache.rs
@@ -23,7 +23,7 @@ use rustc_session::Session;
 use rustc_span::hygiene::{
     ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, SyntaxContextData,
 };
-use rustc_span::source_map::{SourceMap, Spanned};
+use rustc_span::source_map::Spanned;
 use rustc_span::{
     BytePos, CachingSourceMapView, ExpnData, ExpnHash, Pos, RelativeBytePos, SourceFile, Span,
     SpanDecoder, SpanEncoder, StableSourceFileId, Symbol,
@@ -49,7 +49,7 @@ const SYMBOL_PREINTERNED: u8 = 2;
 /// previous compilation session. This data will eventually include the results
 /// of a few selected queries (like `typeck` and `mir_optimized`) and
 /// any side effects that have been emitted during a query.
-pub struct OnDiskCache<'sess> {
+pub struct OnDiskCache {
     // The complete cache data in serialized form.
     serialized_data: RwLock<Option<Mmap>>,
 
@@ -57,7 +57,6 @@ pub struct OnDiskCache<'sess> {
     // session.
     current_side_effects: Lock<FxHashMap<DepNodeIndex, QuerySideEffects>>,
 
-    source_map: &'sess SourceMap,
     file_index_to_stable_id: FxHashMap<SourceFileIndex, EncodedSourceFileId>,
 
     // Caches that are populated lazily during decoding.
@@ -151,12 +150,12 @@ impl EncodedSourceFileId {
     }
 }
 
-impl<'sess> OnDiskCache<'sess> {
+impl OnDiskCache {
     /// Creates a new `OnDiskCache` instance from the serialized data in `data`.
     ///
     /// The serialized cache has some basic integrity checks, if those checks indicate that the
     /// on-disk data is corrupt, an error is returned.
-    pub fn new(sess: &'sess Session, data: Mmap, start_pos: usize) -> Result<Self, ()> {
+    pub fn new(sess: &Session, data: Mmap, start_pos: usize) -> Result<Self, ()> {
         assert!(sess.opts.incremental.is_some());
 
         let mut decoder = MemDecoder::new(&data, start_pos)?;
@@ -175,7 +174,6 @@ impl<'sess> OnDiskCache<'sess> {
             serialized_data: RwLock::new(Some(data)),
             file_index_to_stable_id: footer.file_index_to_stable_id,
             file_index_to_file: Default::default(),
-            source_map: sess.source_map(),
             current_side_effects: Default::default(),
             query_result_index: footer.query_result_index.into_iter().collect(),
             prev_side_effects_index: footer.side_effects_index.into_iter().collect(),
@@ -187,12 +185,11 @@ impl<'sess> OnDiskCache<'sess> {
         })
     }
 
-    pub fn new_empty(source_map: &'sess SourceMap) -> Self {
+    pub fn new_empty() -> Self {
         Self {
             serialized_data: RwLock::new(None),
             file_index_to_stable_id: Default::default(),
             file_index_to_file: Default::default(),
-            source_map,
             current_side_effects: Default::default(),
             query_result_index: Default::default(),
             prev_side_effects_index: Default::default(),
@@ -423,7 +420,7 @@ impl<'sess> OnDiskCache<'sess> {
     }
 
     fn with_decoder<'a, 'tcx, T, F: for<'s> FnOnce(&mut CacheDecoder<'s, 'tcx>) -> T>(
-        &'sess self,
+        &self,
         tcx: TyCtxt<'tcx>,
         pos: AbsoluteBytePos,
         f: F,
@@ -436,7 +433,6 @@ impl<'sess> OnDiskCache<'sess> {
             tcx,
             opaque: MemDecoder::new(serialized_data.as_deref().unwrap_or(&[]), pos.to_usize())
                 .unwrap(),
-            source_map: self.source_map,
             file_index_to_file: &self.file_index_to_file,
             file_index_to_stable_id: &self.file_index_to_stable_id,
             alloc_decoding_session: self.alloc_decoding_state.new_decoding_session(),
@@ -457,7 +453,6 @@ impl<'sess> OnDiskCache<'sess> {
 pub struct CacheDecoder<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     opaque: MemDecoder<'a>,
-    source_map: &'a SourceMap,
     file_index_to_file: &'a Lock<FxHashMap<SourceFileIndex, Lrc<SourceFile>>>,
     file_index_to_stable_id: &'a FxHashMap<SourceFileIndex, EncodedSourceFileId>,
     alloc_decoding_session: AllocDecodingSession<'a>,
@@ -470,8 +465,7 @@ pub struct CacheDecoder<'a, 'tcx> {
 impl<'a, 'tcx> CacheDecoder<'a, 'tcx> {
     #[inline]
     fn file_index_to_file(&self, index: SourceFileIndex) -> Lrc<SourceFile> {
-        let CacheDecoder { tcx, file_index_to_file, file_index_to_stable_id, source_map, .. } =
-            *self;
+        let CacheDecoder { tcx, file_index_to_file, file_index_to_stable_id, .. } = *self;
 
         Lrc::clone(file_index_to_file.borrow_mut().entry(index).or_insert_with(|| {
             let source_file_id = &file_index_to_stable_id[&index];
@@ -490,7 +484,8 @@ impl<'a, 'tcx> CacheDecoder<'a, 'tcx> {
                 self.tcx.import_source_files(source_file_cnum);
             }
 
-            source_map
+            tcx.sess
+                .source_map()
                 .source_file_by_stable_id(source_file_id.stable_source_file_id)
                 .expect("failed to lookup `SourceFile` in new context")
         }))
diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index 20ba1b27c0e..c8675660e0f 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -66,7 +66,7 @@ pub struct QuerySystem<'tcx> {
     /// Do not access this directly. It is only meant to be used by
     /// `DepGraph::try_mark_green()` and the query infrastructure.
     /// This is `None` if we are not incremental compilation mode
-    pub on_disk_cache: Option<OnDiskCache<'tcx>>,
+    pub on_disk_cache: Option<OnDiskCache>,
 
     pub fns: QuerySystemFns<'tcx>,
 
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index fd807882e0f..604f1da26c6 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -1,11 +1,12 @@
 //! Diagnostics related methods for `Ty`.
 
-use std::borrow::Cow;
 use std::fmt::Write;
 use std::ops::ControlFlow;
 
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{Applicability, Diag, DiagArgValue, IntoDiagArg, into_diag_arg_using_display};
+use rustc_errors::{
+    Applicability, Diag, DiagArgValue, IntoDiagArg, into_diag_arg_using_display, pluralize,
+};
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{self as hir, LangItem, PredicateOrigin, WherePredicateKind};
@@ -161,7 +162,7 @@ pub fn suggest_arbitrary_trait_bound<'tcx>(
     true
 }
 
-#[derive(Debug)]
+#[derive(Debug, Clone, Copy)]
 enum SuggestChangingConstraintsMessage<'a> {
     RestrictBoundFurther,
     RestrictType { ty: &'a str },
@@ -172,7 +173,7 @@ enum SuggestChangingConstraintsMessage<'a> {
 
 fn suggest_changing_unsized_bound(
     generics: &hir::Generics<'_>,
-    suggestions: &mut Vec<(Span, String, SuggestChangingConstraintsMessage<'_>)>,
+    suggestions: &mut Vec<(Span, String, String, SuggestChangingConstraintsMessage<'_>)>,
     param: &hir::GenericParam<'_>,
     def_id: Option<DefId>,
 ) {
@@ -207,7 +208,8 @@ fn suggest_changing_unsized_bound(
             continue;
         }
 
-        let mut push_suggestion = |sp, msg| suggestions.push((sp, String::new(), msg));
+        let mut push_suggestion =
+            |sp, msg| suggestions.push((sp, "Sized".to_string(), String::new(), msg));
 
         if predicate.bounds.len() == unsized_bounds.len() {
             // All the bounds are unsized bounds, e.g.
@@ -278,8 +280,25 @@ pub fn suggest_constraining_type_params<'a>(
     span_to_replace: Option<Span>,
 ) -> bool {
     let mut grouped = FxHashMap::default();
+    let mut unstable_suggestion = false;
     param_names_and_constraints.for_each(|(param_name, constraint, def_id)| {
-        grouped.entry(param_name).or_insert(Vec::new()).push((constraint, def_id))
+        let stable = match def_id {
+            Some(def_id) => match tcx.lookup_stability(def_id) {
+                Some(s) => s.level.is_stable(),
+                None => true,
+            },
+            None => true,
+        };
+        if stable || tcx.sess.is_nightly_build() {
+            grouped.entry(param_name).or_insert(Vec::new()).push((
+                constraint,
+                def_id,
+                if stable { "" } else { "unstable " },
+            ));
+            if !stable {
+                unstable_suggestion = true;
+            }
+        }
     });
 
     let mut applicability = Applicability::MachineApplicable;
@@ -290,16 +309,21 @@ pub fn suggest_constraining_type_params<'a>(
         let Some(param) = param else { return false };
 
         {
-            let mut sized_constraints = constraints.extract_if(|(_, def_id)| {
+            let mut sized_constraints = constraints.extract_if(|(_, def_id, _)| {
                 def_id.is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::Sized))
             });
-            if let Some((_, def_id)) = sized_constraints.next() {
+            if let Some((_, def_id, _)) = sized_constraints.next() {
                 applicability = Applicability::MaybeIncorrect;
 
                 err.span_label(param.span, "this type parameter needs to be `Sized`");
                 suggest_changing_unsized_bound(generics, &mut suggestions, param, def_id);
             }
         }
+        let bound_message = if constraints.iter().any(|(_, def_id, _)| def_id.is_none()) {
+            SuggestChangingConstraintsMessage::RestrictBoundFurther
+        } else {
+            SuggestChangingConstraintsMessage::RestrictTypeFurther { ty: param_name }
+        };
 
         // in the scenario like impl has stricter requirements than trait,
         // we should not suggest restrict bound on the impl, here we double check
@@ -312,15 +336,54 @@ pub fn suggest_constraining_type_params<'a>(
             .collect();
 
         constraints
-            .retain(|(_, def_id)| def_id.map_or(true, |def| !bound_trait_defs.contains(&def)));
+            .retain(|(_, def_id, _)| def_id.map_or(true, |def| !bound_trait_defs.contains(&def)));
 
         if constraints.is_empty() {
             continue;
         }
 
-        let mut constraint = constraints.iter().map(|&(c, _)| c).collect::<Vec<_>>();
+        let mut constraint = constraints.iter().map(|&(c, _, _)| c).collect::<Vec<_>>();
         constraint.sort();
         constraint.dedup();
+        let all_known = constraints.iter().all(|&(_, def_id, _)| def_id.is_some());
+        let all_stable = constraints.iter().all(|&(_, _, stable)| stable.is_empty());
+        let all_unstable = constraints.iter().all(|&(_, _, stable)| !stable.is_empty());
+        let post = if all_stable || all_unstable {
+            // Don't redundantly say "trait `X`, trait `Y`", instead "traits `X` and `Y`"
+            let mut trait_names = constraints
+                .iter()
+                .map(|&(c, def_id, _)| match def_id {
+                    None => format!("`{c}`"),
+                    Some(def_id) => format!("`{}`", tcx.item_name(def_id)),
+                })
+                .collect::<Vec<_>>();
+            trait_names.sort();
+            trait_names.dedup();
+            let n = trait_names.len();
+            let stable = if all_stable { "" } else { "unstable " };
+            let trait_ = if all_known { format!("trait{}", pluralize!(n)) } else { String::new() };
+            format!("{stable}{trait_}{}", match &trait_names[..] {
+                [t] => format!(" {t}"),
+                [ts @ .., last] => format!(" {} and {last}", ts.join(", ")),
+                [] => return false,
+            },)
+        } else {
+            // We're more explicit when there's a mix of stable and unstable traits.
+            let mut trait_names = constraints
+                .iter()
+                .map(|&(c, def_id, stable)| match def_id {
+                    None => format!("`{c}`"),
+                    Some(def_id) => format!("{stable}trait `{}`", tcx.item_name(def_id)),
+                })
+                .collect::<Vec<_>>();
+            trait_names.sort();
+            trait_names.dedup();
+            match &trait_names[..] {
+                [t] => t.to_string(),
+                [ts @ .., last] => format!("{} and {last}", ts.join(", ")),
+                [] => return false,
+            }
+        };
         let constraint = constraint.join(" + ");
         let mut suggest_restrict = |span, bound_list_non_empty, open_paren_sp| {
             let suggestion = if span_to_replace.is_some() {
@@ -333,13 +396,11 @@ pub fn suggest_constraining_type_params<'a>(
                 format!(" {constraint}")
             };
 
-            use SuggestChangingConstraintsMessage::RestrictBoundFurther;
-
             if let Some(open_paren_sp) = open_paren_sp {
-                suggestions.push((open_paren_sp, "(".to_string(), RestrictBoundFurther));
-                suggestions.push((span, format!("){suggestion}"), RestrictBoundFurther));
+                suggestions.push((open_paren_sp, post.clone(), "(".to_string(), bound_message));
+                suggestions.push((span, post.clone(), format!("){suggestion}"), bound_message));
             } else {
-                suggestions.push((span, suggestion, RestrictBoundFurther));
+                suggestions.push((span, post.clone(), suggestion, bound_message));
             }
         };
 
@@ -397,7 +458,8 @@ pub fn suggest_constraining_type_params<'a>(
             //                                           - insert: `, X: Bar`
             suggestions.push((
                 generics.tail_span_for_predicate_suggestion(),
-                constraints.iter().fold(String::new(), |mut string, &(constraint, _)| {
+                post,
+                constraints.iter().fold(String::new(), |mut string, &(constraint, _, _)| {
                     write!(string, ", {param_name}: {constraint}").unwrap();
                     string
                 }),
@@ -426,6 +488,7 @@ pub fn suggest_constraining_type_params<'a>(
             // default (`<T=Foo>`), so we suggest adding `where T: Bar`.
             suggestions.push((
                 generics.tail_span_for_predicate_suggestion(),
+                post,
                 format!("{where_prefix} {param_name}: {constraint}"),
                 SuggestChangingConstraintsMessage::RestrictTypeFurther { ty: param_name },
             ));
@@ -439,6 +502,7 @@ pub fn suggest_constraining_type_params<'a>(
         if let Some(colon_span) = param.colon_span {
             suggestions.push((
                 colon_span.shrink_to_hi(),
+                post,
                 format!(" {constraint}"),
                 SuggestChangingConstraintsMessage::RestrictType { ty: param_name },
             ));
@@ -451,6 +515,7 @@ pub fn suggest_constraining_type_params<'a>(
         //          - help: consider restricting this type parameter with `T: Foo`
         suggestions.push((
             param.span.shrink_to_hi(),
+            post,
             format!(": {constraint}"),
             SuggestChangingConstraintsMessage::RestrictType { ty: param_name },
         ));
@@ -459,39 +524,46 @@ pub fn suggest_constraining_type_params<'a>(
     // FIXME: remove the suggestions that are from derive, as the span is not correct
     suggestions = suggestions
         .into_iter()
-        .filter(|(span, _, _)| !span.in_derive_expansion())
+        .filter(|(span, _, _, _)| !span.in_derive_expansion())
         .collect::<Vec<_>>();
-
+    let suggested = !suggestions.is_empty();
     if suggestions.len() == 1 {
-        let (span, suggestion, msg) = suggestions.pop().unwrap();
+        let (span, post, suggestion, msg) = suggestions.pop().unwrap();
         let msg = match msg {
             SuggestChangingConstraintsMessage::RestrictBoundFurther => {
-                Cow::from("consider further restricting this bound")
+                format!("consider further restricting this bound")
+            }
+            SuggestChangingConstraintsMessage::RestrictTypeFurther { ty }
+            | SuggestChangingConstraintsMessage::RestrictType { ty }
+                if ty.starts_with("impl ") =>
+            {
+                format!("consider restricting opaque type `{ty}` with {post}")
             }
             SuggestChangingConstraintsMessage::RestrictType { ty } => {
-                Cow::from(format!("consider restricting type parameter `{ty}`"))
+                format!("consider restricting type parameter `{ty}` with {post}")
             }
             SuggestChangingConstraintsMessage::RestrictTypeFurther { ty } => {
-                Cow::from(format!("consider further restricting type parameter `{ty}`"))
+                format!("consider further restricting type parameter `{ty}` with {post}")
             }
             SuggestChangingConstraintsMessage::RemoveMaybeUnsized => {
-                Cow::from("consider removing the `?Sized` bound to make the type parameter `Sized`")
+                format!("consider removing the `?Sized` bound to make the type parameter `Sized`")
             }
             SuggestChangingConstraintsMessage::ReplaceMaybeUnsizedWithSized => {
-                Cow::from("consider replacing `?Sized` with `Sized`")
+                format!("consider replacing `?Sized` with `Sized`")
             }
         };
 
         err.span_suggestion_verbose(span, msg, suggestion, applicability);
     } else if suggestions.len() > 1 {
+        let post = if unstable_suggestion { " (some of them are unstable traits)" } else { "" };
         err.multipart_suggestion_verbose(
-            "consider restricting type parameters",
-            suggestions.into_iter().map(|(span, suggestion, _)| (span, suggestion)).collect(),
+            format!("consider restricting type parameters{post}"),
+            suggestions.into_iter().map(|(span, _, suggestion, _)| (span, suggestion)).collect(),
             applicability,
         );
     }
 
-    true
+    suggested
 }
 
 /// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for.
diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
index 561229cf725..f844e8fbe03 100644
--- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
@@ -2,19 +2,186 @@
 
 use std::borrow::Cow;
 use std::cell::RefCell;
+use std::ffi::OsString;
+use std::path::PathBuf;
 use std::sync::OnceLock;
 use std::{io, ops, str};
 
 use regex::Regex;
-use rustc_graphviz as dot;
+use rustc_hir::def_id::DefId;
 use rustc_index::bit_set::BitSet;
-use rustc_middle::mir::{self, BasicBlock, Body, Location, graphviz_safe_def_name};
+use rustc_middle::mir::{
+    self, BasicBlock, Body, Location, create_dump_file, dump_enabled, graphviz_safe_def_name,
+    traversal,
+};
+use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_span::symbol::{Symbol, sym};
+use tracing::debug;
+use {rustc_ast as ast, rustc_graphviz as dot};
 
 use super::fmt::{DebugDiffWithAdapter, DebugWithAdapter, DebugWithContext};
 use super::{Analysis, CallReturnPlaces, Direction, Results, ResultsCursor, ResultsVisitor};
+use crate::errors::{
+    DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter,
+};
+
+/// Writes a DOT file containing the results of a dataflow analysis if the user requested it via
+/// `rustc_mir` attributes and `-Z dump-mir-dataflow`. The `Result` in and the `Results` out are
+/// the same.
+pub(super) fn write_graphviz_results<'tcx, A>(
+    tcx: TyCtxt<'tcx>,
+    body: &Body<'tcx>,
+    results: &mut Results<'tcx, A>,
+    pass_name: Option<&'static str>,
+) -> std::io::Result<()>
+where
+    A: Analysis<'tcx>,
+    A::Domain: DebugWithContext<A>,
+{
+    use std::fs;
+    use std::io::Write;
+
+    let def_id = body.source.def_id();
+    let Ok(attrs) = RustcMirAttrs::parse(tcx, def_id) else {
+        // Invalid `rustc_mir` attrs are reported in `RustcMirAttrs::parse`
+        return Ok(());
+    };
+
+    let file = try {
+        match attrs.output_path(A::NAME) {
+            Some(path) => {
+                debug!("printing dataflow results for {:?} to {}", def_id, path.display());
+                if let Some(parent) = path.parent() {
+                    fs::create_dir_all(parent)?;
+                }
+                fs::File::create_buffered(&path)?
+            }
+
+            None if dump_enabled(tcx, A::NAME, def_id) => {
+                create_dump_file(tcx, "dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)?
+            }
+
+            _ => return Ok(()),
+        }
+    };
+    let mut file = match file {
+        Ok(f) => f,
+        Err(e) => return Err(e),
+    };
+
+    let style = match attrs.formatter {
+        Some(sym::two_phase) => OutputStyle::BeforeAndAfter,
+        _ => OutputStyle::AfterOnly,
+    };
+
+    let mut buf = Vec::new();
+
+    let graphviz = Formatter::new(body, results, style);
+    let mut render_opts =
+        vec![dot::RenderOption::Fontname(tcx.sess.opts.unstable_opts.graphviz_font.clone())];
+    if tcx.sess.opts.unstable_opts.graphviz_dark_mode {
+        render_opts.push(dot::RenderOption::DarkTheme);
+    }
+    let r = with_no_trimmed_paths!(dot::render_opts(&graphviz, &mut buf, &render_opts));
+
+    let lhs = try {
+        r?;
+        file.write_all(&buf)?;
+    };
+
+    lhs
+}
+
+#[derive(Default)]
+struct RustcMirAttrs {
+    basename_and_suffix: Option<PathBuf>,
+    formatter: Option<Symbol>,
+}
+
+impl RustcMirAttrs {
+    fn parse(tcx: TyCtxt<'_>, def_id: DefId) -> Result<Self, ()> {
+        let mut result = Ok(());
+        let mut ret = RustcMirAttrs::default();
+
+        let rustc_mir_attrs = tcx
+            .get_attrs(def_id, sym::rustc_mir)
+            .flat_map(|attr| attr.meta_item_list().into_iter().flat_map(|v| v.into_iter()));
+
+        for attr in rustc_mir_attrs {
+            let attr_result = if attr.has_name(sym::borrowck_graphviz_postflow) {
+                Self::set_field(&mut ret.basename_and_suffix, tcx, &attr, |s| {
+                    let path = PathBuf::from(s.to_string());
+                    match path.file_name() {
+                        Some(_) => Ok(path),
+                        None => {
+                            tcx.dcx().emit_err(PathMustEndInFilename { span: attr.span() });
+                            Err(())
+                        }
+                    }
+                })
+            } else if attr.has_name(sym::borrowck_graphviz_format) {
+                Self::set_field(&mut ret.formatter, tcx, &attr, |s| match s {
+                    sym::gen_kill | sym::two_phase => Ok(s),
+                    _ => {
+                        tcx.dcx().emit_err(UnknownFormatter { span: attr.span() });
+                        Err(())
+                    }
+                })
+            } else {
+                Ok(())
+            };
+
+            result = result.and(attr_result);
+        }
+
+        result.map(|()| ret)
+    }
+
+    fn set_field<T>(
+        field: &mut Option<T>,
+        tcx: TyCtxt<'_>,
+        attr: &ast::MetaItemInner,
+        mapper: impl FnOnce(Symbol) -> Result<T, ()>,
+    ) -> Result<(), ()> {
+        if field.is_some() {
+            tcx.dcx()
+                .emit_err(DuplicateValuesFor { span: attr.span(), name: attr.name_or_empty() });
+
+            return Err(());
+        }
+
+        if let Some(s) = attr.value_str() {
+            *field = Some(mapper(s)?);
+            Ok(())
+        } else {
+            tcx.dcx()
+                .emit_err(RequiresAnArgument { span: attr.span(), name: attr.name_or_empty() });
+            Err(())
+        }
+    }
+
+    /// Returns the path where dataflow results should be written, or `None`
+    /// `borrowck_graphviz_postflow` was not specified.
+    ///
+    /// This performs the following transformation to the argument of `borrowck_graphviz_postflow`:
+    ///
+    /// "path/suffix.dot" -> "path/analysis_name_suffix.dot"
+    fn output_path(&self, analysis_name: &str) -> Option<PathBuf> {
+        let mut ret = self.basename_and_suffix.as_ref().cloned()?;
+        let suffix = ret.file_name().unwrap(); // Checked when parsing attrs
+
+        let mut file_name: OsString = analysis_name.into();
+        file_name.push("_");
+        file_name.push(suffix);
+        ret.set_file_name(file_name);
+
+        Some(ret)
+    }
+}
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub(crate) enum OutputStyle {
+enum OutputStyle {
     AfterOnly,
     BeforeAndAfter,
 }
@@ -28,7 +195,7 @@ impl OutputStyle {
     }
 }
 
-pub(crate) struct Formatter<'mir, 'tcx, A>
+struct Formatter<'mir, 'tcx, A>
 where
     A: Analysis<'tcx>,
 {
@@ -45,12 +212,12 @@ impl<'mir, 'tcx, A> Formatter<'mir, 'tcx, A>
 where
     A: Analysis<'tcx>,
 {
-    pub(crate) fn new(
+    fn new(
         body: &'mir Body<'tcx>,
         results: &'mir mut Results<'tcx, A>,
         style: OutputStyle,
     ) -> Self {
-        let reachable = mir::traversal::reachable_as_bitset(body);
+        let reachable = traversal::reachable_as_bitset(body);
         Formatter { cursor: results.as_results_cursor(body).into(), style, reachable }
     }
 
@@ -61,7 +228,7 @@ where
 
 /// A pair of a basic block and an index into that basic blocks `successors`.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub(crate) struct CfgEdge {
+struct CfgEdge {
     source: BasicBlock,
     index: usize,
 }
@@ -520,7 +687,7 @@ struct StateDiffCollector<D> {
 
 impl<D> StateDiffCollector<D> {
     fn run<'tcx, A>(
-        body: &mir::Body<'tcx>,
+        body: &Body<'tcx>,
         block: BasicBlock,
         results: &mut Results<'tcx, A>,
         style: OutputStyle,
diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs
index b9407882ec5..13384d6f285 100644
--- a/compiler/rustc_mir_dataflow/src/framework/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs
@@ -42,7 +42,7 @@ use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, Terminator
 use rustc_middle::ty::TyCtxt;
 use tracing::error;
 
-use self::results::write_graphviz_results;
+use self::graphviz::write_graphviz_results;
 use super::fmt::DebugWithContext;
 
 mod cursor;
diff --git a/compiler/rustc_mir_dataflow/src/framework/results.rs b/compiler/rustc_mir_dataflow/src/framework/results.rs
index c4321c454e6..a7dbd99b8ab 100644
--- a/compiler/rustc_mir_dataflow/src/framework/results.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/results.rs
@@ -1,22 +1,9 @@
 //! Dataflow analysis results.
 
-use std::ffi::OsString;
-use std::path::PathBuf;
-
-use rustc_hir::def_id::DefId;
 use rustc_index::IndexVec;
-use rustc_middle::mir::{self, BasicBlock, create_dump_file, dump_enabled, traversal};
-use rustc_middle::ty::TyCtxt;
-use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_span::symbol::{Symbol, sym};
-use tracing::debug;
-use {rustc_ast as ast, rustc_graphviz as dot};
+use rustc_middle::mir::{BasicBlock, Body, traversal};
 
-use super::fmt::DebugWithContext;
-use super::{Analysis, ResultsCursor, ResultsVisitor, graphviz, visit_results};
-use crate::errors::{
-    DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter,
-};
+use super::{Analysis, ResultsCursor, ResultsVisitor, visit_results};
 use crate::framework::cursor::ResultsHandle;
 
 pub type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>;
@@ -41,16 +28,13 @@ where
     /// `Results` is also used outside the cursor.
     pub fn as_results_cursor<'mir>(
         &'mir mut self,
-        body: &'mir mir::Body<'tcx>,
+        body: &'mir Body<'tcx>,
     ) -> ResultsCursor<'mir, 'tcx, A> {
         ResultsCursor::new(body, ResultsHandle::BorrowedMut(self))
     }
 
     /// Creates a `ResultsCursor` that takes ownership of the `Results`.
-    pub fn into_results_cursor<'mir>(
-        self,
-        body: &'mir mir::Body<'tcx>,
-    ) -> ResultsCursor<'mir, 'tcx, A> {
+    pub fn into_results_cursor<'mir>(self, body: &'mir Body<'tcx>) -> ResultsCursor<'mir, 'tcx, A> {
         ResultsCursor::new(body, ResultsHandle::Owned(self))
     }
 
@@ -61,7 +45,7 @@ where
 
     pub fn visit_with<'mir>(
         &mut self,
-        body: &'mir mir::Body<'tcx>,
+        body: &'mir Body<'tcx>,
         blocks: impl IntoIterator<Item = BasicBlock>,
         vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
     ) {
@@ -70,166 +54,10 @@ where
 
     pub fn visit_reachable_with<'mir>(
         &mut self,
-        body: &'mir mir::Body<'tcx>,
+        body: &'mir Body<'tcx>,
         vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
     ) {
         let blocks = traversal::reachable(body);
         visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
     }
 }
-
-// Graphviz
-
-/// Writes a DOT file containing the results of a dataflow analysis if the user requested it via
-/// `rustc_mir` attributes and `-Z dump-mir-dataflow`. The `Result` in and the `Results` out are
-/// the same.
-pub(super) fn write_graphviz_results<'tcx, A>(
-    tcx: TyCtxt<'tcx>,
-    body: &mir::Body<'tcx>,
-    results: &mut Results<'tcx, A>,
-    pass_name: Option<&'static str>,
-) -> std::io::Result<()>
-where
-    A: Analysis<'tcx>,
-    A::Domain: DebugWithContext<A>,
-{
-    use std::fs;
-    use std::io::Write;
-
-    let def_id = body.source.def_id();
-    let Ok(attrs) = RustcMirAttrs::parse(tcx, def_id) else {
-        // Invalid `rustc_mir` attrs are reported in `RustcMirAttrs::parse`
-        return Ok(());
-    };
-
-    let file = try {
-        match attrs.output_path(A::NAME) {
-            Some(path) => {
-                debug!("printing dataflow results for {:?} to {}", def_id, path.display());
-                if let Some(parent) = path.parent() {
-                    fs::create_dir_all(parent)?;
-                }
-                fs::File::create_buffered(&path)?
-            }
-
-            None if dump_enabled(tcx, A::NAME, def_id) => {
-                create_dump_file(tcx, "dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)?
-            }
-
-            _ => return Ok(()),
-        }
-    };
-    let mut file = match file {
-        Ok(f) => f,
-        Err(e) => return Err(e),
-    };
-
-    let style = match attrs.formatter {
-        Some(sym::two_phase) => graphviz::OutputStyle::BeforeAndAfter,
-        _ => graphviz::OutputStyle::AfterOnly,
-    };
-
-    let mut buf = Vec::new();
-
-    let graphviz = graphviz::Formatter::new(body, results, style);
-    let mut render_opts =
-        vec![dot::RenderOption::Fontname(tcx.sess.opts.unstable_opts.graphviz_font.clone())];
-    if tcx.sess.opts.unstable_opts.graphviz_dark_mode {
-        render_opts.push(dot::RenderOption::DarkTheme);
-    }
-    let r = with_no_trimmed_paths!(dot::render_opts(&graphviz, &mut buf, &render_opts));
-
-    let lhs = try {
-        r?;
-        file.write_all(&buf)?;
-    };
-
-    lhs
-}
-
-#[derive(Default)]
-struct RustcMirAttrs {
-    basename_and_suffix: Option<PathBuf>,
-    formatter: Option<Symbol>,
-}
-
-impl RustcMirAttrs {
-    fn parse(tcx: TyCtxt<'_>, def_id: DefId) -> Result<Self, ()> {
-        let mut result = Ok(());
-        let mut ret = RustcMirAttrs::default();
-
-        let rustc_mir_attrs = tcx
-            .get_attrs(def_id, sym::rustc_mir)
-            .flat_map(|attr| attr.meta_item_list().into_iter().flat_map(|v| v.into_iter()));
-
-        for attr in rustc_mir_attrs {
-            let attr_result = if attr.has_name(sym::borrowck_graphviz_postflow) {
-                Self::set_field(&mut ret.basename_and_suffix, tcx, &attr, |s| {
-                    let path = PathBuf::from(s.to_string());
-                    match path.file_name() {
-                        Some(_) => Ok(path),
-                        None => {
-                            tcx.dcx().emit_err(PathMustEndInFilename { span: attr.span() });
-                            Err(())
-                        }
-                    }
-                })
-            } else if attr.has_name(sym::borrowck_graphviz_format) {
-                Self::set_field(&mut ret.formatter, tcx, &attr, |s| match s {
-                    sym::gen_kill | sym::two_phase => Ok(s),
-                    _ => {
-                        tcx.dcx().emit_err(UnknownFormatter { span: attr.span() });
-                        Err(())
-                    }
-                })
-            } else {
-                Ok(())
-            };
-
-            result = result.and(attr_result);
-        }
-
-        result.map(|()| ret)
-    }
-
-    fn set_field<T>(
-        field: &mut Option<T>,
-        tcx: TyCtxt<'_>,
-        attr: &ast::MetaItemInner,
-        mapper: impl FnOnce(Symbol) -> Result<T, ()>,
-    ) -> Result<(), ()> {
-        if field.is_some() {
-            tcx.dcx()
-                .emit_err(DuplicateValuesFor { span: attr.span(), name: attr.name_or_empty() });
-
-            return Err(());
-        }
-
-        if let Some(s) = attr.value_str() {
-            *field = Some(mapper(s)?);
-            Ok(())
-        } else {
-            tcx.dcx()
-                .emit_err(RequiresAnArgument { span: attr.span(), name: attr.name_or_empty() });
-            Err(())
-        }
-    }
-
-    /// Returns the path where dataflow results should be written, or `None`
-    /// `borrowck_graphviz_postflow` was not specified.
-    ///
-    /// This performs the following transformation to the argument of `borrowck_graphviz_postflow`:
-    ///
-    /// "path/suffix.dot" -> "path/analysis_name_suffix.dot"
-    fn output_path(&self, analysis_name: &str) -> Option<PathBuf> {
-        let mut ret = self.basename_and_suffix.as_ref().cloned()?;
-        let suffix = ret.file_name().unwrap(); // Checked when parsing attrs
-
-        let mut file_name: OsString = analysis_name.into();
-        file_name.push("_");
-        file_name.push(suffix);
-        ret.set_file_name(file_name);
-
-        Some(ret)
-    }
-}
diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs
index b9e194b00c5..d69a8019c8d 100644
--- a/compiler/rustc_mir_dataflow/src/impls/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs
@@ -1,7 +1,3 @@
-//! Dataflow analyses are built upon some interpretation of the
-//! bitvectors attached to each basic block, represented via a
-//! zero-sized structure.
-
 mod borrowed_locals;
 mod initialized;
 mod liveness;
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 8d16d44b0a2..3a9e9b480ec 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -2631,7 +2631,7 @@ impl<'a> Parser<'a> {
         };
         self.bump(); // Eat `let` token
         let lo = self.prev_token.span;
-        let pat = self.parse_pat_allow_top_alt(
+        let pat = self.parse_pat_no_top_guard(
             None,
             RecoverComma::Yes,
             RecoverColon::Yes,
@@ -2778,7 +2778,7 @@ impl<'a> Parser<'a> {
         };
         // Try to parse the pattern `for ($PAT) in $EXPR`.
         let pat = match (
-            self.parse_pat_allow_top_alt(
+            self.parse_pat_allow_top_guard(
                 None,
                 RecoverComma::Yes,
                 RecoverColon::Yes,
@@ -3241,7 +3241,7 @@ impl<'a> Parser<'a> {
                     // then we should recover.
                     let mut snapshot = this.create_snapshot_for_diagnostic();
                     let pattern_follows = snapshot
-                        .parse_pat_allow_top_alt(
+                        .parse_pat_no_top_guard(
                             None,
                             RecoverComma::Yes,
                             RecoverColon::Yes,
@@ -3315,43 +3315,37 @@ impl<'a> Parser<'a> {
 
     fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (P<Pat>, Option<P<Expr>>)> {
         if self.token == token::OpenDelim(Delimiter::Parenthesis) {
-            // Detect and recover from `($pat if $cond) => $arm`.
             let left = self.token.span;
-            match self.parse_pat_allow_top_alt(
+            let pat = self.parse_pat_no_top_guard(
                 None,
                 RecoverComma::Yes,
                 RecoverColon::Yes,
                 CommaRecoveryMode::EitherTupleOrPipe,
-            ) {
-                Ok(pat) => Ok((pat, self.parse_match_arm_guard()?)),
-                Err(err)
-                    if let prev_sp = self.prev_token.span
-                        && let true = self.eat_keyword(kw::If) =>
-                {
-                    // We know for certain we've found `($pat if` so far.
-                    let mut cond = match self.parse_match_guard_condition() {
-                        Ok(cond) => cond,
-                        Err(cond_err) => {
-                            cond_err.cancel();
-                            return Err(err);
-                        }
-                    };
-                    err.cancel();
-                    CondChecker::new(self).visit_expr(&mut cond);
-                    self.eat_to_tokens(&[&token::CloseDelim(Delimiter::Parenthesis)]);
-                    self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
-                    let right = self.prev_token.span;
-                    self.dcx().emit_err(errors::ParenthesesInMatchPat {
-                        span: vec![left, right],
-                        sugg: errors::ParenthesesInMatchPatSugg { left, right },
-                    });
-                    Ok((self.mk_pat(left.to(prev_sp), ast::PatKind::Wild), Some(cond)))
-                }
-                Err(err) => Err(err),
+            )?;
+            if let ast::PatKind::Paren(subpat) = &pat.kind
+                && let ast::PatKind::Guard(..) = &subpat.kind
+            {
+                // Detect and recover from `($pat if $cond) => $arm`.
+                // FIXME(guard_patterns): convert this to a normal guard instead
+                let span = pat.span;
+                let ast::PatKind::Paren(subpat) = pat.into_inner().kind else { unreachable!() };
+                let ast::PatKind::Guard(_, mut cond) = subpat.into_inner().kind else {
+                    unreachable!()
+                };
+                self.psess.gated_spans.ungate_last(sym::guard_patterns, cond.span);
+                CondChecker::new(self).visit_expr(&mut cond);
+                let right = self.prev_token.span;
+                self.dcx().emit_err(errors::ParenthesesInMatchPat {
+                    span: vec![left, right],
+                    sugg: errors::ParenthesesInMatchPatSugg { left, right },
+                });
+                Ok((self.mk_pat(span, ast::PatKind::Wild), Some(cond)))
+            } else {
+                Ok((pat, self.parse_match_arm_guard()?))
             }
         } else {
             // Regular parser flow:
-            let pat = self.parse_pat_allow_top_alt(
+            let pat = self.parse_pat_no_top_guard(
                 None,
                 RecoverComma::Yes,
                 RecoverColon::Yes,
diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs
index 8fb6f85d0dd..752a52b382b 100644
--- a/compiler/rustc_parse/src/parser/nonterminal.rs
+++ b/compiler/rustc_parse/src/parser/nonterminal.rs
@@ -174,7 +174,7 @@ impl<'a> Parser<'a> {
             NonterminalKind::Pat(pat_kind) => {
                 NtPat(self.collect_tokens_no_attrs(|this| match pat_kind {
                     PatParam { .. } => this.parse_pat_no_top_alt(None, None),
-                    PatWithOr => this.parse_pat_allow_top_alt(
+                    PatWithOr => this.parse_pat_no_top_guard(
                         None,
                         RecoverComma::No,
                         RecoverColon::No,
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index e08b925f008..4cda887a02b 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -99,9 +99,34 @@ pub enum PatternLocation {
 impl<'a> Parser<'a> {
     /// Parses a pattern.
     ///
-    /// Corresponds to `pat<no_top_alt>` in RFC 2535 and does not admit or-patterns
-    /// at the top level. Used when parsing the parameters of lambda expressions,
-    /// functions, function pointers, and `pat` macro fragments.
+    /// Corresponds to `Pattern` in RFC 3637 and admits guard patterns at the top level.
+    /// Used when parsing patterns in all cases where neither `PatternNoTopGuard` nor
+    /// `PatternNoTopAlt` (see below) are used.
+    pub fn parse_pat_allow_top_guard(
+        &mut self,
+        expected: Option<Expected>,
+        rc: RecoverComma,
+        ra: RecoverColon,
+        rt: CommaRecoveryMode,
+    ) -> PResult<'a, P<Pat>> {
+        let pat = self.parse_pat_no_top_guard(expected, rc, ra, rt)?;
+
+        if self.eat_keyword(kw::If) {
+            let cond = self.parse_expr()?;
+            // Feature-gate guard patterns
+            self.psess.gated_spans.gate(sym::guard_patterns, cond.span);
+            let span = pat.span.to(cond.span);
+            Ok(self.mk_pat(span, PatKind::Guard(pat, cond)))
+        } else {
+            Ok(pat)
+        }
+    }
+
+    /// Parses a pattern.
+    ///
+    /// Corresponds to `PatternNoTopAlt` in RFC 3637 and does not admit or-patterns
+    /// or guard patterns at the top level. Used when parsing the parameters of lambda
+    /// expressions, functions, function pointers, and `pat_param` macro fragments.
     pub fn parse_pat_no_top_alt(
         &mut self,
         expected: Option<Expected>,
@@ -112,25 +137,26 @@ impl<'a> Parser<'a> {
 
     /// Parses a pattern.
     ///
-    /// Corresponds to `top_pat` in RFC 2535 and allows or-pattern at the top level.
-    /// Used for parsing patterns in all cases when `pat<no_top_alt>` is not used.
+    /// Corresponds to `PatternNoTopGuard` in RFC 3637 and allows or-patterns, but not
+    /// guard patterns, at the top level. Used for parsing patterns in `pat` fragments (until
+    /// the next edition) and `let`, `if let`, and `while let` expressions.
     ///
     /// Note that after the FCP in <https://github.com/rust-lang/rust/issues/81415>,
     /// a leading vert is allowed in nested or-patterns, too. This allows us to
     /// simplify the grammar somewhat.
-    pub fn parse_pat_allow_top_alt(
+    pub fn parse_pat_no_top_guard(
         &mut self,
         expected: Option<Expected>,
         rc: RecoverComma,
         ra: RecoverColon,
         rt: CommaRecoveryMode,
     ) -> PResult<'a, P<Pat>> {
-        self.parse_pat_allow_top_alt_inner(expected, rc, ra, rt, None).map(|(pat, _)| pat)
+        self.parse_pat_no_top_guard_inner(expected, rc, ra, rt, None).map(|(pat, _)| pat)
     }
 
     /// Returns the pattern and a bool indicating whether we recovered from a trailing vert (true =
     /// recovered).
-    fn parse_pat_allow_top_alt_inner(
+    fn parse_pat_no_top_guard_inner(
         &mut self,
         expected: Option<Expected>,
         rc: RecoverComma,
@@ -231,7 +257,7 @@ impl<'a> Parser<'a> {
         // We use `parse_pat_allow_top_alt` regardless of whether we actually want top-level
         // or-patterns so that we can detect when a user tries to use it. This allows us to print a
         // better error message.
-        let (pat, trailing_vert) = self.parse_pat_allow_top_alt_inner(
+        let (pat, trailing_vert) = self.parse_pat_no_top_guard_inner(
             expected,
             rc,
             RecoverColon::No,
@@ -696,7 +722,7 @@ impl<'a> Parser<'a> {
         } else if self.check(&token::OpenDelim(Delimiter::Bracket)) {
             // Parse `[pat, pat,...]` as a slice pattern.
             let (pats, _) = self.parse_delim_comma_seq(Delimiter::Bracket, |p| {
-                p.parse_pat_allow_top_alt(
+                p.parse_pat_allow_top_guard(
                     None,
                     RecoverComma::No,
                     RecoverColon::No,
@@ -944,7 +970,7 @@ impl<'a> Parser<'a> {
         let open_paren = self.token.span;
 
         let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| {
-            p.parse_pat_allow_top_alt(
+            p.parse_pat_allow_top_guard(
                 None,
                 RecoverComma::No,
                 RecoverColon::No,
@@ -1361,7 +1387,7 @@ impl<'a> Parser<'a> {
         path: Path,
     ) -> PResult<'a, PatKind> {
         let (fields, _) = self.parse_paren_comma_seq(|p| {
-            p.parse_pat_allow_top_alt(
+            p.parse_pat_allow_top_guard(
                 None,
                 RecoverComma::No,
                 RecoverColon::No,
@@ -1396,7 +1422,7 @@ impl<'a> Parser<'a> {
         self.parse_builtin(|self_, _lo, ident| {
             Ok(match ident.name {
                 // builtin#deref(PAT)
-                sym::deref => Some(ast::PatKind::Deref(self_.parse_pat_allow_top_alt(
+                sym::deref => Some(ast::PatKind::Deref(self_.parse_pat_allow_top_guard(
                     None,
                     RecoverComma::Yes,
                     RecoverColon::Yes,
@@ -1671,7 +1697,7 @@ impl<'a> Parser<'a> {
             // Parsing a pattern of the form `fieldname: pat`.
             let fieldname = self.parse_field_name()?;
             self.bump();
-            let pat = self.parse_pat_allow_top_alt(
+            let pat = self.parse_pat_allow_top_guard(
                 None,
                 RecoverComma::No,
                 RecoverColon::No,
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 2f19a9b6b20..6a7029a8f1c 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -469,7 +469,7 @@ impl<'a> Parser<'a> {
             PathStyle::Pat
                 if let Ok(_) = self
                     .parse_paren_comma_seq(|p| {
-                        p.parse_pat_allow_top_alt(
+                        p.parse_pat_allow_top_guard(
                             None,
                             RecoverComma::No,
                             RecoverColon::No,
diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs
index b8f66a2b2ec..f2a37307cee 100644
--- a/compiler/rustc_passes/src/input_stats.rs
+++ b/compiler/rustc_passes/src/input_stats.rs
@@ -555,6 +555,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
             Slice,
             Rest,
             Never,
+            Guard,
             Paren,
             MacCall,
             Err
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index a1917fed4d9..d2bb0b3f277 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -198,12 +198,12 @@ trait QueryConfigRestored<'tcx> {
     -> Self::RestoredValue;
 }
 
-pub fn query_system<'tcx>(
+pub fn query_system<'a>(
     local_providers: Providers,
     extern_providers: ExternProviders,
-    on_disk_cache: Option<OnDiskCache<'tcx>>,
+    on_disk_cache: Option<OnDiskCache>,
     incremental: bool,
-) -> QuerySystem<'tcx> {
+) -> QuerySystem<'a> {
     QuerySystem {
         states: Default::default(),
         arenas: Default::default(),
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 7db3b7b7d9d..993d111466b 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -19,7 +19,6 @@ use rustc_errors::emitter::{
     DynEmitter, HumanEmitter, HumanReadableErrorType, OutputTheme, stderr_destination,
 };
 use rustc_errors::json::JsonEmitter;
-use rustc_errors::registry::Registry;
 use rustc_errors::{
     Diag, DiagCtxt, DiagCtxtHandle, DiagMessage, Diagnostic, ErrorGuaranteed, FatalAbort,
     FluentBundle, LazyFallbackBundle, TerminalUrl, fallback_fluent_bundle,
@@ -276,11 +275,11 @@ impl Session {
     }
 
     /// Invoked all the way at the end to finish off diagnostics printing.
-    pub fn finish_diagnostics(&self, registry: &Registry) -> Option<ErrorGuaranteed> {
+    pub fn finish_diagnostics(&self) -> Option<ErrorGuaranteed> {
         let mut guar = None;
         guar = guar.or(self.check_miri_unleashed_features());
         guar = guar.or(self.dcx().emit_stashed_diagnostics());
-        self.dcx().print_error_count(registry);
+        self.dcx().print_error_count();
         if self.opts.json_future_incompat {
             self.dcx().emit_future_breakage_report();
         }
@@ -880,7 +879,6 @@ impl Session {
 #[allow(rustc::bad_opt_access)]
 fn default_emitter(
     sopts: &config::Options,
-    registry: rustc_errors::registry::Registry,
     source_map: Lrc<SourceMap>,
     bundle: Option<Lrc<FluentBundle>>,
     fallback_bundle: LazyFallbackBundle,
@@ -943,7 +941,6 @@ fn default_emitter(
                 json_rendered,
                 color_config,
             )
-            .registry(Some(registry))
             .fluent_bundle(bundle)
             .ui_testing(sopts.unstable_opts.ui_testing)
             .ignored_directories_in_source_blocks(
@@ -999,11 +996,11 @@ pub fn build_session(
         sopts.unstable_opts.translate_directionality_markers,
     );
     let source_map = rustc_span::source_map::get_source_map().unwrap();
-    let emitter =
-        default_emitter(&sopts, registry, Lrc::clone(&source_map), bundle, fallback_bundle);
+    let emitter = default_emitter(&sopts, Lrc::clone(&source_map), bundle, fallback_bundle);
 
-    let mut dcx =
-        DiagCtxt::new(emitter).with_flags(sopts.unstable_opts.dcx_flags(can_emit_warnings));
+    let mut dcx = DiagCtxt::new(emitter)
+        .with_flags(sopts.unstable_opts.dcx_flags(can_emit_warnings))
+        .with_registry(registry);
     if let Some(ice_file) = ice_file {
         dcx = dcx.with_ice_file(ice_file);
     }
diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs
index d4b034ea219..614c9169d66 100644
--- a/compiler/rustc_smir/src/rustc_internal/mod.rs
+++ b/compiler/rustc_smir/src/rustc_internal/mod.rs
@@ -342,8 +342,9 @@ macro_rules! run_driver {
 
             /// Runs the compiler against given target and tests it with `test_function`
             pub fn run(&mut self) -> Result<C, CompilerError<B>> {
-                let compiler_result = rustc_driver::catch_fatal_errors(|| {
-                    RunCompiler::new(&self.args.clone(), self).run()
+                let compiler_result = rustc_driver::catch_fatal_errors(|| -> interface::Result::<()> {
+                    RunCompiler::new(&self.args.clone(), self).run();
+                    Ok(())
                 });
                 match (compiler_result, self.result.take()) {
                     (Ok(Ok(())), Some(ControlFlow::Continue(value))) => Ok(value),
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 57c645bfaba..958d4f0c251 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -51,6 +51,7 @@ pub mod source_map;
 use source_map::{SourceMap, SourceMapInputs};
 
 pub use self::caching_source_map_view::CachingSourceMapView;
+use crate::fatal_error::FatalError;
 
 pub mod edition;
 use edition::Edition;
@@ -2614,6 +2615,10 @@ impl ErrorGuaranteed {
     pub fn unchecked_error_guaranteed() -> Self {
         ErrorGuaranteed(())
     }
+
+    pub fn raise_fatal(self) -> ! {
+        FatalError.raise()
+    }
 }
 
 impl<E: rustc_serialize::Encoder> Encodable<E> for ErrorGuaranteed {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index a7dc20a874b..818d4afffc6 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -999,6 +999,7 @@ symbols! {
         global_registration,
         globs,
         gt,
+        guard_patterns,
         half_open_range_patterns,
         half_open_range_patterns_in_slices,
         hash,
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
index 8ba7969207e..f856a8d7abb 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -52,7 +52,9 @@ use std::{cmp, fmt, iter};
 
 use rustc_abi::ExternAbi;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
-use rustc_errors::{Applicability, Diag, DiagStyledString, IntoDiagArg, StringPart, pluralize};
+use rustc_errors::{
+    Applicability, Diag, DiagStyledString, IntoDiagArg, MultiSpan, StringPart, pluralize,
+};
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
@@ -67,6 +69,7 @@ use rustc_middle::ty::{
     self, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable,
     TypeVisitableExt,
 };
+use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::{BytePos, DesugaringKind, Pos, Span, sym};
 use tracing::{debug, instrument};
 
@@ -211,7 +214,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     }
 
     /// Adds a note if the types come from similarly named crates
-    fn check_and_note_conflicting_crates(&self, err: &mut Diag<'_>, terr: TypeError<'tcx>) {
+    fn check_and_note_conflicting_crates(&self, err: &mut Diag<'_>, terr: TypeError<'tcx>) -> bool {
+        // FIXME(estebank): unify with `report_similar_impl_candidates`. The message is similar,
+        // even if the logic needed to detect the case is very different.
         use hir::def_id::CrateNum;
         use rustc_hir::definitions::DisambiguatedDefPathData;
         use ty::GenericArg;
@@ -285,7 +290,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             }
         }
 
-        let report_path_match = |err: &mut Diag<'_>, did1: DefId, did2: DefId| {
+        let report_path_match = |err: &mut Diag<'_>, did1: DefId, did2: DefId, ty: &str| -> bool {
             // Only report definitions from different crates. If both definitions
             // are from a local module we could have false positives, e.g.
             // let _ = [{struct Foo; Foo}, {struct Foo; Foo}];
@@ -297,24 +302,112 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
                 // We compare strings because DefPath can be different
                 // for imported and non-imported crates
+                let expected_str = self.tcx.def_path_str(did1);
+                let found_str = self.tcx.def_path_str(did2);
+                let Ok(expected_abs) = abs_path(did1) else { return false };
+                let Ok(found_abs) = abs_path(did2) else { return false };
                 let same_path = || -> Result<_, PrintError> {
-                    Ok(self.tcx.def_path_str(did1) == self.tcx.def_path_str(did2)
-                        || abs_path(did1)? == abs_path(did2)?)
+                    Ok(expected_str == found_str || expected_abs == found_abs)
+                };
+                // We want to use as unique a type path as possible. If both types are "locally
+                // known" by the same name, we use the "absolute path" which uses the original
+                // crate name instead.
+                let (expected, found) = if expected_str == found_str {
+                    (expected_abs.join("::"), found_abs.join("::"))
+                } else {
+                    (expected_str.clone(), found_str.clone())
                 };
                 if same_path().unwrap_or(false) {
-                    let crate_name = self.tcx.crate_name(did1.krate);
-                    let msg = if did1.is_local() || did2.is_local() {
+                    // We've displayed "expected `a::b`, found `a::b`". We add context to
+                    // differentiate the different cases where that might happen.
+                    let expected_crate_name = self.tcx.crate_name(did1.krate);
+                    let found_crate_name = self.tcx.crate_name(did2.krate);
+                    let same_crate = expected_crate_name == found_crate_name;
+                    let expected_sp = self.tcx.def_span(did1);
+                    let found_sp = self.tcx.def_span(did2);
+
+                    let both_direct_dependencies = if !did1.is_local()
+                        && !did2.is_local()
+                        && let Some(data1) = self.tcx.extern_crate(did1.krate)
+                        && let Some(data2) = self.tcx.extern_crate(did2.krate)
+                        && data1.dependency_of == LOCAL_CRATE
+                        && data2.dependency_of == LOCAL_CRATE
+                    {
+                        // If both crates are directly depended on, we don't want to mention that
+                        // in the final message, as it is redundant wording.
+                        // We skip the case of semver trick, where one version of the local crate
+                        // depends on another version of itself by checking that both crates at play
+                        // are not the current one.
+                        true
+                    } else {
+                        false
+                    };
+
+                    let mut span: MultiSpan = vec![expected_sp, found_sp].into();
+                    span.push_span_label(
+                        self.tcx.def_span(did1),
+                        format!("this is the expected {ty} `{expected}`"),
+                    );
+                    span.push_span_label(
+                        self.tcx.def_span(did2),
+                        format!("this is the found {ty} `{found}`"),
+                    );
+                    for def_id in [did1, did2] {
+                        let crate_name = self.tcx.crate_name(def_id.krate);
+                        if !def_id.is_local()
+                            && let Some(data) = self.tcx.extern_crate(def_id.krate)
+                        {
+                            let descr = if same_crate {
+                                "one version of".to_string()
+                            } else {
+                                format!("one {ty} comes from")
+                            };
+                            let dependency = if both_direct_dependencies {
+                                if let rustc_session::cstore::ExternCrateSource::Extern(def_id) =
+                                    data.src
+                                    && let Some(name) = self.tcx.opt_item_name(def_id)
+                                {
+                                    format!(", which is renamed locally to `{name}`")
+                                } else {
+                                    String::new()
+                                }
+                            } else if data.dependency_of == LOCAL_CRATE {
+                                ", as a direct dependency of the current crate".to_string()
+                            } else {
+                                let dep = self.tcx.crate_name(data.dependency_of);
+                                format!(", as a dependency of crate `{dep}`")
+                            };
+                            span.push_span_label(
+                                data.span,
+                                format!("{descr} crate `{crate_name}` used here{dependency}"),
+                            );
+                        }
+                    }
+                    let msg = if (did1.is_local() || did2.is_local()) && same_crate {
+                        format!(
+                            "the crate `{expected_crate_name}` is compiled multiple times, \
+                             possibly with different configurations",
+                        )
+                    } else if same_crate {
                         format!(
-                            "the crate `{crate_name}` is compiled multiple times, possibly with different configurations"
+                            "two different versions of crate `{expected_crate_name}` are being \
+                             used; two types coming from two different versions of the same crate \
+                             are different types even if they look the same",
                         )
                     } else {
                         format!(
-                            "perhaps two different versions of crate `{crate_name}` are being used?"
+                            "two types coming from two different crates are different types even \
+                             if they look the same",
                         )
                     };
-                    err.note(msg);
+                    err.span_note(span, msg);
+                    if same_crate {
+                        err.help("you can use `cargo tree` to explore your dependency tree");
+                    }
+                    return true;
                 }
             }
+            false
         };
         match terr {
             TypeError::Sorts(ref exp_found) => {
@@ -323,14 +416,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 if let (&ty::Adt(exp_adt, _), &ty::Adt(found_adt, _)) =
                     (exp_found.expected.kind(), exp_found.found.kind())
                 {
-                    report_path_match(err, exp_adt.did(), found_adt.did());
+                    return report_path_match(err, exp_adt.did(), found_adt.did(), "type");
                 }
             }
             TypeError::Traits(ref exp_found) => {
-                report_path_match(err, exp_found.expected, exp_found.found);
+                return report_path_match(err, exp_found.expected, exp_found.found, "trait");
             }
             _ => (), // FIXME(#22750) handle traits and stuff
         }
+        false
     }
 
     fn note_error_origin(
@@ -1409,6 +1503,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             label_or_note(span, terr.to_string(self.tcx));
         }
 
+        if self.check_and_note_conflicting_crates(diag, terr) {
+            return;
+        }
+
         if let Some((expected, found, path)) = expected_found {
             let (expected_label, found_label, exp_found) = match exp_found {
                 Mismatch::Variable(ef) => (
@@ -1470,15 +1568,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         |prim: Ty<'tcx>, shadow: Ty<'tcx>, defid: DefId, diag: &mut Diag<'_>| {
                             let name = shadow.sort_string(self.tcx);
                             diag.note(format!(
-                                "{prim} and {name} have similar names, but are actually distinct types"
+                                "`{prim}` and {name} have similar names, but are actually distinct types"
+                            ));
+                            diag.note(format!(
+                                "one `{prim}` is a primitive defined by the language",
                             ));
-                            diag.note(format!("{prim} is a primitive defined by the language"));
                             let def_span = self.tcx.def_span(defid);
                             let msg = if defid.is_local() {
-                                format!("{name} is defined in the current crate")
+                                format!("the other {name} is defined in the current crate")
                             } else {
                                 let crate_name = self.tcx.crate_name(defid.krate);
-                                format!("{name} is defined in crate `{crate_name}`")
+                                format!("the other {name} is defined in crate `{crate_name}`")
                             };
                             diag.span_note(def_span, msg);
                         };
@@ -1666,8 +1766,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             }
         }
 
-        self.check_and_note_conflicting_crates(diag, terr);
-
         self.note_and_explain_type_err(diag, terr, cause, span, cause.body_id.to_def_id());
         if let Some(exp_found) = exp_found
             && let exp_found = TypeError::Sorts(exp_found)
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 90b18253629..4fb02f60943 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -1745,9 +1745,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     };
                     (
                         data.span,
-                        format!(
-                            "one version of crate `{crate_name}` is used here, as a {dependency}"
-                        ),
+                        format!("one version of crate `{crate_name}` used here, as a {dependency}"),
                     )
                 })
             {
diff --git a/library/core/src/bool.rs b/library/core/src/bool.rs
index 58a870d2e07..1590b9f29fc 100644
--- a/library/core/src/bool.rs
+++ b/library/core/src/bool.rs
@@ -54,6 +54,7 @@ impl bool {
     /// // `then`.
     /// assert_eq!(a, 1);
     /// ```
+    #[doc(alias = "then_with")]
     #[stable(feature = "lazy_bool_to_option", since = "1.50.0")]
     #[cfg_attr(not(test), rustc_diagnostic_item = "bool_then")]
     #[inline]
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index 802b571c510..3e53c0497cc 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -3577,34 +3577,44 @@ pub const fn discriminant_value<T>(_v: &T) -> <T as DiscriminantKind>::Discrimin
     unimplemented!()
 }
 
-extern "rust-intrinsic" {
-    /// Rust's "try catch" construct for unwinding. Invokes the function pointer `try_fn` with the
-    /// data pointer `data`, and calls `catch_fn` if unwinding occurs while `try_fn` runs.
-    ///
-    /// `catch_fn` must not unwind.
-    ///
-    /// The third argument is a function called if an unwind occurs (both Rust `panic` and foreign
-    /// unwinds). This function takes the data pointer and a pointer to the target- and
-    /// runtime-specific exception object that was caught.
-    ///
-    /// Note that in the case of a foreign unwinding operation, the exception object data may not be
-    /// safely usable from Rust, and should not be directly exposed via the standard library. To
-    /// prevent unsafe access, the library implementation may either abort the process or present an
-    /// opaque error type to the user.
-    ///
-    /// For more information, see the compiler's source, as well as the documentation for the stable
-    /// version of this intrinsic, `std::panic::catch_unwind`.
-    #[rustc_nounwind]
-    pub fn catch_unwind(try_fn: fn(*mut u8), data: *mut u8, catch_fn: fn(*mut u8, *mut u8)) -> i32;
-
-    /// Emits a `nontemporal` store, which gives a hint to the CPU that the data should not be held
-    /// in cache. Except for performance, this is fully equivalent to `ptr.write(val)`.
-    ///
-    /// Not all architectures provide such an operation. For instance, x86 does not: while `MOVNT`
-    /// exists, that operation is *not* equivalent to `ptr.write(val)` (`MOVNT` writes can be reordered
-    /// in ways that are not allowed for regular writes).
-    #[rustc_nounwind]
-    pub fn nontemporal_store<T>(ptr: *mut T, val: T);
+/// Rust's "try catch" construct for unwinding. Invokes the function pointer `try_fn` with the
+/// data pointer `data`, and calls `catch_fn` if unwinding occurs while `try_fn` runs.
+///
+/// `catch_fn` must not unwind.
+///
+/// The third argument is a function called if an unwind occurs (both Rust `panic` and foreign
+/// unwinds). This function takes the data pointer and a pointer to the target- and
+/// runtime-specific exception object that was caught.
+///
+/// Note that in the case of a foreign unwinding operation, the exception object data may not be
+/// safely usable from Rust, and should not be directly exposed via the standard library. To
+/// prevent unsafe access, the library implementation may either abort the process or present an
+/// opaque error type to the user.
+///
+/// For more information, see the compiler's source, as well as the documentation for the stable
+/// version of this intrinsic, `std::panic::catch_unwind`.
+#[rustc_intrinsic]
+#[rustc_intrinsic_must_be_overridden]
+#[rustc_nounwind]
+pub unsafe fn catch_unwind(
+    _try_fn: fn(*mut u8),
+    _data: *mut u8,
+    _catch_fn: fn(*mut u8, *mut u8),
+) -> i32 {
+    unreachable!()
+}
+
+/// Emits a `nontemporal` store, which gives a hint to the CPU that the data should not be held
+/// in cache. Except for performance, this is fully equivalent to `ptr.write(val)`.
+///
+/// Not all architectures provide such an operation. For instance, x86 does not: while `MOVNT`
+/// exists, that operation is *not* equivalent to `ptr.write(val)` (`MOVNT` writes can be reordered
+/// in ways that are not allowed for regular writes).
+#[rustc_intrinsic]
+#[rustc_intrinsic_must_be_overridden]
+#[rustc_nounwind]
+pub unsafe fn nontemporal_store<T>(_ptr: *mut T, _val: T) {
+    unreachable!()
 }
 
 /// See documentation of `<*const T>::offset_from` for details.
diff --git a/library/std/src/env.rs b/library/std/src/env.rs
index 043747d0bc5..535236ff89a 100644
--- a/library/std/src/env.rs
+++ b/library/std/src/env.rs
@@ -597,6 +597,13 @@ impl Error for JoinPathsError {
 
 /// Returns the path of the current user's home directory if known.
 ///
+/// This may return `None` if getting the directory fails or if the platform does not have user home directories.
+///
+/// For storing user data and configuration it is often preferable to use more specific directories.
+/// For example, [XDG Base Directories] on Unix or the `LOCALAPPDATA` and `APPDATA` environment variables on Windows.
+///
+/// [XDG Base Directories]: https://specifications.freedesktop.org/basedir-spec/latest/
+///
 /// # Unix
 ///
 /// - Returns the value of the 'HOME' environment variable if it is set
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index 56cf438bd9b..2313f4b5beb 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -12,7 +12,7 @@ use crate::cell::{Cell, RefCell};
 use crate::error::Error;
 use crate::fmt;
 
-/// A thread local storage key which owns its contents.
+/// A thread local storage (TLS) key which owns its contents.
 ///
 /// This key uses the fastest possible implementation available to it for the
 /// target platform. It is instantiated with the [`thread_local!`] macro and the
diff --git a/src/etc/lldb_commands b/src/etc/lldb_commands
index 4be2dba34f6..ef0c3740f03 100644
--- a/src/etc/lldb_commands
+++ b/src/etc/lldb_commands
@@ -1,4 +1,25 @@
-type synthetic add -l lldb_lookup.synthetic_lookup -x ".*" --category Rust
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)String$" --category Rust
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^&(mut )?str$" --category Rust
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^&(mut )?\\[.+\\]$" --category Rust
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::ffi::([a-z_]+::)+)OsString$" --category Rust
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)Vec<.+>$" --category Rust
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)VecDeque<.+>$" --category Rust
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)BTreeSet<.+>$" --category Rust
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)BTreeMap<.+>$" --category Rust
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::collections::([a-z_]+::)+)HashMap<.+>$" --category Rust
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::collections::([a-z_]+::)+)HashSet<.+>$" --category Rust
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)Rc<.+>$" --category Rust
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)Arc<.+>$" --category Rust
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)Cell<.+>$" --category Rust
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)Ref<.+>$" --category Rust
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)RefMut<.+>$" --category Rust
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)RefCell<.+>$" --category Rust
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)NonZero<.+>$" --category Rust
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^core::num::([a-z_]+::)*NonZero.+$" --category Rust
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::([a-z_]+::)+)PathBuf$" --category Rust
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^&(mut )?(std::([a-z_]+::)+)Path$" --category Rust
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^(.*)$" --category Rust
+type summary add -F _ -e -x -h "^.*$" --category Rust
 type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)String$" --category Rust
 type summary add -F lldb_lookup.summary_lookup  -e -x -h "^&(mut )?str$" --category Rust
 type summary add -F lldb_lookup.summary_lookup  -e -x -h "^&(mut )?\\[.+\\]$" --category Rust
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index a562a9eee71..0dda3466a71 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -5,12 +5,12 @@ use std::{io, mem};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::unord::UnordSet;
+use rustc_errors::TerminalUrl;
 use rustc_errors::codes::*;
 use rustc_errors::emitter::{
     DynEmitter, HumanEmitter, HumanReadableErrorType, OutputTheme, stderr_destination,
 };
 use rustc_errors::json::JsonEmitter;
-use rustc_errors::{ErrorGuaranteed, TerminalUrl};
 use rustc_feature::UnstableFeatures;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId};
@@ -326,7 +326,7 @@ pub(crate) fn run_global_ctxt(
     show_coverage: bool,
     render_options: RenderOptions,
     output_format: OutputFormat,
-) -> Result<(clean::Crate, RenderOptions, Cache), ErrorGuaranteed> {
+) -> (clean::Crate, RenderOptions, Cache) {
     // Certain queries assume that some checks were run elsewhere
     // (see https://github.com/rust-lang/rust/pull/73566#issuecomment-656954425),
     // so type-check everything other than function bodies in this crate before running lints.
@@ -340,9 +340,7 @@ pub(crate) fn run_global_ctxt(
         tcx.hir().try_par_for_each_module(|module| tcx.ensure().check_mod_type_wf(module))
     });
 
-    if let Some(guar) = tcx.dcx().has_errors() {
-        return Err(guar);
-    }
+    tcx.dcx().abort_if_errors();
 
     tcx.sess.time("missing_docs", || rustc_lint::check_crate(tcx));
     tcx.sess.time("check_mod_attrs", || {
@@ -446,11 +444,9 @@ pub(crate) fn run_global_ctxt(
         LinkCollector { cx: &mut ctxt, visited_links: visited, ambiguous_links: ambiguous };
     collector.resolve_ambiguities();
 
-    if let Some(guar) = tcx.dcx().has_errors() {
-        return Err(guar);
-    }
+    tcx.dcx().abort_if_errors();
 
-    Ok((krate, ctxt.render_options, ctxt.cache))
+    (krate, ctxt.render_options, ctxt.cache)
 }
 
 /// Due to <https://github.com/rust-lang/rust/pull/73566>,
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index da1316a19cc..70d9269ae5c 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -16,7 +16,7 @@ pub(crate) use markdown::test as test_markdown;
 use rustc_ast as ast;
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
 use rustc_errors::emitter::HumanReadableErrorType;
-use rustc_errors::{ColorConfig, DiagCtxtHandle, ErrorGuaranteed, FatalError};
+use rustc_errors::{ColorConfig, DiagCtxtHandle};
 use rustc_hir::CRATE_HIR_ID;
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_interface::interface;
@@ -89,11 +89,7 @@ fn get_doctest_dir() -> io::Result<TempDir> {
     TempFileBuilder::new().prefix("rustdoctest").tempdir()
 }
 
-pub(crate) fn run(
-    dcx: DiagCtxtHandle<'_>,
-    input: Input,
-    options: RustdocOptions,
-) -> Result<(), ErrorGuaranteed> {
+pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions) {
     let invalid_codeblock_attributes_name = crate::lint::INVALID_CODEBLOCK_ATTRIBUTES.name;
 
     // See core::create_config for what's going on here.
@@ -167,7 +163,7 @@ pub(crate) fn run(
         Err(error) => return crate::wrap_return(dcx, Err(error)),
     };
     let args_path = temp_dir.path().join("rustdoc-cfgs");
-    crate::wrap_return(dcx, generate_args_file(&args_path, &options))?;
+    crate::wrap_return(dcx, generate_args_file(&args_path, &options));
 
     let CreateRunnableDocTests {
         standalone_tests,
@@ -179,7 +175,7 @@ pub(crate) fn run(
         ..
     } = interface::run_compiler(config, |compiler| {
         compiler.enter(|queries| {
-            let collector = queries.global_ctxt()?.enter(|tcx| {
+            let collector = queries.global_ctxt().enter(|tcx| {
                 let crate_name = tcx.crate_name(LOCAL_CRATE).to_string();
                 let crate_attrs = tcx.hir().attrs(CRATE_HIR_ID);
                 let opts = scrape_test_config(crate_name, crate_attrs, args_path);
@@ -196,13 +192,11 @@ pub(crate) fn run(
 
                 collector
             });
-            if compiler.sess.dcx().has_errors().is_some() {
-                FatalError.raise();
-            }
+            compiler.sess.dcx().abort_if_errors();
 
-            Ok(collector)
+            collector
         })
-    })?;
+    });
 
     run_tests(opts, &rustdoc_options, &unused_extern_reports, standalone_tests, mergeable_tests);
 
@@ -246,8 +240,6 @@ pub(crate) fn run(
             eprintln!("{unused_extern_json}");
         }
     }
-
-    Ok(())
 }
 
 pub(crate) fn run_tests(
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 8bc543f7e72..a384c286039 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -76,7 +76,7 @@ use std::process;
 use std::sync::Arc;
 use std::sync::atomic::AtomicBool;
 
-use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, FatalError};
+use rustc_errors::DiagCtxtHandle;
 use rustc_interface::interface;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{ErrorOutputType, RustcOptGroup, make_crate_type_option};
@@ -179,7 +179,8 @@ pub fn main() {
 
     let exit_code = rustc_driver::catch_with_exit_code(|| {
         let at_args = rustc_driver::args::raw_args(&early_dcx)?;
-        main_args(&mut early_dcx, &at_args, using_internal_features)
+        main_args(&mut early_dcx, &at_args, using_internal_features);
+        Ok(())
     });
     process::exit(exit_code);
 }
@@ -699,13 +700,10 @@ fn usage(argv0: &str) {
     );
 }
 
-/// A result type used by several functions under `main()`.
-type MainResult = Result<(), ErrorGuaranteed>;
-
-pub(crate) fn wrap_return(dcx: DiagCtxtHandle<'_>, res: Result<(), String>) -> MainResult {
+pub(crate) fn wrap_return(dcx: DiagCtxtHandle<'_>, res: Result<(), String>) {
     match res {
-        Ok(()) => dcx.has_errors().map_or(Ok(()), Err),
-        Err(err) => Err(dcx.err(err)),
+        Ok(()) => dcx.abort_if_errors(),
+        Err(err) => dcx.fatal(err),
     }
 }
 
@@ -714,17 +712,17 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>(
     renderopts: config::RenderOptions,
     cache: formats::cache::Cache,
     tcx: TyCtxt<'tcx>,
-) -> MainResult {
+) {
     match formats::run_format::<T>(krate, renderopts, cache, tcx) {
-        Ok(_) => tcx.dcx().has_errors().map_or(Ok(()), Err),
+        Ok(_) => tcx.dcx().abort_if_errors(),
         Err(e) => {
             let mut msg =
-                tcx.dcx().struct_err(format!("couldn't generate documentation: {}", e.error));
+                tcx.dcx().struct_fatal(format!("couldn't generate documentation: {}", e.error));
             let file = e.file.display().to_string();
             if !file.is_empty() {
                 msg.note(format!("failed to create or modify \"{file}\""));
             }
-            Err(msg.emit())
+            msg.emit();
         }
     }
 }
@@ -759,7 +757,7 @@ fn main_args(
     early_dcx: &mut EarlyDiagCtxt,
     at_args: &[String],
     using_internal_features: Arc<AtomicBool>,
-) -> MainResult {
+) {
     // Throw away the first argument, the name of the binary.
     // In case of at_args being empty, as might be the case by
     // passing empty argument array to execve under some platforms,
@@ -770,7 +768,7 @@ fn main_args(
     // the compiler with @empty_file as argv[0] and no more arguments.
     let at_args = at_args.get(1..).unwrap_or_default();
 
-    let args = rustc_driver::args::arg_expand_all(early_dcx, at_args)?;
+    let args = rustc_driver::args::arg_expand_all(early_dcx, at_args);
 
     let mut options = getopts::Options::new();
     for option in opts() {
@@ -788,7 +786,7 @@ fn main_args(
     let (input, options, render_options) =
         match config::Options::from_matches(early_dcx, &matches, args) {
             Some(opts) => opts,
-            None => return Ok(()),
+            None => return,
         };
 
     let dcx =
@@ -853,11 +851,11 @@ fn main_args(
 
         if sess.opts.describe_lints {
             rustc_driver::describe_lints(sess);
-            return Ok(());
+            return;
         }
 
         compiler.enter(|queries| {
-            let Ok(mut gcx) = queries.global_ctxt() else { FatalError.raise() };
+            let mut gcx = queries.global_ctxt();
             if sess.dcx().has_errors().is_some() {
                 sess.dcx().fatal("Compilation failed, aborting rustdoc");
             }
@@ -865,7 +863,7 @@ fn main_args(
             gcx.enter(|tcx| {
                 let (krate, render_opts, mut cache) = sess.time("run_global_ctxt", || {
                     core::run_global_ctxt(tcx, show_coverage, render_options, output_format)
-                })?;
+                });
                 info!("finished with rustc");
 
                 if let Some(options) = scrape_examples_options {
@@ -884,10 +882,10 @@ fn main_args(
                 if show_coverage {
                     // if we ran coverage, bail early, we don't need to also generate docs at this point
                     // (also we didn't load in any of the useful passes)
-                    return Ok(());
+                    return;
                 } else if run_check {
                     // Since we're in "check" mode, no need to generate anything beyond this point.
-                    return Ok(());
+                    return;
                 }
 
                 info!("going to format");
diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs
index 20d65d8cd9f..d9c277c047f 100644
--- a/src/librustdoc/passes/lint/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs
@@ -2,6 +2,7 @@
 
 use rustc_data_structures::sync::{Lock, Lrc};
 use rustc_errors::emitter::Emitter;
+use rustc_errors::registry::Registry;
 use rustc_errors::translation::{Translate, to_fluent_args};
 use rustc_errors::{Applicability, DiagCtxt, DiagInner, LazyFallbackBundle};
 use rustc_parse::{source_str_to_stream, unwrap_or_emit_fatal};
@@ -155,7 +156,7 @@ impl Translate for BufferEmitter {
 }
 
 impl Emitter for BufferEmitter {
-    fn emit_diagnostic(&mut self, diag: DiagInner) {
+    fn emit_diagnostic(&mut self, diag: DiagInner, _registry: &Registry) {
         let mut buffer = self.buffer.borrow_mut();
 
         let fluent_args = to_fluent_args(diag.args.iter());
diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs
index 980a9f7a47c..599671bd4d4 100644
--- a/src/librustdoc/scrape_examples.rs
+++ b/src/librustdoc/scrape_examples.rs
@@ -7,7 +7,6 @@ use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::DiagCtxtHandle;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{self as hir};
-use rustc_interface::interface;
 use rustc_macros::{Decodable, Encodable};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{self, TyCtxt};
@@ -275,7 +274,7 @@ pub(crate) fn run(
     tcx: TyCtxt<'_>,
     options: ScrapeExamplesOptions,
     bin_crate: bool,
-) -> interface::Result<()> {
+) {
     let inner = move || -> Result<(), String> {
         // Generates source files for examples
         renderopts.no_emit_shared = true;
@@ -329,8 +328,6 @@ pub(crate) fn run(
     if let Err(e) = inner() {
         tcx.dcx().fatal(e);
     }
-
-    Ok(())
 }
 
 // Note: the DiagCtxt must be passed in explicitly because sess isn't available while parsing
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
index 9d26bf930a1..50a97579df7 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -234,7 +234,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us
         // In the case of only two patterns, replacement adds net characters.
         | Ref(_, Mutability::Not)
         // Dealt with elsewhere.
-        | Or(_) | Paren(_) | Deref(_) => false,
+        | Or(_) | Paren(_) | Deref(_) | Guard(..) => false,
         // Transform `box x | ... | box y` into `box (x | y)`.
         //
         // The cases below until `Slice(...)` deal with *singleton* products.
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index c66837dc998..32ee668cda1 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -236,7 +236,8 @@ pub fn main() {
             let mut args: Vec<String> = orig_args.clone();
             pass_sysroot_env_if_given(&mut args, sys_root_env);
 
-            return rustc_driver::RunCompiler::new(&args, &mut DefaultCallbacks).run();
+            rustc_driver::RunCompiler::new(&args, &mut DefaultCallbacks).run();
+            return Ok(());
         }
 
         if orig_args.iter().any(|a| a == "--version" || a == "-V") {
@@ -296,12 +297,13 @@ pub fn main() {
             args.extend(clippy_args);
             rustc_driver::RunCompiler::new(&args, &mut ClippyCallbacks { clippy_args_var })
                 .set_using_internal_features(using_internal_features)
-                .run()
+                .run();
         } else {
             rustc_driver::RunCompiler::new(&args, &mut RustcCallbacks { clippy_args_var })
                 .set_using_internal_features(using_internal_features)
-                .run()
+                .run();
         }
+        return Ok(());
     }))
 }
 
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index bf4a3124075..a5a166af33b 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -37,8 +37,8 @@ use walkdir::WalkDir;
 
 use self::header::{EarlyProps, make_test_description};
 use crate::common::{
-    Config, Mode, PassMode, TestPaths, UI_EXTENSIONS, expected_output_path, output_base_dir,
-    output_relative_path,
+    CompareMode, Config, Mode, PassMode, TestPaths, UI_EXTENSIONS, expected_output_path,
+    output_base_dir, output_relative_path,
 };
 use crate::header::HeadersCache;
 use crate::util::logv;
@@ -273,6 +273,15 @@ pub fn parse_config(args: Vec<String>) -> Config {
     } else {
         matches.free.clone()
     };
+    let compare_mode = matches.opt_str("compare-mode").map(|s| {
+        s.parse().unwrap_or_else(|_| {
+            let variants: Vec<_> = CompareMode::STR_VARIANTS.iter().copied().collect();
+            panic!(
+                "`{s}` is not a valid value for `--compare-mode`, it should be one of: {}",
+                variants.join(", ")
+            );
+        })
+    });
     Config {
         bless: matches.opt_present("bless"),
         compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")),
@@ -342,9 +351,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
         only_modified: matches.opt_present("only-modified"),
         color,
         remote_test_client: matches.opt_str("remote-test-client").map(PathBuf::from),
-        compare_mode: matches
-            .opt_str("compare-mode")
-            .map(|s| s.parse().expect("invalid --compare-mode provided")),
+        compare_mode,
         rustfix_coverage: matches.opt_present("rustfix-coverage"),
         has_html_tidy,
         has_enzyme,
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 84269fd44a1..7b11bf3b121 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -22,7 +22,7 @@ use crate::common::{
     UI_STDERR, UI_STDOUT, UI_SVG, UI_WINDOWS_SVG, Ui, expected_output_path, incremental_dir,
     output_base_dir, output_base_name, output_testname_unique,
 };
-use crate::compute_diff::{write_diff, write_filtered_diff};
+use crate::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff};
 use crate::errors::{self, Error, ErrorKind};
 use crate::header::TestProps;
 use crate::read2::{Truncated, read2_abbreviated};
@@ -2295,17 +2295,31 @@ impl<'test> TestCx<'test> {
         match output_kind {
             TestOutput::Compile => {
                 if !self.props.dont_check_compiler_stdout {
-                    errors +=
-                        self.compare_output(stdout_kind, &normalized_stdout, &expected_stdout);
+                    errors += self.compare_output(
+                        stdout_kind,
+                        &normalized_stdout,
+                        &proc_res.stdout,
+                        &expected_stdout,
+                    );
                 }
                 if !self.props.dont_check_compiler_stderr {
-                    errors +=
-                        self.compare_output(stderr_kind, &normalized_stderr, &expected_stderr);
+                    errors += self.compare_output(
+                        stderr_kind,
+                        &normalized_stderr,
+                        &stderr,
+                        &expected_stderr,
+                    );
                 }
             }
             TestOutput::Run => {
-                errors += self.compare_output(stdout_kind, &normalized_stdout, &expected_stdout);
-                errors += self.compare_output(stderr_kind, &normalized_stderr, &expected_stderr);
+                errors += self.compare_output(
+                    stdout_kind,
+                    &normalized_stdout,
+                    &proc_res.stdout,
+                    &expected_stdout,
+                );
+                errors +=
+                    self.compare_output(stderr_kind, &normalized_stderr, &stderr, &expected_stderr);
             }
         }
         errors
@@ -2533,7 +2547,13 @@ impl<'test> TestCx<'test> {
         }
     }
 
-    fn compare_output(&self, stream: &str, actual: &str, expected: &str) -> usize {
+    fn compare_output(
+        &self,
+        stream: &str,
+        actual: &str,
+        actual_unnormalized: &str,
+        expected: &str,
+    ) -> usize {
         let are_different = match (self.force_color_svg(), expected.find('\n'), actual.find('\n')) {
             // FIXME: We ignore the first line of SVG files
             // because the width parameter is non-deterministic.
@@ -2590,28 +2610,14 @@ impl<'test> TestCx<'test> {
             if expected.is_empty() {
                 println!("normalized {}:\n{}\n", stream, actual);
             } else {
-                println!("diff of {stream}:\n");
-                if let Some(diff_command) = self.config.diff_command.as_deref() {
-                    let mut args = diff_command.split_whitespace();
-                    let name = args.next().unwrap();
-                    match Command::new(name)
-                        .args(args)
-                        .args([&expected_path, &actual_path])
-                        .output()
-                    {
-                        Err(err) => {
-                            self.fatal(&format!(
-                                "failed to call custom diff command `{diff_command}`: {err}"
-                            ));
-                        }
-                        Ok(output) => {
-                            let output = String::from_utf8_lossy(&output.stdout);
-                            print!("{output}");
-                        }
-                    }
-                } else {
-                    print!("{}", write_diff(expected, actual, 3));
-                }
+                self.show_diff(
+                    stream,
+                    &expected_path,
+                    &actual_path,
+                    expected,
+                    actual,
+                    actual_unnormalized,
+                );
             }
         } else {
             // Delete non-revision .stderr/.stdout file if revisions are used.
@@ -2633,6 +2639,76 @@ impl<'test> TestCx<'test> {
         if self.config.bless { 0 } else { 1 }
     }
 
+    /// Returns whether to show the full stderr/stdout.
+    fn show_diff(
+        &self,
+        stream: &str,
+        expected_path: &Path,
+        actual_path: &Path,
+        expected: &str,
+        actual: &str,
+        actual_unnormalized: &str,
+    ) {
+        eprintln!("diff of {stream}:\n");
+        if let Some(diff_command) = self.config.diff_command.as_deref() {
+            let mut args = diff_command.split_whitespace();
+            let name = args.next().unwrap();
+            match Command::new(name).args(args).args([expected_path, actual_path]).output() {
+                Err(err) => {
+                    self.fatal(&format!(
+                        "failed to call custom diff command `{diff_command}`: {err}"
+                    ));
+                }
+                Ok(output) => {
+                    let output = String::from_utf8_lossy(&output.stdout);
+                    eprint!("{output}");
+                }
+            }
+        } else {
+            eprint!("{}", write_diff(expected, actual, 3));
+        }
+
+        // NOTE: argument order is important, we need `actual` to be on the left so the line number match up when we compare it to `actual_unnormalized` below.
+        let diff_results = make_diff(actual, expected, 0);
+
+        let (mut mismatches_normalized, mut mismatch_line_nos) = (String::new(), vec![]);
+        for hunk in diff_results {
+            let mut line_no = hunk.line_number;
+            for line in hunk.lines {
+                // NOTE: `Expected` is actually correct here, the argument order is reversed so our line numbers match up
+                if let DiffLine::Expected(normalized) = line {
+                    mismatches_normalized += &normalized;
+                    mismatches_normalized += "\n";
+                    mismatch_line_nos.push(line_no);
+                    line_no += 1;
+                }
+            }
+        }
+        let mut mismatches_unnormalized = String::new();
+        let diff_normalized = make_diff(actual, actual_unnormalized, 0);
+        for hunk in diff_normalized {
+            if mismatch_line_nos.contains(&hunk.line_number) {
+                for line in hunk.lines {
+                    if let DiffLine::Resulting(unnormalized) = line {
+                        mismatches_unnormalized += &unnormalized;
+                        mismatches_unnormalized += "\n";
+                    }
+                }
+            }
+        }
+
+        let normalized_diff = make_diff(&mismatches_normalized, &mismatches_unnormalized, 0);
+        // HACK: instead of checking if each hunk is empty, this only checks if the whole input is empty. we should be smarter about this so we don't treat added or removed output as normalized.
+        if !normalized_diff.is_empty()
+            && !mismatches_unnormalized.is_empty()
+            && !mismatches_normalized.is_empty()
+        {
+            eprintln!("Note: some mismatched output was normalized before being compared");
+            // FIXME: respect diff_command
+            eprint!("{}", write_diff(&mismatches_unnormalized, &mismatches_normalized, 0));
+        }
+    }
+
     fn check_and_prune_duplicate_outputs(
         &self,
         proc_res: &ProcRes,
diff --git a/src/tools/compiletest/src/runtest/coverage.rs b/src/tools/compiletest/src/runtest/coverage.rs
index 961a1602986..030ca5ebb24 100644
--- a/src/tools/compiletest/src/runtest/coverage.rs
+++ b/src/tools/compiletest/src/runtest/coverage.rs
@@ -39,8 +39,12 @@ impl<'test> TestCx<'test> {
         let expected_coverage_dump = self.load_expected_output(kind);
         let actual_coverage_dump = self.normalize_output(&proc_res.stdout, &[]);
 
-        let coverage_dump_errors =
-            self.compare_output(kind, &actual_coverage_dump, &expected_coverage_dump);
+        let coverage_dump_errors = self.compare_output(
+            kind,
+            &actual_coverage_dump,
+            &proc_res.stdout,
+            &expected_coverage_dump,
+        );
 
         if coverage_dump_errors > 0 {
             self.fatal_proc_rec(
@@ -135,8 +139,12 @@ impl<'test> TestCx<'test> {
                 self.fatal_proc_rec(&err, &proc_res);
             });
 
-        let coverage_errors =
-            self.compare_output(kind, &normalized_actual_coverage, &expected_coverage);
+        let coverage_errors = self.compare_output(
+            kind,
+            &normalized_actual_coverage,
+            &proc_res.stdout,
+            &expected_coverage,
+        );
 
         if coverage_errors > 0 {
             self.fatal_proc_rec(
diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs
index bb747c68029..172b1e32aad 100644
--- a/src/tools/compiletest/src/runtest/ui.rs
+++ b/src/tools/compiletest/src/runtest/ui.rs
@@ -100,7 +100,7 @@ impl TestCx<'_> {
                 )
             });
 
-            errors += self.compare_output("fixed", &fixed_code, &expected_fixed);
+            errors += self.compare_output("fixed", &fixed_code, &fixed_code, &expected_fixed);
         } else if !expected_fixed.is_empty() {
             panic!(
                 "the `//@ run-rustfix` directive wasn't found but a `*.fixed` \
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 57d0b27dfd3..50710f55266 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-728f2daab42ba8f1b3d5caab62495798d1eabfa1
+1b3fb316751227d30b1523ed0e3f00d83956d4d0
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 2c4b02e2873..5248c9d186b 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -290,7 +290,8 @@ fn run_compiler(
     let exit_code = rustc_driver::catch_with_exit_code(move || {
         rustc_driver::RunCompiler::new(&args, callbacks)
             .set_using_internal_features(using_internal_features)
-            .run()
+            .run();
+        Ok(())
     });
     std::process::exit(exit_code)
 }
diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs
index 54ad56ed3f3..63cc8794cea 100644
--- a/src/tools/rustfmt/src/parse/session.rs
+++ b/src/tools/rustfmt/src/parse/session.rs
@@ -3,6 +3,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
 
 use rustc_data_structures::sync::{IntoDynSyncSend, Lrc};
 use rustc_errors::emitter::{DynEmitter, Emitter, HumanEmitter, SilentEmitter, stderr_destination};
+use rustc_errors::registry::Registry;
 use rustc_errors::translation::Translate;
 use rustc_errors::{ColorConfig, Diag, DiagCtxt, DiagInner, Level as DiagnosticLevel};
 use rustc_session::parse::ParseSess as RawParseSess;
@@ -38,10 +39,10 @@ struct SilentOnIgnoredFilesEmitter {
 }
 
 impl SilentOnIgnoredFilesEmitter {
-    fn handle_non_ignoreable_error(&mut self, diag: DiagInner) {
+    fn handle_non_ignoreable_error(&mut self, diag: DiagInner, registry: &Registry) {
         self.has_non_ignorable_parser_errors = true;
         self.can_reset.store(false, Ordering::Release);
-        self.emitter.emit_diagnostic(diag);
+        self.emitter.emit_diagnostic(diag, registry);
     }
 }
 
@@ -60,9 +61,9 @@ impl Emitter for SilentOnIgnoredFilesEmitter {
         None
     }
 
-    fn emit_diagnostic(&mut self, diag: DiagInner) {
+    fn emit_diagnostic(&mut self, diag: DiagInner, registry: &Registry) {
         if diag.level() == DiagnosticLevel::Fatal {
-            return self.handle_non_ignoreable_error(diag);
+            return self.handle_non_ignoreable_error(diag, registry);
         }
         if let Some(primary_span) = &diag.span.primary_span() {
             let file_name = self.source_map.span_to_filename(*primary_span);
@@ -80,7 +81,7 @@ impl Emitter for SilentOnIgnoredFilesEmitter {
                 }
             };
         }
-        self.handle_non_ignoreable_error(diag);
+        self.handle_non_ignoreable_error(diag, registry);
     }
 }
 
@@ -358,7 +359,7 @@ mod tests {
                 None
             }
 
-            fn emit_diagnostic(&mut self, _diag: DiagInner) {
+            fn emit_diagnostic(&mut self, _diag: DiagInner, _registry: &Registry) {
                 self.num_emitted_errors.fetch_add(1, Ordering::Release);
             }
         }
@@ -412,6 +413,7 @@ mod tests {
                 SourceMapFileName::Real(RealFileName::LocalPath(PathBuf::from("foo.rs"))),
                 source,
             );
+            let registry = Registry::new(&[]);
             let mut emitter = build_emitter(
                 Lrc::clone(&num_emitted_errors),
                 Lrc::clone(&can_reset_errors),
@@ -420,7 +422,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, &registry);
             assert_eq!(num_emitted_errors.load(Ordering::Acquire), 1);
             assert_eq!(can_reset_errors.load(Ordering::Acquire), false);
         }
@@ -437,6 +439,7 @@ mod tests {
                 SourceMapFileName::Real(RealFileName::LocalPath(PathBuf::from("foo.rs"))),
                 source,
             );
+            let registry = Registry::new(&[]);
             let mut emitter = build_emitter(
                 Lrc::clone(&num_emitted_errors),
                 Lrc::clone(&can_reset_errors),
@@ -445,7 +448,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, &registry);
             assert_eq!(num_emitted_errors.load(Ordering::Acquire), 0);
             assert_eq!(can_reset_errors.load(Ordering::Acquire), true);
         }
@@ -461,6 +464,7 @@ mod tests {
                 SourceMapFileName::Real(RealFileName::LocalPath(PathBuf::from("foo.rs"))),
                 source,
             );
+            let registry = Registry::new(&[]);
             let mut emitter = build_emitter(
                 Lrc::clone(&num_emitted_errors),
                 Lrc::clone(&can_reset_errors),
@@ -469,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, &registry);
             assert_eq!(num_emitted_errors.load(Ordering::Acquire), 1);
             assert_eq!(can_reset_errors.load(Ordering::Acquire), false);
         }
@@ -497,6 +501,7 @@ mod tests {
                 SourceMapFileName::Real(RealFileName::LocalPath(PathBuf::from("fatal.rs"))),
                 fatal_source,
             );
+            let registry = Registry::new(&[]);
             let mut emitter = build_emitter(
                 Lrc::clone(&num_emitted_errors),
                 Lrc::clone(&can_reset_errors),
@@ -508,9 +513,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, &registry);
+            emitter.emit_diagnostic(foo_diagnostic, &registry);
+            emitter.emit_diagnostic(fatal_diagnostic, &registry);
             assert_eq!(num_emitted_errors.load(Ordering::Acquire), 2);
             assert_eq!(can_reset_errors.load(Ordering::Acquire), false);
         }
diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs
index 6fe2d4a8520..7b4730eadc8 100644
--- a/src/tools/rustfmt/src/patterns.rs
+++ b/src/tools/rustfmt/src/patterns.rs
@@ -48,7 +48,8 @@ fn is_short_pattern_inner(pat: &ast::Pat) -> bool {
         | ast::PatKind::MacCall(..)
         | ast::PatKind::Slice(..)
         | ast::PatKind::Path(..)
-        | ast::PatKind::Range(..) => false,
+        | ast::PatKind::Range(..)
+        | ast::PatKind::Guard(..) => false,
         ast::PatKind::Tuple(ref subpats) => subpats.len() <= 1,
         ast::PatKind::TupleStruct(_, ref path, ref subpats) => {
             path.segments.len() <= 1 && subpats.len() <= 1
@@ -338,8 +339,9 @@ impl Rewrite for Pat {
                         .max_width_error(shape.width, self.span)?,
                 )
                 .map(|inner_pat| format!("({})", inner_pat)),
-            PatKind::Err(_) => Err(RewriteError::Unknown),
+            PatKind::Guard(..) => Ok(context.snippet(self.span).to_string()),
             PatKind::Deref(_) => Err(RewriteError::Unknown),
+            PatKind::Err(_) => Err(RewriteError::Unknown),
         }
     }
 }
diff --git a/src/tools/rustfmt/tests/target/guard_patterns.rs b/src/tools/rustfmt/tests/target/guard_patterns.rs
new file mode 100644
index 00000000000..2e4667b916c
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/guard_patterns.rs
@@ -0,0 +1,12 @@
+#![feature(guard_patterns)]
+
+fn main() {
+    match user.subscription_plan() {
+        (Plan::Regular if user.credit() >= 100) | (Plan::Premium if user.credit() >= 80) => {
+            // Complete the transaction.
+        }
+        _ => {
+            // The user doesn't have enough credit, return an error message.
+        }
+    }
+}
diff --git a/tests/crashes/121363.rs b/tests/crashes/121363.rs
index 2a5b6274496..38796342284 100644
--- a/tests/crashes/121363.rs
+++ b/tests/crashes/121363.rs
@@ -1,5 +1,5 @@
 //@ known-bug: #121363
-//@ compile-flags: -Zmir-opt-level=5 --crate-type lib
+//@ compile-flags: -Zmir-enable-passes=+GVN --crate-type lib
 
 #![feature(trivial_bounds)]
 
diff --git a/tests/crashes/128094.rs b/tests/crashes/128094.rs
index 105a1c84a65..5f0ae108f8f 100644
--- a/tests/crashes/128094.rs
+++ b/tests/crashes/128094.rs
@@ -1,5 +1,5 @@
 //@ known-bug: rust-lang/rust#128094
-//@ compile-flags: -Zmir-opt-level=5 --edition=2018
+//@ compile-flags: -Zmir-enable-passes=+GVN --edition=2018
 
 pub enum Request {
     TestSome(T),
diff --git a/tests/crashes/129095.rs b/tests/crashes/129095.rs
index ea70c0565fc..d82474e18e7 100644
--- a/tests/crashes/129095.rs
+++ b/tests/crashes/129095.rs
@@ -1,5 +1,5 @@
 //@ known-bug: rust-lang/rust#129095
-//@ compile-flags: -Zmir-opt-level=5 -Zvalidate-mir
+//@ compile-flags: -Zmir-enable-passes=+GVN -Zmir-enable-passes=+Inline -Zvalidate-mir
 
 pub fn function_with_bytes<const BYTES: &'static [u8; 4]>() -> &'static [u8] {
     BYTES
diff --git a/tests/crashes/129109.rs b/tests/crashes/129109.rs
index 8b9ebdf03c7..0db53b98a71 100644
--- a/tests/crashes/129109.rs
+++ b/tests/crashes/129109.rs
@@ -1,5 +1,5 @@
 //@ known-bug: rust-lang/rust#129109
-//@ compile-flags: -Zmir-opt-level=5 -Zvalidate-mir
+//@ compile-flags: -Zmir-enable-passes=+GVN -Zvalidate-mir
 
 extern "C" {
     pub static mut symbol: [i8];
diff --git a/tests/crashes/130970.rs b/tests/crashes/130970.rs
index e1f59c155a5..698c2b478e1 100644
--- a/tests/crashes/130970.rs
+++ b/tests/crashes/130970.rs
@@ -1,5 +1,5 @@
 //@ known-bug: #130970
-//@ compile-flags: -Zmir-opt-level=5 -Zvalidate-mir
+//@ compile-flags: -Zmir-enable-passes=+GVN -Zvalidate-mir
 
 fn main() {
     extern "C" {
diff --git a/tests/crashes/131347.rs b/tests/crashes/131347.rs
index 15f367d79e2..08f7d068e25 100644
--- a/tests/crashes/131347.rs
+++ b/tests/crashes/131347.rs
@@ -1,5 +1,5 @@
 //@ known-bug: #131347
-//@ compile-flags: -Zmir-opt-level=5 -Zvalidate-mir
+//@ compile-flags: -Zmir-enable-passes=+GVN -Zmir-enable-passes=+Inline -Zvalidate-mir
 
 struct S;
 static STUFF: [i8] = [0; S::N];
diff --git a/tests/crashes/131451.rs b/tests/crashes/131451.rs
new file mode 100644
index 00000000000..cd5b44bad8a
--- /dev/null
+++ b/tests/crashes/131451.rs
@@ -0,0 +1,9 @@
+//@ known-bug: #131451
+//@ needs-rustc-debug-assertions
+//@ compile-flags: -Zmir-enable-passes=+GVN -Zmir-enable-passes=+JumpThreading --crate-type=lib
+
+pub fn fun(terminate: bool) {
+    while true {}
+
+    while !terminate {}
+}
diff --git a/tests/crashes/131507.rs b/tests/crashes/131507.rs
index d402fb8afc3..05b5e76bed7 100644
--- a/tests/crashes/131507.rs
+++ b/tests/crashes/131507.rs
@@ -1,5 +1,5 @@
 //@ known-bug: #131507
-//@ compile-flags: -Zmir-opt-level=5 -Zvalidate-mir
+//@ compile-flags: -Zmir-enable-passes=+GVN -Zmir-enable-passes=+Inline -Zvalidate-mir
 #![feature(non_lifetime_binders)]
 
 fn brick()
diff --git a/tests/incremental/circular-dependencies.rs b/tests/incremental/circular-dependencies.rs
index 320edad3fde..c7b5b931fbb 100644
--- a/tests/incremental/circular-dependencies.rs
+++ b/tests/incremental/circular-dependencies.rs
@@ -6,10 +6,12 @@
 //@ [cfail2] compile-flags: --test --extern aux={{build-base}}/circular-dependencies/auxiliary/libcircular_dependencies_aux.rmeta -L dependency={{build-base}}/circular-dependencies
 
 pub struct Foo;
-//[cfail2]~^ NOTE `Foo` is defined in the current crate
-//[cfail2]~| NOTE `Foo` is defined in the current crate
-//[cfail2]~| NOTE `circular_dependencies::Foo` is defined in crate `circular_dependencies`
-//[cfail2]~| NOTE `circular_dependencies::Foo` is defined in crate `circular_dependencies`
+//[cfail2]~^ NOTE the crate `circular_dependencies` is compiled multiple times, possibly with different configurations
+//[cfail2]~| NOTE the crate `circular_dependencies` is compiled multiple times, possibly with different configurations
+//[cfail2]~| NOTE this is the expected type `Foo`
+//[cfail2]~| NOTE this is the expected type `circular_dependencies::Foo`
+//[cfail2]~| NOTE this is the found type `Foo`
+//[cfail2]~| NOTE this is the found type `circular_dependencies::Foo`
 
 pub fn consume_foo(_: Foo) {}
 //[cfail2]~^ NOTE function defined here
@@ -24,14 +26,12 @@ fn test() {
     //[cfail2]~^ ERROR mismatched types [E0308]
     //[cfail2]~| NOTE expected `circular_dependencies::Foo`, found `Foo`
     //[cfail2]~| NOTE arguments to this function are incorrect
-    //[cfail2]~| NOTE `Foo` and `circular_dependencies::Foo` have similar names, but are actually distinct types
-    //[cfail2]~| NOTE the crate `circular_dependencies` is compiled multiple times, possibly with different configurations
     //[cfail2]~| NOTE function defined here
+    //[cfail2]~| NOTE one version of crate `circular_dependencies` used here, as a dependency of crate `circular_dependencies_aux`
+    //[cfail2]~| NOTE one version of crate `circular_dependencies` used here, as a dependency of crate `circular_dependencies_aux`
 
     consume_foo(aux::produce_foo());
     //[cfail2]~^ ERROR mismatched types [E0308]
     //[cfail2]~| NOTE expected `Foo`, found `circular_dependencies::Foo`
     //[cfail2]~| NOTE arguments to this function are incorrect
-    //[cfail2]~| NOTE `circular_dependencies::Foo` and `Foo` have similar names, but are actually distinct types
-    //[cfail2]~| NOTE the crate `circular_dependencies` is compiled multiple times, possibly with different configurations
 }
diff --git a/tests/run-make/crate-loading-crate-depends-on-itself/foo.stderr b/tests/run-make/crate-loading-crate-depends-on-itself/foo.stderr
index 36379429530..7f131153540 100644
--- a/tests/run-make/crate-loading-crate-depends-on-itself/foo.stderr
+++ b/tests/run-make/crate-loading-crate-depends-on-itself/foo.stderr
@@ -8,7 +8,7 @@ note: there are multiple different versions of crate `foo` in the dependency gra
   --> foo-current.rs:7:1
    |
 4  | extern crate foo;
-   | ----------------- one version of crate `foo` is used here, as a direct dependency of the current crate
+   | ----------------- one version of crate `foo` used here, as a direct dependency of the current crate
 5  |
 6  | pub struct Struct;
    | ----------------- this type implements the required trait
diff --git a/tests/run-make/crate-loading/multiple-dep-versions-1.rs b/tests/run-make/crate-loading/multiple-dep-versions-1.rs
index d81462504dd..bfeabccf5c1 100644
--- a/tests/run-make/crate-loading/multiple-dep-versions-1.rs
+++ b/tests/run-make/crate-loading/multiple-dep-versions-1.rs
@@ -5,8 +5,11 @@ pub trait Trait {
     fn foo(&self);
     fn bar();
 }
+pub trait Trait2 {}
 impl Trait for Type {
     fn foo(&self) {}
     fn bar() {}
 }
 pub fn do_something<X: Trait>(_: X) {}
+pub fn do_something_type(_: Type) {}
+pub fn do_something_trait(_: Box<dyn Trait2>) {}
diff --git a/tests/run-make/crate-loading/multiple-dep-versions-2.rs b/tests/run-make/crate-loading/multiple-dep-versions-2.rs
index 0a566fe2c60..682d1ff64b8 100644
--- a/tests/run-make/crate-loading/multiple-dep-versions-2.rs
+++ b/tests/run-make/crate-loading/multiple-dep-versions-2.rs
@@ -5,8 +5,12 @@ pub trait Trait {
     fn foo(&self);
     fn bar();
 }
+pub trait Trait2 {}
+impl Trait2 for Type {}
 impl Trait for Type {
     fn foo(&self) {}
     fn bar() {}
 }
 pub fn do_something<X: Trait>(_: X) {}
+pub fn do_something_type(_: Type) {}
+pub fn do_something_trait(_: Box<dyn Trait2>) {}
diff --git a/tests/run-make/crate-loading/multiple-dep-versions-3.rs b/tests/run-make/crate-loading/multiple-dep-versions-3.rs
index f5c4d1baa81..07444511472 100644
--- a/tests/run-make/crate-loading/multiple-dep-versions-3.rs
+++ b/tests/run-make/crate-loading/multiple-dep-versions-3.rs
@@ -2,7 +2,7 @@
 #![crate_type = "rlib"]
 
 extern crate dependency;
-pub use dependency::Type;
+pub use dependency::{Trait2, Type, do_something_trait, do_something_type};
 pub struct OtherType;
 impl dependency::Trait for OtherType {
     fn foo(&self) {}
diff --git a/tests/run-make/crate-loading/multiple-dep-versions.rs b/tests/run-make/crate-loading/multiple-dep-versions.rs
index c68a9e6489f..3a4a20d38fc 100644
--- a/tests/run-make/crate-loading/multiple-dep-versions.rs
+++ b/tests/run-make/crate-loading/multiple-dep-versions.rs
@@ -1,11 +1,13 @@
 extern crate dep_2_reexport;
 extern crate dependency;
-use dep_2_reexport::{OtherType, Type};
-use dependency::{Trait, do_something};
+use dep_2_reexport::{OtherType, Trait2, Type};
+use dependency::{Trait, do_something, do_something_trait, do_something_type};
 
 fn main() {
     do_something(Type);
     Type.foo();
     Type::bar();
     do_something(OtherType);
+    do_something_type(Type);
+    do_something_trait(Box::new(Type) as Box<dyn Trait2>);
 }
diff --git a/tests/run-make/crate-loading/multiple-dep-versions.stderr b/tests/run-make/crate-loading/multiple-dep-versions.stderr
index 5888aad8f37..6e1d6111b58 100644
--- a/tests/run-make/crate-loading/multiple-dep-versions.stderr
+++ b/tests/run-make/crate-loading/multiple-dep-versions.stderr
@@ -17,9 +17,9 @@ LL | pub trait Trait {
   ::: replaced
    |
 LL | extern crate dep_2_reexport;
-   | ---------------------------- one version of crate `dependency` is used here, as a dependency of crate `foo`
+   | ---------------------------- one version of crate `dependency` used here, as a dependency of crate `foo`
 LL | extern crate dependency;
-   | ------------------------ one version of crate `dependency` is used here, as a direct dependency of the current crate
+   | ------------------------ one version of crate `dependency` used here, as a direct dependency of the current crate
    |
   ::: replaced
    |
@@ -51,7 +51,7 @@ LL |     fn foo(&self);
    |
   ::: replaced
    |
-LL | use dependency::{Trait, do_something};
+LL | use dependency::{Trait, do_something, do_something_trait, do_something_type};
    |                  ----- `Trait` imported here doesn't correspond to the right version of crate `dependency`
    |
   ::: replaced
@@ -76,7 +76,7 @@ LL |     fn bar();
    |
   ::: replaced
    |
-LL | use dependency::{Trait, do_something};
+LL | use dependency::{Trait, do_something, do_something_trait, do_something_type};
    |                  ----- `Trait` imported here doesn't correspond to the right version of crate `dependency`
    |
   ::: replaced
@@ -101,9 +101,9 @@ LL | pub trait Trait {
   ::: replaced
    |
 LL | extern crate dep_2_reexport;
-   | ---------------------------- one version of crate `dependency` is used here, as a dependency of crate `foo`
+   | ---------------------------- one version of crate `dependency` used here, as a dependency of crate `foo`
 LL | extern crate dependency;
-   | ------------------------ one version of crate `dependency` is used here, as a direct dependency of the current crate
+   | ------------------------ one version of crate `dependency` used here, as a direct dependency of the current crate
    |
   ::: replaced
    |
@@ -121,7 +121,71 @@ note: required by a bound in `do_something`
 LL | pub fn do_something<X: Trait>(_: X) {}
    |                        ^^^^^ required by this bound in `do_something`
 
-error: aborting due to 4 previous errors
+error[E0308]: mismatched types
+  --> replaced
+   |
+LL |     do_something_type(Type);
+   |     ----------------- ^^^^ expected `dependency::Type`, found `dep_2_reexport::Type`
+   |     |
+   |     arguments to this function are incorrect
+   |
+note: two different versions of crate `dependency` are being used; two types coming from two different versions of the same crate are different types even if they look the same
+  --> replaced
+   |
+LL | pub struct Type(pub i32);
+   | ^^^^^^^^^^^^^^^ this is the expected type `dependency::Type`
+   |
+  ::: replaced
+   |
+LL | pub struct Type;
+   | ^^^^^^^^^^^^^^^ this is the found type `dep_2_reexport::Type`
+   |
+  ::: replaced
+   |
+LL | extern crate dep_2_reexport;
+   | ---------------------------- one version of crate `dependency` used here, as a dependency of crate `foo`
+LL | extern crate dependency;
+   | ------------------------ one version of crate `dependency` used here, as a direct dependency of the current crate
+   = help: you can use `cargo tree` to explore your dependency tree
+note: function defined here
+  --> replaced
+   |
+LL | pub fn do_something_type(_: Type) {}
+   |        ^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> replaced
+   |
+LL |     do_something_trait(Box::new(Type) as Box<dyn Trait2>);
+   |     ------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait `dependency::Trait2`, found trait `dep_2_reexport::Trait2`
+   |     |
+   |     arguments to this function are incorrect
+   |
+note: two different versions of crate `dependency` are being used; two types coming from two different versions of the same crate are different types even if they look the same
+  --> replaced
+   |
+LL | pub trait Trait2 {}
+   | ^^^^^^^^^^^^^^^^ this is the expected trait `dependency::Trait2`
+   |
+  ::: replaced
+   |
+LL | pub trait Trait2 {}
+   | ^^^^^^^^^^^^^^^^ this is the found trait `dep_2_reexport::Trait2`
+   |
+  ::: replaced
+   |
+LL | extern crate dep_2_reexport;
+   | ---------------------------- one version of crate `dependency` used here, as a dependency of crate `foo`
+LL | extern crate dependency;
+   | ------------------------ one version of crate `dependency` used here, as a direct dependency of the current crate
+   = help: you can use `cargo tree` to explore your dependency tree
+note: function defined here
+  --> replaced
+   |
+LL | pub fn do_something_trait(_: Box<dyn Trait2>) {}
+   |        ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
 
-Some errors have detailed explanations: E0277, E0599.
+Some errors have detailed explanations: E0277, E0308, E0599.
 For more information about an error, try `rustc --explain E0277`.
\ No newline at end of file
diff --git a/tests/run-make/missing-unstable-trait-bound/missing-bound.rs b/tests/run-make/missing-unstable-trait-bound/missing-bound.rs
new file mode 100644
index 00000000000..65d0745f494
--- /dev/null
+++ b/tests/run-make/missing-unstable-trait-bound/missing-bound.rs
@@ -0,0 +1,4 @@
+pub fn baz<T>(t: std::ops::Range<T>) {
+    for _ in t {}
+}
+fn main() {}
diff --git a/tests/run-make/missing-unstable-trait-bound/missing-bound.stderr b/tests/run-make/missing-unstable-trait-bound/missing-bound.stderr
new file mode 100644
index 00000000000..7196a1a6fed
--- /dev/null
+++ b/tests/run-make/missing-unstable-trait-bound/missing-bound.stderr
@@ -0,0 +1,12 @@
+error[E0277]: the trait bound `T: Step` is not satisfied
+ --> missing-bound.rs:2:14
+  |
+2 |     for _ in t {}
+  |              ^ the trait `Step` is not implemented for `T`
+  |
+  = note: required for `std::ops::Range<T>` to implement `Iterator`
+  = note: required for `std::ops::Range<T>` to implement `IntoIterator`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/run-make/missing-unstable-trait-bound/rmake.rs b/tests/run-make/missing-unstable-trait-bound/rmake.rs
new file mode 100644
index 00000000000..20f77f7c9aa
--- /dev/null
+++ b/tests/run-make/missing-unstable-trait-bound/rmake.rs
@@ -0,0 +1,24 @@
+//@ only-linux
+//@ ignore-wasm32
+//@ ignore-wasm64
+// ignore-tidy-linelength
+
+// Ensure that on stable we don't suggest restricting with an unsafe trait and we continue
+// mentioning the rest of the obligation chain.
+
+use run_make_support::{diff, rust_lib_name, rustc};
+
+fn main() {
+    let out = rustc()
+        .env("RUSTC_BOOTSTRAP", "-1")
+        .input("missing-bound.rs")
+        .run_fail()
+        .assert_stderr_not_contains("help: consider restricting type parameter `T`")
+        .assert_stderr_contains(
+            r#"
+  = note: required for `std::ops::Range<T>` to implement `Iterator`
+  = note: required for `std::ops::Range<T>` to implement `IntoIterator`"#,
+        )
+        .stderr_utf8();
+    diff().expected_file("missing-bound.stderr").actual_text("(stable rustc)", &out).run()
+}
diff --git a/tests/rustdoc-ui/issues/issue-96287.stderr b/tests/rustdoc-ui/issues/issue-96287.stderr
index 9aba0332164..40dc1cc0e70 100644
--- a/tests/rustdoc-ui/issues/issue-96287.stderr
+++ b/tests/rustdoc-ui/issues/issue-96287.stderr
@@ -4,7 +4,7 @@ error[E0220]: associated type `Assoc` not found for `V`
 LL | pub type Foo<V> = impl Trait<V::Assoc>;
    |                                 ^^^^^ there is an associated type `Assoc` in the trait `TraitWithAssoc`
    |
-help: consider restricting type parameter `V`
+help: consider restricting type parameter `V` with trait `TraitWithAssoc`
    |
 LL | pub type Foo<V: TraitWithAssoc> = impl Trait<V::Assoc>;
    |               ++++++++++++++++
@@ -16,7 +16,7 @@ LL | pub type Foo<V> = impl Trait<V::Assoc>;
    |                                 ^^^^^ there is an associated type `Assoc` in the trait `TraitWithAssoc`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: consider restricting type parameter `V`
+help: consider restricting type parameter `V` with trait `TraitWithAssoc`
    |
 LL | pub type Foo<V: TraitWithAssoc> = impl Trait<V::Assoc>;
    |               ++++++++++++++++
diff --git a/tests/rustdoc-ui/synthetic-auto-trait-impls/projections-in-super-trait-bound-unsatisfied.stderr b/tests/rustdoc-ui/synthetic-auto-trait-impls/projections-in-super-trait-bound-unsatisfied.stderr
index d87e769b505..045516d7d2f 100644
--- a/tests/rustdoc-ui/synthetic-auto-trait-impls/projections-in-super-trait-bound-unsatisfied.stderr
+++ b/tests/rustdoc-ui/synthetic-auto-trait-impls/projections-in-super-trait-bound-unsatisfied.stderr
@@ -4,7 +4,7 @@ error[E0277]: the trait bound `C: Bar<5>` is not satisfied
 LL | pub struct Structure<C: Tec> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar<5>` is not implemented for `C`
    |
-help: consider further restricting this bound
+help: consider further restricting type parameter `C` with trait `Bar`
    |
 LL | pub struct Structure<C: Tec + Bar<5>> {
    |                             ++++++++
@@ -15,7 +15,7 @@ error[E0277]: the trait bound `C: Bar<5>` is not satisfied
 LL |     _field: C::BarType,
    |             ^^^^^^^^^^ the trait `Bar<5>` is not implemented for `C`
    |
-help: consider further restricting this bound
+help: consider further restricting type parameter `C` with trait `Bar`
    |
 LL | pub struct Structure<C: Tec + Bar<5>> {
    |                             ++++++++
diff --git a/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs b/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs
index f273bbc99a8..656cfca1ed1 100644
--- a/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs
+++ b/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs
@@ -15,16 +15,16 @@ extern crate rustc_span;
 extern crate rustc_symbol_mangling;
 extern crate rustc_target;
 
+use std::any::Any;
+
 use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_codegen_ssa::{CodegenResults, CrateInfo};
 use rustc_data_structures::fx::FxIndexMap;
-use rustc_errors::ErrorGuaranteed;
 use rustc_metadata::EncodedMetadata;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_middle::ty::TyCtxt;
-use rustc_session::config::OutputFilenames;
 use rustc_session::Session;
-use std::any::Any;
+use rustc_session::config::OutputFilenames;
 
 struct TheBackend;
 
@@ -60,17 +60,12 @@ impl CodegenBackend for TheBackend {
         (*codegen_results, FxIndexMap::default())
     }
 
-    fn link(
-        &self,
-        sess: &Session,
-        codegen_results: CodegenResults,
-        outputs: &OutputFilenames,
-    ) -> Result<(), ErrorGuaranteed> {
-        use rustc_session::{
-            config::{CrateType, OutFileName},
-            output::out_filename,
-        };
+    fn link(&self, sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames) {
         use std::io::Write;
+
+        use rustc_session::config::{CrateType, OutFileName};
+        use rustc_session::output::out_filename;
+
         let crate_name = codegen_results.crate_info.local_crate_name;
         for &crate_type in sess.opts.crate_types.iter() {
             if crate_type != CrateType::Rlib {
@@ -88,7 +83,6 @@ impl CodegenBackend for TheBackend {
                 }
             }
         }
-        Ok(())
     }
 }
 
diff --git a/tests/ui-fulldeps/compiler-calls.rs b/tests/ui-fulldeps/compiler-calls.rs
index f6c10add290..5fb47c87e50 100644
--- a/tests/ui-fulldeps/compiler-calls.rs
+++ b/tests/ui-fulldeps/compiler-calls.rs
@@ -12,7 +12,7 @@ extern crate rustc_interface;
 use rustc_interface::interface;
 
 struct TestCalls<'a> {
-    count: &'a mut u32
+    count: &'a mut u32,
 }
 
 impl rustc_driver::Callbacks for TestCalls<'_> {
@@ -24,8 +24,9 @@ impl rustc_driver::Callbacks for TestCalls<'_> {
 fn main() {
     let mut count = 1;
     let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()];
-    rustc_driver::catch_fatal_errors(|| {
-        rustc_driver::RunCompiler::new(&args, &mut TestCalls { count: &mut count }).run().ok();
+    rustc_driver::catch_fatal_errors(|| -> interface::Result<()> {
+        rustc_driver::RunCompiler::new(&args, &mut TestCalls { count: &mut count }).run();
+        Ok(())
     })
     .ok();
     assert_eq!(count, 2);
diff --git a/tests/ui-fulldeps/obtain-borrowck.rs b/tests/ui-fulldeps/obtain-borrowck.rs
index af98f93297b..8ea2ac61971 100644
--- a/tests/ui-fulldeps/obtain-borrowck.rs
+++ b/tests/ui-fulldeps/obtain-borrowck.rs
@@ -47,7 +47,8 @@ fn main() {
         rustc_args.push("-Zpolonius".to_owned());
         let mut callbacks = CompilerCalls::default();
         // Call the Rust compiler with our callbacks.
-        rustc_driver::RunCompiler::new(&rustc_args, &mut callbacks).run()
+        rustc_driver::RunCompiler::new(&rustc_args, &mut callbacks).run();
+        Ok(())
     });
     std::process::exit(exit_code);
 }
diff --git a/tests/ui-fulldeps/run-compiler-twice.rs b/tests/ui-fulldeps/run-compiler-twice.rs
index cce4eac0d7c..d4c9fd019b0 100644
--- a/tests/ui-fulldeps/run-compiler-twice.rs
+++ b/tests/ui-fulldeps/run-compiler-twice.rs
@@ -17,8 +17,7 @@ extern crate rustc_span;
 
 use std::path::{Path, PathBuf};
 
-use rustc_interface::Linker;
-use rustc_interface::interface;
+use rustc_interface::{Linker, interface};
 use rustc_session::config::{Input, Options, OutFileName, OutputType, OutputTypes};
 use rustc_span::FileName;
 
@@ -79,11 +78,11 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf, linker: Option<&Path
 
     interface::run_compiler(config, |compiler| {
         let linker = compiler.enter(|queries| {
-            queries.global_ctxt()?.enter(|tcx| {
-                tcx.analysis(())?;
+            queries.global_ctxt().enter(|tcx| {
+                let _ = tcx.analysis(());
                 Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend)
             })
         });
-        linker.unwrap().link(&compiler.sess, &*compiler.codegen_backend).unwrap();
+        linker.link(&compiler.sess, &*compiler.codegen_backend);
     });
 }
diff --git a/tests/ui/assign-imm-local-twice.rs b/tests/ui/assign-imm-local-twice.rs
deleted file mode 100644
index b2dfeb564d9..00000000000
--- a/tests/ui/assign-imm-local-twice.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-fn test() {
-    let v: isize;
-    //~^ HELP consider making this binding mutable
-    //~| SUGGESTION mut
-    v = 1; //~ NOTE first assignment
-    println!("v={}", v);
-    v = 2; //~ ERROR cannot assign twice to immutable variable
-           //~| NOTE cannot assign twice to immutable
-    println!("v={}", v);
-}
-
-fn main() {
-}
diff --git a/tests/ui/assoc-lang-items.rs b/tests/ui/assoc-lang-items.rs
deleted file mode 100644
index 23453d201a7..00000000000
--- a/tests/ui/assoc-lang-items.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-#![feature(lang_items)]
-
-trait Foo {
-    #[lang = "dummy_lang_item_1"] //~ ERROR definition
-    fn foo() {}
-
-    #[lang = "dummy_lang_item_2"] //~ ERROR definition
-    fn bar();
-
-    #[lang = "dummy_lang_item_3"] //~ ERROR definition
-    type MyType;
-}
-
-struct Bar;
-
-impl Bar {
-    #[lang = "dummy_lang_item_4"] //~ ERROR definition
-    fn test() {}
-}
-
-fn main() {}
diff --git a/tests/ui/assoc-oddities-3.rs b/tests/ui/assoc-oddities-3.rs
deleted file mode 100644
index ffde2ccf786..00000000000
--- a/tests/ui/assoc-oddities-3.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-//@ run-pass
-
-fn that_odd_parse(c: bool, n: usize) -> u32 {
-    let x = 2;
-    let a = [1, 2, 3, 4];
-    let b = [5, 6, 7, 7];
-    x + if c { a } else { b }[n]
-}
-
-fn main() {
-    assert_eq!(4, that_odd_parse(true, 1));
-    assert_eq!(8, that_odd_parse(false, 1));
-}
diff --git a/tests/ui/associated-types/associated-types-no-suitable-bound.stderr b/tests/ui/associated-types/associated-types-no-suitable-bound.stderr
index 9713051d973..4f951ee4b4e 100644
--- a/tests/ui/associated-types/associated-types-no-suitable-bound.stderr
+++ b/tests/ui/associated-types/associated-types-no-suitable-bound.stderr
@@ -4,7 +4,7 @@ error[E0277]: the trait bound `T: Get` is not satisfied
 LL |     fn uhoh<T>(foo: <T as Get>::Value) {}
    |                     ^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `T`
    |
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Get`
    |
 LL |     fn uhoh<T: Get>(foo: <T as Get>::Value) {}
    |              +++++
@@ -15,7 +15,7 @@ error[E0277]: the trait bound `T: Get` is not satisfied
 LL |     fn uhoh<T>(foo: <T as Get>::Value) {}
    |                                        ^^ the trait `Get` is not implemented for `T`
    |
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Get`
    |
 LL |     fn uhoh<T: Get>(foo: <T as Get>::Value) {}
    |              +++++
diff --git a/tests/ui/associated-types/defaults-suitability.current.stderr b/tests/ui/associated-types/defaults-suitability.current.stderr
index 9c0ae59ae43..61247cee1f3 100644
--- a/tests/ui/associated-types/defaults-suitability.current.stderr
+++ b/tests/ui/associated-types/defaults-suitability.current.stderr
@@ -47,7 +47,7 @@ note: required by a bound in `Foo::Bar`
    |
 LL |     type Bar: Clone = Vec<T>;
    |               ^^^^^ required by this bound in `Foo::Bar`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Clone`
    |
 LL | trait Foo<T: std::clone::Clone> {
    |            +++++++++++++++++++
@@ -132,7 +132,7 @@ LL |     Self::Baz: Clone,
 ...
 LL |     type Baz = T;
    |          --- required by a bound in this associated type
-help: consider further restricting type parameter `T`
+help: consider further restricting type parameter `T` with trait `Clone`
    |
 LL |     Self::Baz: Clone, T: std::clone::Clone
    |                     ~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tests/ui/associated-types/defaults-suitability.next.stderr b/tests/ui/associated-types/defaults-suitability.next.stderr
index 9c0ae59ae43..61247cee1f3 100644
--- a/tests/ui/associated-types/defaults-suitability.next.stderr
+++ b/tests/ui/associated-types/defaults-suitability.next.stderr
@@ -47,7 +47,7 @@ note: required by a bound in `Foo::Bar`
    |
 LL |     type Bar: Clone = Vec<T>;
    |               ^^^^^ required by this bound in `Foo::Bar`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Clone`
    |
 LL | trait Foo<T: std::clone::Clone> {
    |            +++++++++++++++++++
@@ -132,7 +132,7 @@ LL |     Self::Baz: Clone,
 ...
 LL |     type Baz = T;
    |          --- required by a bound in this associated type
-help: consider further restricting type parameter `T`
+help: consider further restricting type parameter `T` with trait `Clone`
    |
 LL |     Self::Baz: Clone, T: std::clone::Clone
    |                     ~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tests/ui/associated-types/hr-associated-type-bound-param-6.stderr b/tests/ui/associated-types/hr-associated-type-bound-param-6.stderr
index 5278bdb7a5c..b2a86bb7f75 100644
--- a/tests/ui/associated-types/hr-associated-type-bound-param-6.stderr
+++ b/tests/ui/associated-types/hr-associated-type-bound-param-6.stderr
@@ -4,7 +4,7 @@ error[E0277]: the trait bound `for<'b> T: X<'b, T>` is not satisfied
 LL | impl<S, T> X<'_, T> for (S,) {
    |            ^^^^^^^^ the trait `for<'b> X<'b, T>` is not implemented for `T`
    |
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `X`
    |
 LL | impl<S, T: for<'b> X<'b, T>> X<'_, T> for (S,) {
    |          ++++++++++++++++++
diff --git a/tests/ui/associated-types/issue-27675-unchecked-bounds.stderr b/tests/ui/associated-types/issue-27675-unchecked-bounds.stderr
index 70bf90150b8..0815bdce16f 100644
--- a/tests/ui/associated-types/issue-27675-unchecked-bounds.stderr
+++ b/tests/ui/associated-types/issue-27675-unchecked-bounds.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `copy`
    |
 LL | fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From {
    |            ^^^^^ required by this bound in `copy`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | pub fn copy_any<T: std::marker::Copy>(t: &T) -> T {
    |                  +++++++++++++++++++
diff --git a/tests/ui/associated-types/issue-43784-associated-type.stderr b/tests/ui/associated-types/issue-43784-associated-type.stderr
index 529fc1f119a..ba4e683194f 100644
--- a/tests/ui/associated-types/issue-43784-associated-type.stderr
+++ b/tests/ui/associated-types/issue-43784-associated-type.stderr
@@ -14,7 +14,7 @@ note: required by a bound in `Complete::Assoc`
    |
 LL |     type Assoc: Partial<Self>;
    |                 ^^^^^^^^^^^^^ required by this bound in `Complete::Assoc`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | impl<T: std::marker::Copy> Complete for T {
    |       +++++++++++++++++++
diff --git a/tests/ui/associated-types/issue-59324.stderr b/tests/ui/associated-types/issue-59324.stderr
index 6c77ee6044f..ec2890cc8e7 100644
--- a/tests/ui/associated-types/issue-59324.stderr
+++ b/tests/ui/associated-types/issue-59324.stderr
@@ -7,7 +7,7 @@ LL | |
 LL | |     Service<AssocType = <Bug as Foo>::OnlyFoo>
    | |______________________________________________^ the trait `Foo` is not implemented for `Bug`
    |
-help: consider further restricting this bound
+help: consider further restricting type parameter `Bug` with trait `Foo`
    |
 LL | pub trait ThriftService<Bug: NotFoo + Foo>:
    |                                     +++++
@@ -24,7 +24,7 @@ LL | |
 LL | | }
    | |_^ the trait `Foo` is not implemented for `Bug`
    |
-help: consider further restricting this bound
+help: consider further restricting type parameter `Bug` with trait `Foo`
    |
 LL | pub trait ThriftService<Bug: NotFoo + Foo>:
    |                                     +++++
@@ -38,7 +38,7 @@ LL | |         &self,
 LL | |     ) -> Self::AssocType;
    | |_________________________^ the trait `Foo` is not implemented for `Bug`
    |
-help: consider further restricting this bound
+help: consider further restricting type parameter `Bug` with trait `Foo`
    |
 LL | pub trait ThriftService<Bug: NotFoo + Foo>:
    |                                     +++++
@@ -61,7 +61,7 @@ error[E0277]: the trait bound `Bug: Foo` is not satisfied
 LL |     ) -> Self::AssocType;
    |          ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug`
    |
-help: consider further restricting this bound
+help: consider further restricting type parameter `Bug` with trait `Foo`
    |
 LL | pub trait ThriftService<Bug: NotFoo + Foo>:
    |                                     +++++
diff --git a/tests/ui/async-await/issue-70818.stderr b/tests/ui/async-await/issue-70818.stderr
index 317c04d2c74..8de6a825042 100644
--- a/tests/ui/async-await/issue-70818.stderr
+++ b/tests/ui/async-await/issue-70818.stderr
@@ -9,7 +9,7 @@ note: captured value is not `Send`
    |
 LL |     async { (ty, ty1) }
    |                  ^^^ has type `U` which is not `Send`
-help: consider restricting type parameter `U`
+help: consider restricting type parameter `U` with trait `Send`
    |
 LL | fn foo<T: Send, U: std::marker::Send>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send {
    |                  +++++++++++++++++++
diff --git a/tests/ui/async-await/issue-86507.stderr b/tests/ui/async-await/issue-86507.stderr
index f4cd7c42706..6385a8c975e 100644
--- a/tests/ui/async-await/issue-86507.stderr
+++ b/tests/ui/async-await/issue-86507.stderr
@@ -14,7 +14,7 @@ note: captured value is not `Send` because `&` references cannot be sent unless
 LL |                     let x = x;
    |                             ^ has type `&T` which is not `Send`, because `T` is not `Sync`
    = note: required for the cast from `Pin<Box<{async block@$DIR/issue-86507.rs:18:17: 18:27}>>` to `Pin<Box<(dyn Future<Output = ()> + Send + 'async_trait)>>`
-help: consider further restricting this bound
+help: consider further restricting type parameter `T` with trait `Sync`
    |
 LL |     fn bar<'me, 'async_trait, T: Send + std::marker::Sync>(x: &'me T)
    |                                       +++++++++++++++++++
diff --git a/tests/ui/atomic-from-mut-not-available.rs b/tests/ui/atomic-from-mut-not-available.rs
deleted file mode 100644
index 8326187838a..00000000000
--- a/tests/ui/atomic-from-mut-not-available.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-//@ only-x86
-//@ only-linux
-
-fn main() {
-    core::sync::atomic::AtomicU64::from_mut(&mut 0u64);
-    //~^ ERROR: no function or associated item named `from_mut` found for struct `AtomicU64`
-}
diff --git a/tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr b/tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr
index 4c1de72798c..27e38ce06a4 100644
--- a/tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr
+++ b/tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr
@@ -30,7 +30,7 @@ LL | fn copy<T: Magic>(x: T) -> (T, T) { (x, x) }
    |         ^                            - you could clone this value
    |         |
    |         consider constraining this type parameter with `Clone`
-help: consider further restricting this bound
+help: consider further restricting type parameter `T` with trait `Copy`
    |
 LL | fn copy<T: Magic + Copy>(x: T) -> (T, T) { (x, x) }
    |                  ++++++
diff --git a/tests/ui/binop/binop-consume-args.stderr b/tests/ui/binop/binop-consume-args.stderr
index 1b59216b3c7..d9d92a44766 100644
--- a/tests/ui/binop/binop-consume-args.stderr
+++ b/tests/ui/binop/binop-consume-args.stderr
@@ -17,7 +17,7 @@ LL |     lhs + rhs;
    |     --- you could clone this value
 note: calling this operator moves the left-hand side
   --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
-help: consider further restricting this bound
+help: consider further restricting type parameter `A` with trait `Copy`
    |
 LL | fn add<A: Add<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
    |                             ++++++
@@ -40,7 +40,7 @@ LL | fn add<A: Add<B, Output=()>, B>(lhs: A, rhs: B) {
    |                              ^ consider constraining this type parameter with `Clone`
 LL |     lhs + rhs;
    |           --- you could clone this value
-help: consider restricting type parameter `B`
+help: consider restricting type parameter `B` with trait `Copy`
    |
 LL | fn add<A: Add<B, Output=()>, B: Copy>(lhs: A, rhs: B) {
    |                               ++++++
@@ -64,7 +64,7 @@ LL |     lhs - rhs;
    |     --- you could clone this value
 note: calling this operator moves the left-hand side
   --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
-help: consider further restricting this bound
+help: consider further restricting type parameter `A` with trait `Copy`
    |
 LL | fn sub<A: Sub<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
    |                             ++++++
@@ -87,7 +87,7 @@ LL | fn sub<A: Sub<B, Output=()>, B>(lhs: A, rhs: B) {
    |                              ^ consider constraining this type parameter with `Clone`
 LL |     lhs - rhs;
    |           --- you could clone this value
-help: consider restricting type parameter `B`
+help: consider restricting type parameter `B` with trait `Copy`
    |
 LL | fn sub<A: Sub<B, Output=()>, B: Copy>(lhs: A, rhs: B) {
    |                               ++++++
@@ -111,7 +111,7 @@ LL |     lhs * rhs;
    |     --- you could clone this value
 note: calling this operator moves the left-hand side
   --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
-help: consider further restricting this bound
+help: consider further restricting type parameter `A` with trait `Copy`
    |
 LL | fn mul<A: Mul<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
    |                             ++++++
@@ -134,7 +134,7 @@ LL | fn mul<A: Mul<B, Output=()>, B>(lhs: A, rhs: B) {
    |                              ^ consider constraining this type parameter with `Clone`
 LL |     lhs * rhs;
    |           --- you could clone this value
-help: consider restricting type parameter `B`
+help: consider restricting type parameter `B` with trait `Copy`
    |
 LL | fn mul<A: Mul<B, Output=()>, B: Copy>(lhs: A, rhs: B) {
    |                               ++++++
@@ -158,7 +158,7 @@ LL |     lhs / rhs;
    |     --- you could clone this value
 note: calling this operator moves the left-hand side
   --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
-help: consider further restricting this bound
+help: consider further restricting type parameter `A` with trait `Copy`
    |
 LL | fn div<A: Div<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
    |                             ++++++
@@ -181,7 +181,7 @@ LL | fn div<A: Div<B, Output=()>, B>(lhs: A, rhs: B) {
    |                              ^ consider constraining this type parameter with `Clone`
 LL |     lhs / rhs;
    |           --- you could clone this value
-help: consider restricting type parameter `B`
+help: consider restricting type parameter `B` with trait `Copy`
    |
 LL | fn div<A: Div<B, Output=()>, B: Copy>(lhs: A, rhs: B) {
    |                               ++++++
@@ -205,7 +205,7 @@ LL |     lhs % rhs;
    |     --- you could clone this value
 note: calling this operator moves the left-hand side
   --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
-help: consider further restricting this bound
+help: consider further restricting type parameter `A` with trait `Copy`
    |
 LL | fn rem<A: Rem<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
    |                             ++++++
@@ -228,7 +228,7 @@ LL | fn rem<A: Rem<B, Output=()>, B>(lhs: A, rhs: B) {
    |                              ^ consider constraining this type parameter with `Clone`
 LL |     lhs % rhs;
    |           --- you could clone this value
-help: consider restricting type parameter `B`
+help: consider restricting type parameter `B` with trait `Copy`
    |
 LL | fn rem<A: Rem<B, Output=()>, B: Copy>(lhs: A, rhs: B) {
    |                               ++++++
@@ -252,7 +252,7 @@ LL |     lhs & rhs;
    |     --- you could clone this value
 note: calling this operator moves the left-hand side
   --> $SRC_DIR/core/src/ops/bit.rs:LL:COL
-help: consider further restricting this bound
+help: consider further restricting type parameter `A` with trait `Copy`
    |
 LL | fn bitand<A: BitAnd<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
    |                                   ++++++
@@ -275,7 +275,7 @@ LL | fn bitand<A: BitAnd<B, Output=()>, B>(lhs: A, rhs: B) {
    |                                    ^ consider constraining this type parameter with `Clone`
 LL |     lhs & rhs;
    |           --- you could clone this value
-help: consider restricting type parameter `B`
+help: consider restricting type parameter `B` with trait `Copy`
    |
 LL | fn bitand<A: BitAnd<B, Output=()>, B: Copy>(lhs: A, rhs: B) {
    |                                     ++++++
@@ -299,7 +299,7 @@ LL |     lhs | rhs;
    |     --- you could clone this value
 note: calling this operator moves the left-hand side
   --> $SRC_DIR/core/src/ops/bit.rs:LL:COL
-help: consider further restricting this bound
+help: consider further restricting type parameter `A` with trait `Copy`
    |
 LL | fn bitor<A: BitOr<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
    |                                 ++++++
@@ -322,7 +322,7 @@ LL | fn bitor<A: BitOr<B, Output=()>, B>(lhs: A, rhs: B) {
    |                                  ^ consider constraining this type parameter with `Clone`
 LL |     lhs | rhs;
    |           --- you could clone this value
-help: consider restricting type parameter `B`
+help: consider restricting type parameter `B` with trait `Copy`
    |
 LL | fn bitor<A: BitOr<B, Output=()>, B: Copy>(lhs: A, rhs: B) {
    |                                   ++++++
@@ -346,7 +346,7 @@ LL |     lhs ^ rhs;
    |     --- you could clone this value
 note: calling this operator moves the left-hand side
   --> $SRC_DIR/core/src/ops/bit.rs:LL:COL
-help: consider further restricting this bound
+help: consider further restricting type parameter `A` with trait `Copy`
    |
 LL | fn bitxor<A: BitXor<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
    |                                   ++++++
@@ -369,7 +369,7 @@ LL | fn bitxor<A: BitXor<B, Output=()>, B>(lhs: A, rhs: B) {
    |                                    ^ consider constraining this type parameter with `Clone`
 LL |     lhs ^ rhs;
    |           --- you could clone this value
-help: consider restricting type parameter `B`
+help: consider restricting type parameter `B` with trait `Copy`
    |
 LL | fn bitxor<A: BitXor<B, Output=()>, B: Copy>(lhs: A, rhs: B) {
    |                                     ++++++
@@ -393,7 +393,7 @@ LL |     lhs << rhs;
    |     --- you could clone this value
 note: calling this operator moves the left-hand side
   --> $SRC_DIR/core/src/ops/bit.rs:LL:COL
-help: consider further restricting this bound
+help: consider further restricting type parameter `A` with trait `Copy`
    |
 LL | fn shl<A: Shl<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
    |                             ++++++
@@ -416,7 +416,7 @@ LL | fn shl<A: Shl<B, Output=()>, B>(lhs: A, rhs: B) {
    |                              ^ consider constraining this type parameter with `Clone`
 LL |     lhs << rhs;
    |            --- you could clone this value
-help: consider restricting type parameter `B`
+help: consider restricting type parameter `B` with trait `Copy`
    |
 LL | fn shl<A: Shl<B, Output=()>, B: Copy>(lhs: A, rhs: B) {
    |                               ++++++
@@ -440,7 +440,7 @@ LL |     lhs >> rhs;
    |     --- you could clone this value
 note: calling this operator moves the left-hand side
   --> $SRC_DIR/core/src/ops/bit.rs:LL:COL
-help: consider further restricting this bound
+help: consider further restricting type parameter `A` with trait `Copy`
    |
 LL | fn shr<A: Shr<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
    |                             ++++++
@@ -463,7 +463,7 @@ LL | fn shr<A: Shr<B, Output=()>, B>(lhs: A, rhs: B) {
    |                              ^ consider constraining this type parameter with `Clone`
 LL |     lhs >> rhs;
    |            --- you could clone this value
-help: consider restricting type parameter `B`
+help: consider restricting type parameter `B` with trait `Copy`
    |
 LL | fn shr<A: Shr<B, Output=()>, B: Copy>(lhs: A, rhs: B) {
    |                               ++++++
diff --git a/tests/ui/binop/binop-move-semantics.stderr b/tests/ui/binop/binop-move-semantics.stderr
index 45c7f110406..2e661c44abd 100644
--- a/tests/ui/binop/binop-move-semantics.stderr
+++ b/tests/ui/binop/binop-move-semantics.stderr
@@ -20,7 +20,7 @@ LL |     x
    |     - you could clone this value
 note: calling this operator moves the left-hand side
   --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
-help: consider further restricting this bound
+help: consider further restricting type parameter `T` with trait `Copy`
    |
 LL | fn double_move<T: Add<Output=()> + Copy>(x: T) {
    |                                  ++++++
@@ -40,7 +40,7 @@ help: consider cloning the value if the performance cost is acceptable
    |
 LL |     x.clone()
    |      ++++++++
-help: consider further restricting this bound
+help: consider further restricting type parameter `T` with trait `Copy`
    |
 LL | fn move_then_borrow<T: Add<Output=()> + Clone + Copy>(x: T) {
    |                                               ++++++
diff --git a/tests/ui/binop/issue-93927.stderr b/tests/ui/binop/issue-93927.stderr
index 9bcf2b17357..ff5ecf66be6 100644
--- a/tests/ui/binop/issue-93927.stderr
+++ b/tests/ui/binop/issue-93927.stderr
@@ -6,7 +6,7 @@ LL |     val == val
    |     |
    |     MyType<T>
    |
-help: consider further restricting this bound
+help: consider further restricting type parameter `T` with trait `Eq`
    |
 LL | fn cond<T: PartialEq + std::cmp::Eq>(val: MyType<T>) -> bool {
    |                      ++++++++++++++
diff --git a/tests/ui/borrowck/assign-imm-local-twice.fixed b/tests/ui/borrowck/assign-imm-local-twice.fixed
new file mode 100644
index 00000000000..dca994141bb
--- /dev/null
+++ b/tests/ui/borrowck/assign-imm-local-twice.fixed
@@ -0,0 +1,21 @@
+//! Check that we do not allow assigning twice to an immutable variable. This test also checks a
+//! few pieces of borrowck diagnostics:
+//!
+//! - A multipart borrowck diagnostics that points out the first assignment to an immutable
+//!   variable, alongside violating assignments that follow subsequently.
+//! - A suggestion diagnostics to make the immutable binding mutable.
+
+//@ run-rustfix
+
+fn main() {
+    let mut v: isize;
+    //~^ HELP consider making this binding mutable
+    //~| SUGGESTION mut
+    v = 1;
+    //~^ NOTE first assignment
+    println!("v={}", v);
+    v = 2;
+    //~^ ERROR cannot assign twice to immutable variable
+    //~| NOTE cannot assign twice to immutable
+    println!("v={}", v);
+}
diff --git a/tests/ui/borrowck/assign-imm-local-twice.rs b/tests/ui/borrowck/assign-imm-local-twice.rs
new file mode 100644
index 00000000000..43437fa69fa
--- /dev/null
+++ b/tests/ui/borrowck/assign-imm-local-twice.rs
@@ -0,0 +1,21 @@
+//! Check that we do not allow assigning twice to an immutable variable. This test also checks a
+//! few pieces of borrowck diagnostics:
+//!
+//! - A multipart borrowck diagnostics that points out the first assignment to an immutable
+//!   variable, alongside violating assignments that follow subsequently.
+//! - A suggestion diagnostics to make the immutable binding mutable.
+
+//@ run-rustfix
+
+fn main() {
+    let v: isize;
+    //~^ HELP consider making this binding mutable
+    //~| SUGGESTION mut
+    v = 1;
+    //~^ NOTE first assignment
+    println!("v={}", v);
+    v = 2;
+    //~^ ERROR cannot assign twice to immutable variable
+    //~| NOTE cannot assign twice to immutable
+    println!("v={}", v);
+}
diff --git a/tests/ui/assign-imm-local-twice.stderr b/tests/ui/borrowck/assign-imm-local-twice.stderr
index fda3aa3de1b..0a2138d0b96 100644
--- a/tests/ui/assign-imm-local-twice.stderr
+++ b/tests/ui/borrowck/assign-imm-local-twice.stderr
@@ -1,9 +1,9 @@
 error[E0384]: cannot assign twice to immutable variable `v`
-  --> $DIR/assign-imm-local-twice.rs:7:5
+  --> $DIR/assign-imm-local-twice.rs:17:5
    |
 LL |     v = 1;
    |     ----- first assignment to `v`
-LL |     println!("v={}", v);
+...
 LL |     v = 2;
    |     ^^^^^ cannot assign twice to immutable variable
    |
diff --git a/tests/ui/borrowck/clone-on-ref.stderr b/tests/ui/borrowck/clone-on-ref.stderr
index d5d21296a3f..911c136086c 100644
--- a/tests/ui/borrowck/clone-on-ref.stderr
+++ b/tests/ui/borrowck/clone-on-ref.stderr
@@ -12,7 +12,7 @@ LL |
 LL |     drop(cloned_items);
    |          ------------ immutable borrow later used here
    |
-help: consider further restricting this bound
+help: consider further restricting type parameter `T` with trait `Clone`
    |
 LL | fn foo<T: Default + Clone>(list: &mut Vec<T>) {
    |                   +++++++
@@ -39,7 +39,7 @@ LL | fn bar<T: std::fmt::Display>(x: T) {
    |        ^ consider constraining this type parameter with `Clone`
 LL |     let a = &x;
    |              - you could clone this value
-help: consider further restricting this bound
+help: consider further restricting type parameter `T` with trait `Clone`
    |
 LL | fn bar<T: std::fmt::Display + Clone>(x: T) {
    |                             +++++++
diff --git a/tests/ui/borrowck/move-error-suggest-clone-panic-issue-127915.stderr b/tests/ui/borrowck/move-error-suggest-clone-panic-issue-127915.stderr
index 6997710ec89..e32a0c54dfe 100644
--- a/tests/ui/borrowck/move-error-suggest-clone-panic-issue-127915.stderr
+++ b/tests/ui/borrowck/move-error-suggest-clone-panic-issue-127915.stderr
@@ -15,7 +15,7 @@ LL | fn test<T, U>(a: i64, b: i64, c: i64, d: i64, e: i64, f: T, g: U) -> i64 {
 ...
 LL |             6, a as f64, b, b as f64, f, c as f64, d, d as f64, e, e as f64, f, g,
    |                                       - you could clone this value
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | fn test<T: Copy, U>(a: i64, b: i64, c: i64, d: i64, e: i64, f: T, g: U) -> i64 {
    |          ++++++
diff --git a/tests/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr b/tests/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr
index 592aa4369ce..9915b772afa 100644
--- a/tests/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr
+++ b/tests/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr
@@ -10,7 +10,7 @@ note: required by a bound in `Foo`
    |
 LL | trait Foo : Send+Sync { }
    |             ^^^^ required by this bound in `Foo`
-help: consider further restricting this bound
+help: consider further restricting type parameter `T` with trait `Send`
    |
 LL | impl <T: Sync+'static + std::marker::Send> Foo for (T,) { }
    |                       +++++++++++++++++++
@@ -27,7 +27,7 @@ note: required by a bound in `Foo`
    |
 LL | trait Foo : Send+Sync { }
    |                  ^^^^ required by this bound in `Foo`
-help: consider further restricting this bound
+help: consider further restricting type parameter `T` with trait `Sync`
    |
 LL | impl <T: Send + std::marker::Sync> Foo for (T,T) { }
    |               +++++++++++++++++++
diff --git a/tests/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr b/tests/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr
index 251651df4f9..39a04186981 100644
--- a/tests/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr
+++ b/tests/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr
@@ -14,7 +14,7 @@ note: required by a bound in `RequiresRequiresShareAndSend`
    |
 LL | pub trait RequiresRequiresShareAndSend : RequiresShare + Send { }
    |                                                          ^^^^ required by this bound in `RequiresRequiresShareAndSend`
-help: consider further restricting this bound
+help: consider further restricting type parameter `T` with trait `Send`
    |
 LL | impl <T:Sync+'static + std::marker::Send> RequiresRequiresShareAndSend for X<T> { }
    |                      +++++++++++++++++++
diff --git a/tests/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr b/tests/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr
index 4a25c42b583..dd273b875ae 100644
--- a/tests/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr
+++ b/tests/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `Foo`
    |
 LL | trait Foo : Send { }
    |             ^^^^ required by this bound in `Foo`
-help: consider further restricting this bound
+help: consider further restricting type parameter `T` with trait `Send`
    |
 LL | impl <T: Sync+'static + std::marker::Send> Foo for T { }
    |                       +++++++++++++++++++
diff --git a/tests/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr b/tests/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr
index 8157590bd9e..9ceee477856 100644
--- a/tests/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr
+++ b/tests/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `X`
    |
 LL | struct X<F> where F: FnOnce() + 'static + Send {
    |                                           ^^^^ required by this bound in `X`
-help: consider further restricting this bound
+help: consider further restricting type parameter `F` with trait `Send`
    |
 LL | fn foo<F>(blk: F) -> X<F> where F: FnOnce() + 'static + std::marker::Send {
    |                                                       +++++++++++++++++++
@@ -25,7 +25,7 @@ note: required by a bound in `X`
    |
 LL | struct X<F> where F: FnOnce() + 'static + Send {
    |                                           ^^^^ required by this bound in `X`
-help: consider further restricting this bound
+help: consider further restricting type parameter `F` with trait `Send`
    |
 LL | fn foo<F>(blk: F) -> X<F> where F: FnOnce() + 'static + std::marker::Send {
    |                                                       +++++++++++++++++++
diff --git a/tests/ui/closures/closure-bounds-subtype.stderr b/tests/ui/closures/closure-bounds-subtype.stderr
index 42588668e8a..34c5e0299a7 100644
--- a/tests/ui/closures/closure-bounds-subtype.stderr
+++ b/tests/ui/closures/closure-bounds-subtype.stderr
@@ -15,7 +15,7 @@ help: use parentheses to call this type parameter
    |
 LL |     take_const_owned(f());
    |                       ++
-help: consider further restricting this bound
+help: consider further restricting type parameter `F` with trait `Sync`
    |
 LL | fn give_owned<F>(f: F) where F: FnOnce() + Send + std::marker::Sync {
    |                                                 +++++++++++++++++++
diff --git a/tests/ui/closures/issue-67123.stderr b/tests/ui/closures/issue-67123.stderr
index bdafeaef15f..7db82845ea5 100644
--- a/tests/ui/closures/issue-67123.stderr
+++ b/tests/ui/closures/issue-67123.stderr
@@ -7,7 +7,7 @@ LL |     || { t; t; };
    |          value moved here
    |
    = note: move occurs because `t` has type `T`, which does not implement the `Copy` trait
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | fn foo<T: Copy>(t: T) {
    |         ++++++
diff --git a/tests/ui/assign-assign.rs b/tests/ui/codegen/assign-expr-unit-type.rs
index 002393f5bff..b4268b5e09a 100644
--- a/tests/ui/assign-assign.rs
+++ b/tests/ui/codegen/assign-expr-unit-type.rs
@@ -1,5 +1,11 @@
+//! Regression test for [Using the result of an assignment expression results in an LLVM assert
+//! #483][issue-483]. This test checks that assignment expressions produce a unit type, and is
+//! properly lowered to LLVM IR such that it does not trigger an LLVM assertion. This test was added
+//! *really* early, back in 2011.
+//!
+//! [issue-483]: https://github.com/rust-lang/rust/issues/483
+
 //@ run-pass
-// Issue 483 - Assignment expressions result in nil
 
 fn test_assign() {
     let mut x: isize;
@@ -27,4 +33,7 @@ fn test_assign_op() {
     assert_eq!(z, ());
 }
 
-pub fn main() { test_assign(); test_assign_op(); }
+pub fn main() {
+    test_assign();
+    test_assign_op();
+}
diff --git a/tests/ui/coherence/fuzzing/best-obligation-ICE.stderr b/tests/ui/coherence/fuzzing/best-obligation-ICE.stderr
index 88de8023f6d..01b6eaf422e 100644
--- a/tests/ui/coherence/fuzzing/best-obligation-ICE.stderr
+++ b/tests/ui/coherence/fuzzing/best-obligation-ICE.stderr
@@ -41,7 +41,7 @@ note: required by a bound in `W`
    |
 LL | struct W<T: Trait>(*mut T);
    |             ^^^^^ required by this bound in `W`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Trait`
    |
 LL | impl<T: Trait> Trait for W<W<W<T>>> {}
    |       +++++++
diff --git a/tests/ui/const-generics/issues/issue-61336-2.stderr b/tests/ui/const-generics/issues/issue-61336-2.stderr
index b0864689f74..92a704da8b4 100644
--- a/tests/ui/const-generics/issues/issue-61336-2.stderr
+++ b/tests/ui/const-generics/issues/issue-61336-2.stderr
@@ -7,7 +7,7 @@ LL |     [x; { N }]
    = note: the `Copy` trait is required because this value will be copied for each element of the array
    = help: consider using `core::array::from_fn` to initialize the array
    = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | fn g<T: std::marker::Copy, const N: usize>(x: T) -> [T; N] {
    |       +++++++++++++++++++
diff --git a/tests/ui/const-generics/issues/issue-61336.stderr b/tests/ui/const-generics/issues/issue-61336.stderr
index 111afbda343..43e8f5c044a 100644
--- a/tests/ui/const-generics/issues/issue-61336.stderr
+++ b/tests/ui/const-generics/issues/issue-61336.stderr
@@ -7,7 +7,7 @@ LL |     [x; N]
    = note: the `Copy` trait is required because this value will be copied for each element of the array
    = help: consider using `core::array::from_fn` to initialize the array
    = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | fn g<T: std::marker::Copy, const N: usize>(x: T) -> [T; N] {
    |       +++++++++++++++++++
diff --git a/tests/ui/consts/ct-var-in-collect_all_mismatches.stderr b/tests/ui/consts/ct-var-in-collect_all_mismatches.stderr
index 24572040b91..74ec052f6ec 100644
--- a/tests/ui/consts/ct-var-in-collect_all_mismatches.stderr
+++ b/tests/ui/consts/ct-var-in-collect_all_mismatches.stderr
@@ -12,7 +12,7 @@ LL |     fn unsatisfied(self)
 LL |     where
 LL |         T: Bar<N>,
    |            ^^^^^^ required by this bound in `Foo::<T, N>::unsatisfied`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Bar`
    |
 LL | impl<T: Bar<N>, const N: usize> Foo<T, N> {
    |       ++++++++
diff --git a/tests/ui/consts/fn_trait_refs.stderr b/tests/ui/consts/fn_trait_refs.stderr
index 11e13c3efdd..bb7ff76b125 100644
--- a/tests/ui/consts/fn_trait_refs.stderr
+++ b/tests/ui/consts/fn_trait_refs.stderr
@@ -212,10 +212,6 @@ LL |     f()
    |     ^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
-   |
-LL |     T: ~const Fn<()> + ~const Destruct + ~const Fn(),
-   |                                        +++++++++++++
 
 error[E0015]: cannot call non-const closure in constant functions
   --> $DIR/fn_trait_refs.rs:23:5
@@ -224,10 +220,6 @@ LL |     f()
    |     ^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
-   |
-LL |     T: ~const FnMut<()> + ~const Destruct + ~const FnMut(),
-   |                                           ++++++++++++++++
 
 error[E0015]: cannot call non-const closure in constant functions
   --> $DIR/fn_trait_refs.rs:30:5
@@ -236,10 +228,6 @@ LL |     f()
    |     ^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
-   |
-LL |     T: ~const FnOnce<()> + ~const FnOnce(),
-   |                          +++++++++++++++++
 
 error: aborting due to 25 previous errors
 
diff --git a/tests/ui/consts/unstable-const-fn-in-libcore.stderr b/tests/ui/consts/unstable-const-fn-in-libcore.stderr
index 2bdec1bf41b..f40c1871e90 100644
--- a/tests/ui/consts/unstable-const-fn-in-libcore.stderr
+++ b/tests/ui/consts/unstable-const-fn-in-libcore.stderr
@@ -19,10 +19,6 @@ LL |             Opt::None => f(),
    |                          ^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
-   |
-LL |     const fn unwrap_or_else<F: ~const FnOnce() -> T + ~const FnOnce()>(self, f: F) -> T {
-   |                                                     +++++++++++++++++
 
 error[E0493]: destructor of `F` cannot be evaluated at compile-time
   --> $DIR/unstable-const-fn-in-libcore.rs:19:60
diff --git a/tests/ui/dropck/explicit-drop-bounds.bad1.stderr b/tests/ui/dropck/explicit-drop-bounds.bad1.stderr
index 3ef11e2c0bb..2caa779ffab 100644
--- a/tests/ui/dropck/explicit-drop-bounds.bad1.stderr
+++ b/tests/ui/dropck/explicit-drop-bounds.bad1.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `DropMe`
    |
 LL | struct DropMe<T: Copy>(T);
    |                  ^^^^ required by this bound in `DropMe`
-help: consider further restricting type parameter `T`
+help: consider further restricting type parameter `T` with trait `Copy`
    |
 LL |     [T; 1]: Copy, T: std::marker::Copy // But `[T; 1]: Copy` does not imply `T: Copy`
    |                 ~~~~~~~~~~~~~~~~~~~~~~
@@ -25,7 +25,7 @@ note: required by a bound in `DropMe`
    |
 LL | struct DropMe<T: Copy>(T);
    |                  ^^^^ required by this bound in `DropMe`
-help: consider further restricting type parameter `T`
+help: consider further restricting type parameter `T` with trait `Copy`
    |
 LL |     [T; 1]: Copy, T: std::marker::Copy // But `[T; 1]: Copy` does not imply `T: Copy`
    |                 ~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tests/ui/dropck/explicit-drop-bounds.bad2.stderr b/tests/ui/dropck/explicit-drop-bounds.bad2.stderr
index 8138b86ddea..5851731e834 100644
--- a/tests/ui/dropck/explicit-drop-bounds.bad2.stderr
+++ b/tests/ui/dropck/explicit-drop-bounds.bad2.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `DropMe`
    |
 LL | struct DropMe<T: Copy>(T);
    |                  ^^^^ required by this bound in `DropMe`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | impl<T: std::marker::Copy> Drop for DropMe<T>
    |       +++++++++++++++++++
@@ -25,7 +25,7 @@ note: required by a bound in `DropMe`
    |
 LL | struct DropMe<T: Copy>(T);
    |                  ^^^^ required by this bound in `DropMe`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | impl<T: std::marker::Copy> Drop for DropMe<T>
    |       +++++++++++++++++++
diff --git a/tests/ui/error-codes/E0229.stderr b/tests/ui/error-codes/E0229.stderr
index 038f44e8b14..ab2536cc0c9 100644
--- a/tests/ui/error-codes/E0229.stderr
+++ b/tests/ui/error-codes/E0229.stderr
@@ -42,7 +42,7 @@ error[E0277]: the trait bound `I: Foo` is not satisfied
 LL | fn baz<I>(x: &<I as Foo<A = Bar>>::A) {}
    |               ^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `I`
    |
-help: consider restricting type parameter `I`
+help: consider restricting type parameter `I` with trait `Foo`
    |
 LL | fn baz<I: Foo>(x: &<I as Foo<A = Bar>>::A) {}
    |         +++++
@@ -53,7 +53,7 @@ error[E0277]: the trait bound `I: Foo` is not satisfied
 LL | fn baz<I>(x: &<I as Foo<A = Bar>>::A) {}
    |                                       ^^ the trait `Foo` is not implemented for `I`
    |
-help: consider restricting type parameter `I`
+help: consider restricting type parameter `I` with trait `Foo`
    |
 LL | fn baz<I: Foo>(x: &<I as Foo<A = Bar>>::A) {}
    |         +++++
diff --git a/tests/ui/errors/trait-bound-error-spans/blame-trait-error.stderr b/tests/ui/errors/trait-bound-error-spans/blame-trait-error.stderr
index 9228a047e87..b221195a7bd 100644
--- a/tests/ui/errors/trait-bound-error-spans/blame-trait-error.stderr
+++ b/tests/ui/errors/trait-bound-error-spans/blame-trait-error.stderr
@@ -25,7 +25,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `T3`
    |
 LL | fn example<Q: T3>(q: Q) {
    |             ++++
@@ -73,7 +73,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `Iterator`
    |
 LL | fn example<Q: std::iter::Iterator>(q: Q) {
    |             +++++++++++++++++++++
@@ -100,7 +100,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `Iterator`
    |
 LL | fn example<Q: std::iter::Iterator>(q: Q) {
    |             +++++++++++++++++++++
@@ -125,7 +125,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `T3`
    |
 LL | fn example<Q: T3>(q: Q) {
    |             ++++
@@ -150,7 +150,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `T3`
    |
 LL | fn example<Q: T3>(q: Q) {
    |             ++++
@@ -175,7 +175,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `T3`
    |
 LL | fn example<Q: T3>(q: Q) {
    |             ++++
@@ -200,7 +200,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `T3`
    |
 LL | fn example<Q: T3>(q: Q) {
    |             ++++
@@ -225,7 +225,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `T3`
    |
 LL | fn example<Q: T3>(q: Q) {
    |             ++++
@@ -248,7 +248,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `T3`
    |
 LL | fn example<Q: T3>(q: Q) {
    |             ++++
@@ -273,7 +273,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `T3`
    |
 LL | fn example<Q: T3>(q: Q) {
    |             ++++
@@ -296,7 +296,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `T3`
    |
 LL | fn example<Q: T3>(q: Q) {
    |             ++++
@@ -319,7 +319,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `T3`
    |
 LL | fn example<Q: T3>(q: Q) {
    |             ++++
@@ -342,7 +342,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `T3`
    |
 LL | fn example<Q: T3>(q: Q) {
    |             ++++
@@ -367,7 +367,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `T3`
    |
 LL | fn example<Q: T3>(q: Q) {
    |             ++++
@@ -392,7 +392,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `T3`
    |
 LL | fn example<Q: T3>(q: Q) {
    |             ++++
diff --git a/tests/ui/errors/traits/blame-trait-error-spans-on-exprs.stderr b/tests/ui/errors/traits/blame-trait-error-spans-on-exprs.stderr
index b6a24e12bcc..90380091c50 100644
--- a/tests/ui/errors/traits/blame-trait-error-spans-on-exprs.stderr
+++ b/tests/ui/errors/traits/blame-trait-error-spans-on-exprs.stderr
@@ -23,7 +23,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `T3`
    |
 LL | fn example<Q: T3>(q: Q) {
    |             ++++
@@ -53,7 +53,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `T3`
    |
 LL | fn example<Q: T3>(q: Q) {
    |             ++++
@@ -85,7 +85,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `T3`
    |
 LL | fn example<Q: T3>(q: Q) {
    |             ++++
@@ -117,7 +117,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `T3`
    |
 LL | fn example<Q: T3>(q: Q) {
    |             ++++
@@ -147,7 +147,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `T3`
    |
 LL | fn example<Q: T3>(q: Q) {
    |             ++++
@@ -172,7 +172,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `T2`
    |
 LL | fn example<Q: T2>(q: Q) {
    |             ++++
@@ -204,7 +204,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `T3`
    |
 LL | fn example<Q: T3>(q: Q) {
    |             ++++
@@ -236,7 +236,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `T3`
    |
 LL | fn example<Q: T3>(q: Q) {
    |             ++++
@@ -261,7 +261,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `T1`
    |
 LL | fn example<Q: T1>(q: Q) {
    |             ++++
@@ -286,7 +286,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `T1`
    |
 LL | fn example<Q: T1>(q: Q) {
    |             ++++
@@ -318,7 +318,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `T3`
    |
 LL | fn example<Q: T3>(q: Q) {
    |             ++++
@@ -343,7 +343,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `T1`
    |
 LL | fn example<Q: T1>(q: Q) {
    |             ++++
@@ -370,7 +370,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `T1`
    |
 LL | fn example<Q: T1>(q: Q) {
    |             ++++
@@ -402,7 +402,7 @@ note: required by a bound in `want`
    |
 LL | fn want<V: T1>(_x: V) {}
    |            ^^ required by this bound in `want`
-help: consider restricting type parameter `Q`
+help: consider restricting type parameter `Q` with trait `T3`
    |
 LL | fn example<Q: T3>(q: Q) {
    |             ++++
diff --git a/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr b/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr
index 044c1ae2dd4..b5c718ec381 100644
--- a/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr
+++ b/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr
@@ -4,6 +4,7 @@ warning: `extern` fn uses type `CStr`, which is not FFI-safe
 LL | type Foo = extern "C" fn(::std::ffi::CStr);
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
+   = note: the function pointer to `extern "C" fn(CStr)` is FFI-unsafe due to `CStr`
    = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
    = note: `CStr`/`CString` do not have a guaranteed layout
    = note: `#[warn(improper_ctypes_definitions)]` on by default
@@ -14,6 +15,7 @@ warning: `extern` block uses type `CStr`, which is not FFI-safe
 LL |     fn meh(blah: Foo);
    |                  ^^^ not FFI-safe
    |
+   = note: the function pointer to `extern "C" fn(CStr)` is FFI-unsafe due to `CStr`
    = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
    = note: `CStr`/`CString` do not have a guaranteed layout
    = note: `#[warn(improper_ctypes)]` on by default
diff --git a/tests/ui/extern/extern-C-str-arg-ice-80125.stderr b/tests/ui/extern/extern-C-str-arg-ice-80125.stderr
index ebd6cec6ecd..f2ee21c3166 100644
--- a/tests/ui/extern/extern-C-str-arg-ice-80125.stderr
+++ b/tests/ui/extern/extern-C-str-arg-ice-80125.stderr
@@ -4,6 +4,7 @@ warning: `extern` fn uses type `str`, which is not FFI-safe
 LL | type ExternCallback = extern "C" fn(*const u8, u32, str);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
+   = note: the function pointer to `extern "C" fn(*const u8, u32, str)` is FFI-unsafe due to `str`
    = help: consider using `*const u8` and a length instead
    = note: string slices have no C equivalent
    = note: `#[warn(improper_ctypes_definitions)]` on by default
@@ -14,6 +15,7 @@ warning: `extern` fn uses type `str`, which is not FFI-safe
 LL | pub extern "C" fn register_something(bind: ExternCallback) -> Struct {
    |                                            ^^^^^^^^^^^^^^ not FFI-safe
    |
+   = note: the function pointer to `extern "C" fn(*const u8, u32, str)` is FFI-unsafe due to `str`
    = help: consider using `*const u8` and a length instead
    = note: string slices have no C equivalent
 
diff --git a/tests/ui/feature-gates/feature-gate-guard-patterns.rs b/tests/ui/feature-gates/feature-gate-guard-patterns.rs
new file mode 100644
index 00000000000..929e8ef3181
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-guard-patterns.rs
@@ -0,0 +1,46 @@
+fn match_guards_still_work() {
+    match 0 {
+        0 if guard(0) => {},
+        _ => {},
+    }
+}
+
+fn other_guards_dont() {
+    match 0 {
+        (0 if guard(0)) => {},
+        //~^ ERROR unexpected parentheses surrounding `match` arm pattern
+        _ => {},
+    }
+
+    match 0 {
+        (0 if guard(0)) | 1 => {},
+        //~^ ERROR: guard patterns are experimental
+        _ => {},
+    }
+
+    let ((x if guard(x)) | x) = 0;
+    //~^ ERROR: guard patterns are experimental
+    //~| ERROR: cannot find value `x`
+
+    if let (x if guard(x)) = 0 {}
+    //~^ ERROR: guard patterns are experimental
+    //~| WARN: irrefutable
+
+    while let (x if guard(x)) = 0 {}
+    //~^ ERROR: guard patterns are experimental
+    //~| WARN: irrefutable
+
+    #[cfg(FALSE)]
+    while let (x if guard(x)) = 0 {}
+    //~^ ERROR: guard patterns are experimental
+}
+
+fn even_as_function_parameters(((x if guard(x), _) | (_, x)): (i32, i32)) {}
+//~^ ERROR: guard patterns are experimental
+//~| ERROR: cannot find value `x`
+
+fn guard<T>(x: T) -> bool {
+    unimplemented!()
+}
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-guard-patterns.stderr b/tests/ui/feature-gates/feature-gate-guard-patterns.stderr
new file mode 100644
index 00000000000..0613b5c95a4
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-guard-patterns.stderr
@@ -0,0 +1,119 @@
+error: unexpected parentheses surrounding `match` arm pattern
+  --> $DIR/feature-gate-guard-patterns.rs:10:9
+   |
+LL |         (0 if guard(0)) => {},
+   |         ^             ^
+   |
+help: remove parentheses surrounding the pattern
+   |
+LL -         (0 if guard(0)) => {},
+LL +         0 if guard(0) => {},
+   |
+
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/feature-gate-guard-patterns.rs:21:22
+   |
+LL |     let ((x if guard(x)) | x) = 0;
+   |                      ^ not found in this scope
+
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/feature-gate-guard-patterns.rs:38:45
+   |
+LL | fn even_as_function_parameters(((x if guard(x), _) | (_, x)): (i32, i32)) {}
+   |                                             ^
+   |
+help: the binding `x` is available in a different scope in the same function
+  --> $DIR/feature-gate-guard-patterns.rs:21:11
+   |
+LL |     let ((x if guard(x)) | x) = 0;
+   |           ^
+
+error[E0658]: guard patterns are experimental
+  --> $DIR/feature-gate-guard-patterns.rs:16:15
+   |
+LL |         (0 if guard(0)) | 1 => {},
+   |               ^^^^^^^^
+   |
+   = note: see issue #129967 <https://github.com/rust-lang/rust/issues/129967> for more information
+   = help: add `#![feature(guard_patterns)]` 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: consider using match arm guards
+
+error[E0658]: guard patterns are experimental
+  --> $DIR/feature-gate-guard-patterns.rs:21:16
+   |
+LL |     let ((x if guard(x)) | x) = 0;
+   |                ^^^^^^^^
+   |
+   = note: see issue #129967 <https://github.com/rust-lang/rust/issues/129967> for more information
+   = help: add `#![feature(guard_patterns)]` 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: consider using match arm guards
+
+error[E0658]: guard patterns are experimental
+  --> $DIR/feature-gate-guard-patterns.rs:25:18
+   |
+LL |     if let (x if guard(x)) = 0 {}
+   |                  ^^^^^^^^
+   |
+   = note: see issue #129967 <https://github.com/rust-lang/rust/issues/129967> for more information
+   = help: add `#![feature(guard_patterns)]` 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: consider using match arm guards
+
+error[E0658]: guard patterns are experimental
+  --> $DIR/feature-gate-guard-patterns.rs:29:21
+   |
+LL |     while let (x if guard(x)) = 0 {}
+   |                     ^^^^^^^^
+   |
+   = note: see issue #129967 <https://github.com/rust-lang/rust/issues/129967> for more information
+   = help: add `#![feature(guard_patterns)]` 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: consider using match arm guards
+
+error[E0658]: guard patterns are experimental
+  --> $DIR/feature-gate-guard-patterns.rs:34:21
+   |
+LL |     while let (x if guard(x)) = 0 {}
+   |                     ^^^^^^^^
+   |
+   = note: see issue #129967 <https://github.com/rust-lang/rust/issues/129967> for more information
+   = help: add `#![feature(guard_patterns)]` 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: consider using match arm guards
+
+error[E0658]: guard patterns are experimental
+  --> $DIR/feature-gate-guard-patterns.rs:38:39
+   |
+LL | fn even_as_function_parameters(((x if guard(x), _) | (_, x)): (i32, i32)) {}
+   |                                       ^^^^^^^^
+   |
+   = note: see issue #129967 <https://github.com/rust-lang/rust/issues/129967> for more information
+   = help: add `#![feature(guard_patterns)]` 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: consider using match arm guards
+
+warning: irrefutable `if let` pattern
+  --> $DIR/feature-gate-guard-patterns.rs:25:8
+   |
+LL |     if let (x if guard(x)) = 0 {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this pattern will always match, so the `if let` is useless
+   = help: consider replacing the `if let` with a `let`
+   = note: `#[warn(irrefutable_let_patterns)]` on by default
+
+warning: irrefutable `while let` pattern
+  --> $DIR/feature-gate-guard-patterns.rs:29:11
+   |
+LL |     while let (x if guard(x)) = 0 {}
+   |           ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this pattern will always match, so the loop will never exit
+   = help: consider instead using a `loop { ... }` with a `let` inside it
+
+error: aborting due to 9 previous errors; 2 warnings emitted
+
+Some errors have detailed explanations: E0425, E0658.
+For more information about an error, try `rustc --explain E0425`.
diff --git a/tests/ui/generic-associated-types/generic-associated-types-where.stderr b/tests/ui/generic-associated-types/generic-associated-types-where.stderr
index 9a745c099c0..7dce34650d7 100644
--- a/tests/ui/generic-associated-types/generic-associated-types-where.stderr
+++ b/tests/ui/generic-associated-types/generic-associated-types-where.stderr
@@ -5,7 +5,7 @@ LL |     type Assoc2<T> = Vec<T>;
    |                      ^^^^^^ `T` cannot be formatted with the default formatter
    |
    = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Display`
    |
 LL |     type Assoc2<T: std::fmt::Display> = Vec<T>;
    |                  +++++++++++++++++++
diff --git a/tests/ui/generic-associated-types/impl_bounds.stderr b/tests/ui/generic-associated-types/impl_bounds.stderr
index 261070d1db4..aa56505dd30 100644
--- a/tests/ui/generic-associated-types/impl_bounds.stderr
+++ b/tests/ui/generic-associated-types/impl_bounds.stderr
@@ -41,7 +41,7 @@ LL | trait Foo {
 LL |     type C where Self: Clone;
    |          ^ this trait's associated type doesn't have the requirement `Fooy<T>: Copy`
    = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | impl<T: std::marker::Copy> Foo for Fooy<T> {
    |       +++++++++++++++++++
@@ -66,7 +66,7 @@ LL | trait Foo {
 LL |     fn d() where Self: Clone;
    |        ^ this trait's method doesn't have the requirement `Fooy<T>: Copy`
    = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | impl<T: std::marker::Copy> Foo for Fooy<T> {
    |       +++++++++++++++++++
diff --git a/tests/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr b/tests/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr
index 55901cf450b..ac91bdcf3e9 100644
--- a/tests/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr
+++ b/tests/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `UnsafeCopy::Item`
    |
 LL |     type Item<'a>: Copy;
    |                    ^^^^ required by this bound in `UnsafeCopy::Item`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | impl<T: std::marker::Copy> UnsafeCopy for T {
    |       +++++++++++++++++++
diff --git a/tests/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr b/tests/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr
index 3929e66a25a..d98071efe83 100644
--- a/tests/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr
+++ b/tests/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr
@@ -10,7 +10,7 @@ note: required by a bound in `Fun::F`
    |
 LL |     type F<'a>: Fn() -> u32;
    |                 ^^^^^^^^^^^ required by this bound in `Fun::F`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Fn`
    |
 LL | impl<T: Fn()> Fun for T {
    |       ++++++
diff --git a/tests/ui/generic-associated-types/issue-68643-broken-mir.stderr b/tests/ui/generic-associated-types/issue-68643-broken-mir.stderr
index 662726b8993..cd4c06a8660 100644
--- a/tests/ui/generic-associated-types/issue-68643-broken-mir.stderr
+++ b/tests/ui/generic-associated-types/issue-68643-broken-mir.stderr
@@ -10,7 +10,7 @@ note: required by a bound in `Fun::F`
    |
 LL |     type F<'a>: Fn() -> u32;
    |                 ^^^^^^^^^^^ required by this bound in `Fun::F`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Fn`
    |
 LL | impl<T: Fn()> Fun for T {
    |       ++++++
diff --git a/tests/ui/generic-associated-types/issue-68644-codegen-selection.stderr b/tests/ui/generic-associated-types/issue-68644-codegen-selection.stderr
index 34278249e35..12f9949a0d3 100644
--- a/tests/ui/generic-associated-types/issue-68644-codegen-selection.stderr
+++ b/tests/ui/generic-associated-types/issue-68644-codegen-selection.stderr
@@ -10,7 +10,7 @@ note: required by a bound in `Fun::F`
    |
 LL |     type F<'a>: Fn() -> u32;
    |                 ^^^^^^^^^^^ required by this bound in `Fun::F`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Fn`
    |
 LL | impl<T: Fn()> Fun for T {
    |       ++++++
diff --git a/tests/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr b/tests/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr
index dafe1c1d395..8b23f609530 100644
--- a/tests/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr
+++ b/tests/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr
@@ -10,7 +10,7 @@ note: required by a bound in `Fun::F`
    |
 LL |     type F<'a>: Fn() -> u32;
    |                 ^^^^^^^^^^^ required by this bound in `Fun::F`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Fn`
    |
 LL | impl<T: Fn()> Fun for T {
    |       ++++++
diff --git a/tests/ui/generic-associated-types/issue-74824.current.stderr b/tests/ui/generic-associated-types/issue-74824.current.stderr
index 231136612a0..3a72db27097 100644
--- a/tests/ui/generic-associated-types/issue-74824.current.stderr
+++ b/tests/ui/generic-associated-types/issue-74824.current.stderr
@@ -23,7 +23,7 @@ note: required by a bound in `UnsafeCopy::Copy`
    |
 LL |     type Copy<T>: Copy = Box<T>;
    |                   ^^^^ required by this bound in `UnsafeCopy::Copy`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Clone`
    |
 LL |     type Copy<T: std::clone::Clone>: Copy = Box<T>;
    |                +++++++++++++++++++
diff --git a/tests/ui/generic-associated-types/issue-74824.next.stderr b/tests/ui/generic-associated-types/issue-74824.next.stderr
index 231136612a0..3a72db27097 100644
--- a/tests/ui/generic-associated-types/issue-74824.next.stderr
+++ b/tests/ui/generic-associated-types/issue-74824.next.stderr
@@ -23,7 +23,7 @@ note: required by a bound in `UnsafeCopy::Copy`
    |
 LL |     type Copy<T>: Copy = Box<T>;
    |                   ^^^^ required by this bound in `UnsafeCopy::Copy`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Clone`
    |
 LL |     type Copy<T: std::clone::Clone>: Copy = Box<T>;
    |                +++++++++++++++++++
diff --git a/tests/ui/generic-associated-types/missing-bounds.stderr b/tests/ui/generic-associated-types/missing-bounds.stderr
index 1d7d80d1b07..6e0700639e9 100644
--- a/tests/ui/generic-associated-types/missing-bounds.stderr
+++ b/tests/ui/generic-associated-types/missing-bounds.stderr
@@ -71,7 +71,7 @@ LL |         Self(self.0 + rhs.0)
    |              |
    |              B
    |
-help: consider restricting type parameter `B`
+help: consider restricting type parameter `B` with trait `Add`
    |
 LL | impl<B: std::ops::Add<Output = B>> Add for D<B> {
    |       +++++++++++++++++++++++++++
diff --git a/tests/ui/higher-ranked/structually-relate-aliases.stderr b/tests/ui/higher-ranked/structually-relate-aliases.stderr
index cf3e4cc85b9..025fcc5e170 100644
--- a/tests/ui/higher-ranked/structually-relate-aliases.stderr
+++ b/tests/ui/higher-ranked/structually-relate-aliases.stderr
@@ -5,7 +5,7 @@ error[E0277]: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied
 LL | impl<T> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T {}
    |                                    ^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `T`
    |
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `ToUnit`
    |
 LL | impl<T: for<'a> ToUnit<'a>> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T {}
    |       ++++++++++++++++++++
diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr
index e10da26665e..da6013a4af3 100644
--- a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr
+++ b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr
@@ -13,7 +13,7 @@ LL | fn want_bar_for_any_ccx<B>(b: &B)
    |    -------------------- required by a bound in this function
 LL |     where B : for<'ccx> Bar<'ccx>
    |               ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_bar_for_any_ccx`
-help: consider further restricting this bound
+help: consider further restricting type parameter `B` with trait `Bar`
    |
 LL |     where B : Qux + for<'ccx> Bar<'ccx>
    |                   +++++++++++++++++++++
diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-85455.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-85455.stderr
index e60531a876b..5080d35bdde 100644
--- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-85455.stderr
+++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-85455.stderr
@@ -4,7 +4,7 @@ error[E0277]: the trait bound `for<'a> T: SomeTrait<'a>` is not satisfied
 LL |     callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> SomeTrait<'a>` is not implemented for `T`
    |
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `SomeTrait`
    |
 LL | fn give_me_ice<T: for<'a> SomeTrait<'a>>() {
    |                 +++++++++++++++++++++++
@@ -15,7 +15,7 @@ error[E0277]: the trait bound `for<'a> T: SomeTrait<'a>` is not satisfied
 LL |     callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> SomeTrait<'a>` is not implemented for `T`
    |
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `SomeTrait`
    |
 LL | fn give_me_ice<T: for<'a> SomeTrait<'a>>() {
    |                 +++++++++++++++++++++++
diff --git a/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr
index 38c7a9ea16e..1ddbd75142f 100644
--- a/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr
+++ b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr
@@ -17,7 +17,7 @@ LL | impl<A, F: MyFn<A>> Callback<A> for F {
    |            -------  ^^^^^^^^^^^     ^
    |            |
    |            unsatisfied trait bound introduced here
-help: consider further restricting this bound
+help: consider further restricting type parameter `F` with trait `MyFn`
    |
 LL |         F: Callback<Self::CallbackArg> + MyFn<i32>,
    |                                        +++++++++++
@@ -43,7 +43,7 @@ LL |     fn autobatch<F>(self) -> impl Trait
 ...
 LL |         F: Callback<Self::CallbackArg>,
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<Sender as ChannelSender>::autobatch`
-help: consider further restricting this bound
+help: consider further restricting type parameter `F` with trait `MyFn`
    |
 LL |         F: Callback<Self::CallbackArg> + MyFn<i32>,
    |                                        +++++++++++
@@ -68,7 +68,7 @@ LL | impl<A, F: MyFn<A>> Callback<A> for F {
    |            |
    |            unsatisfied trait bound introduced here
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: consider further restricting this bound
+help: consider further restricting type parameter `F` with trait `MyFn`
    |
 LL |         F: Callback<Self::CallbackArg> + MyFn<i32>,
    |                                        +++++++++++
@@ -121,7 +121,7 @@ LL | impl<A, F: MyFn<A>> Callback<A> for F {
    |            |
    |            unsatisfied trait bound introduced here
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: consider further restricting this bound
+help: consider further restricting type parameter `F` with trait `MyFn`
    |
 LL |         F: Callback<Self::CallbackArg> + MyFn<i32>,
    |                                        +++++++++++
@@ -137,7 +137,7 @@ note: required by a bound in `Callback`
    |
 LL | trait Callback<A>: MyFn<A, Output = Self::Ret> {
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Callback`
-help: consider further restricting this bound
+help: consider further restricting type parameter `F` with trait `MyFn`
    |
 LL |         F: Callback<Self::CallbackArg> + MyFn<i32>,
    |                                        +++++++++++
diff --git a/tests/ui/impl-trait/issue-55872-1.stderr b/tests/ui/impl-trait/issue-55872-1.stderr
index 2ccca0b562c..81759760bf1 100644
--- a/tests/ui/impl-trait/issue-55872-1.stderr
+++ b/tests/ui/impl-trait/issue-55872-1.stderr
@@ -17,7 +17,7 @@ LL |         (S::default(), T::default())
    |         ---------------------------- return type was inferred to be `(S, T)` here
    |
    = note: required because it appears within the type `(S, T)`
-help: consider further restricting this bound
+help: consider further restricting type parameter `S` with trait `Copy`
    |
 LL | impl<S: Default + std::marker::Copy> Bar for S {
    |                 +++++++++++++++++++
@@ -32,7 +32,7 @@ LL |         (S::default(), T::default())
    |         ---------------------------- return type was inferred to be `(S, T)` here
    |
    = note: required because it appears within the type `(S, T)`
-help: consider further restricting this bound
+help: consider further restricting type parameter `T` with trait `Copy`
    |
 LL |     fn foo<T: Default + std::marker::Copy>() -> Self::E {
    |                       +++++++++++++++++++
diff --git a/tests/ui/impl-trait/normalize-tait-in-const.stderr b/tests/ui/impl-trait/normalize-tait-in-const.stderr
index 203fbfc1d2c..1dd84f10ad8 100644
--- a/tests/ui/impl-trait/normalize-tait-in-const.stderr
+++ b/tests/ui/impl-trait/normalize-tait-in-const.stderr
@@ -33,10 +33,6 @@ LL |     fun(filter_positive());
    |     ^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
-   |
-LL | const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruct + ~const Fn(&foo::Alias<'_>)>(fun: F) {
-   |                                                                              ++++++++++++++++++++++++++++
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/issues/issue-6738.stderr b/tests/ui/issues/issue-6738.stderr
index 9c25c0fd9a1..f22d6a2e468 100644
--- a/tests/ui/issues/issue-6738.stderr
+++ b/tests/ui/issues/issue-6738.stderr
@@ -6,7 +6,7 @@ LL |         self.x += v.x;
    |         |
    |         cannot use `+=` on type `T`
    |
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `AddAssign`
    |
 LL | impl<T: std::ops::AddAssign> Foo<T> {
    |       +++++++++++++++++++++
diff --git a/tests/ui/kindck/kindck-impl-type-params.stderr b/tests/ui/kindck/kindck-impl-type-params.stderr
index da9a8e5532c..a0a4ef09216 100644
--- a/tests/ui/kindck/kindck-impl-type-params.stderr
+++ b/tests/ui/kindck/kindck-impl-type-params.stderr
@@ -12,7 +12,7 @@ LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    |         |
    |         unsatisfied trait bound introduced here
    = note: required for the cast from `&S<T>` to `&dyn Gettable<T>`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Send`
    |
 LL | fn f<T: std::marker::Send>(val: T) {
    |       +++++++++++++++++++
@@ -31,7 +31,7 @@ LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    |                |
    |                unsatisfied trait bound introduced here
    = note: required for the cast from `&S<T>` to `&dyn Gettable<T>`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | fn f<T: std::marker::Copy>(val: T) {
    |       +++++++++++++++++++
@@ -50,7 +50,7 @@ LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    |         |
    |         unsatisfied trait bound introduced here
    = note: required for the cast from `&S<T>` to `&dyn Gettable<T>`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Send`
    |
 LL | fn g<T: std::marker::Send>(val: T) {
    |       +++++++++++++++++++
@@ -69,7 +69,7 @@ LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    |                |
    |                unsatisfied trait bound introduced here
    = note: required for the cast from `&S<T>` to `&dyn Gettable<T>`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | fn g<T: std::marker::Copy>(val: T) {
    |       +++++++++++++++++++
diff --git a/tests/ui/lang-items/assoc-lang-items.rs b/tests/ui/lang-items/assoc-lang-items.rs
new file mode 100644
index 00000000000..460d3ed2326
--- /dev/null
+++ b/tests/ui/lang-items/assoc-lang-items.rs
@@ -0,0 +1,35 @@
+//! Check that associated items can be marked as lang items, so that they don't have to be looked up
+//! by name or by definition order indirectly.
+//!
+//! This test is not *quite* high-fidelity: it checks that you can use lang items on associated
+//! items by looking at the error message *as a proxy*. That is, the error message is about
+//! undefined lang items and not invalid attribute target, indicating that it has reached lang item
+//! machinery (which is relying on knowing the implementation detail). However, it's annoying to
+//! write a full-fidelity test for this, so I think this is acceptable even though it's not *great*.
+//!
+//! This was implemented in <https://github.com/rust-lang/rust/pull/72559> to help with
+//! <https://github.com/rust-lang/rust/issues/70718>, which is itself relevant for e.g. `Fn::Output`
+//! or `Future::Output` or specific use cases like [Use `T`'s discriminant type in
+//! `mem::Discriminant<T>` instead of `u64`](https://github.com/rust-lang/rust/pull/70705).
+
+#![feature(lang_items)]
+
+trait Foo {
+    #[lang = "dummy_lang_item_1"] //~ ERROR definition
+    fn foo() {}
+
+    #[lang = "dummy_lang_item_2"] //~ ERROR definition
+    fn bar();
+
+    #[lang = "dummy_lang_item_3"] //~ ERROR definition
+    type MyType;
+}
+
+struct Bar;
+
+impl Bar {
+    #[lang = "dummy_lang_item_4"] //~ ERROR definition
+    fn test() {}
+}
+
+fn main() {}
diff --git a/tests/ui/assoc-lang-items.stderr b/tests/ui/lang-items/assoc-lang-items.stderr
index 59aec8e3fdc..7e61fea449b 100644
--- a/tests/ui/assoc-lang-items.stderr
+++ b/tests/ui/lang-items/assoc-lang-items.stderr
@@ -1,23 +1,23 @@
 error[E0522]: definition of an unknown lang item: `dummy_lang_item_1`
-  --> $DIR/assoc-lang-items.rs:4:5
+  --> $DIR/assoc-lang-items.rs:18:5
    |
 LL |     #[lang = "dummy_lang_item_1"]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown lang item `dummy_lang_item_1`
 
 error[E0522]: definition of an unknown lang item: `dummy_lang_item_2`
-  --> $DIR/assoc-lang-items.rs:7:5
+  --> $DIR/assoc-lang-items.rs:21:5
    |
 LL |     #[lang = "dummy_lang_item_2"]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown lang item `dummy_lang_item_2`
 
 error[E0522]: definition of an unknown lang item: `dummy_lang_item_3`
-  --> $DIR/assoc-lang-items.rs:10:5
+  --> $DIR/assoc-lang-items.rs:24:5
    |
 LL |     #[lang = "dummy_lang_item_3"]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown lang item `dummy_lang_item_3`
 
 error[E0522]: definition of an unknown lang item: `dummy_lang_item_4`
-  --> $DIR/assoc-lang-items.rs:17:5
+  --> $DIR/assoc-lang-items.rs:31:5
    |
 LL |     #[lang = "dummy_lang_item_4"]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown lang item `dummy_lang_item_4`
diff --git a/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.stderr b/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.stderr
index 206a6801065..3b051ef9a88 100644
--- a/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.stderr
+++ b/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.stderr
@@ -6,7 +6,7 @@ LL | impl<A, B> FnOnce<A> for CachedFun<A, B>
    |
 note: required by a bound in `FnOnce`
   --> $SRC_DIR/core/src/ops/function.rs:LL:COL
-help: consider further restricting this bound
+help: consider further restricting type parameter `A` with unstable trait `Tuple`
    |
 LL |     A: Eq + Hash + Clone + std::marker::Tuple,
    |                          ++++++++++++++++++++
@@ -19,7 +19,7 @@ LL | impl<A, B> FnMut<A> for CachedFun<A, B>
    |
 note: required by a bound in `FnMut`
   --> $SRC_DIR/core/src/ops/function.rs:LL:COL
-help: consider further restricting this bound
+help: consider further restricting type parameter `A` with unstable trait `Tuple`
    |
 LL |     A: Eq + Hash + Clone + std::marker::Tuple,
    |                          ++++++++++++++++++++
@@ -30,7 +30,7 @@ error[E0277]: functions with the "rust-call" ABI must take a single non-self tup
 LL |     extern "rust-call" fn call_once(mut self, a: A) -> Self::Output {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `A`
    |
-help: consider further restricting this bound
+help: consider further restricting type parameter `A` with unstable trait `Tuple`
    |
 LL |     A: Eq + Hash + Clone + std::marker::Tuple,
    |                          ++++++++++++++++++++
@@ -41,7 +41,7 @@ error[E0277]: functions with the "rust-call" ABI must take a single non-self tup
 LL |     extern "rust-call" fn call_mut(&mut self, a: A) -> Self::Output {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `A`
    |
-help: consider further restricting this bound
+help: consider further restricting type parameter `A` with unstable trait `Tuple`
    |
 LL |     A: Eq + Hash + Clone + std::marker::Tuple,
    |                          ++++++++++++++++++++
@@ -56,7 +56,7 @@ LL |         self.call_mut(a)
    |
 note: required by a bound in `call_mut`
   --> $SRC_DIR/core/src/ops/function.rs:LL:COL
-help: consider further restricting this bound
+help: consider further restricting type parameter `A` with unstable trait `Tuple`
    |
 LL |     A: Eq + Hash + Clone + std::marker::Tuple,
    |                          ++++++++++++++++++++
diff --git a/tests/ui/lazy-type-alias/unsatisfied-bounds-type-alias-body.stderr b/tests/ui/lazy-type-alias/unsatisfied-bounds-type-alias-body.stderr
index bd8095224a7..d0d4d04e28a 100644
--- a/tests/ui/lazy-type-alias/unsatisfied-bounds-type-alias-body.stderr
+++ b/tests/ui/lazy-type-alias/unsatisfied-bounds-type-alias-body.stderr
@@ -4,7 +4,7 @@ error[E0277]: cannot multiply `T` by `T`
 LL | type Alias<T> = <T as std::ops::Mul>::Output;
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `T * T`
    |
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Mul`
    |
 LL | type Alias<T: std::ops::Mul> = <T as std::ops::Mul>::Output;
    |             +++++++++++++++
diff --git a/tests/ui/lint/extern-C-fnptr-lints-slices.rs b/tests/ui/lint/extern-C-fnptr-lints-slices.rs
index 0c35eb37a48..4e3832ab1b6 100644
--- a/tests/ui/lint/extern-C-fnptr-lints-slices.rs
+++ b/tests/ui/lint/extern-C-fnptr-lints-slices.rs
@@ -3,7 +3,7 @@
 // It's an improper ctype (a slice) arg in an extern "C" fnptr.
 
 pub type F = extern "C" fn(&[u8]);
-//~^ ERROR: `extern` fn uses type `[u8]`, which is not FFI-safe
+//~^ ERROR: `extern` fn uses type `&[u8]`, which is not FFI-safe
 
 
 fn main() {}
diff --git a/tests/ui/lint/extern-C-fnptr-lints-slices.stderr b/tests/ui/lint/extern-C-fnptr-lints-slices.stderr
index d13f93ca96f..c0923dd96c8 100644
--- a/tests/ui/lint/extern-C-fnptr-lints-slices.stderr
+++ b/tests/ui/lint/extern-C-fnptr-lints-slices.stderr
@@ -1,11 +1,12 @@
-error: `extern` fn uses type `[u8]`, which is not FFI-safe
+error: `extern` fn uses type `&[u8]`, which is not FFI-safe
   --> $DIR/extern-C-fnptr-lints-slices.rs:5:14
    |
 LL | pub type F = extern "C" fn(&[u8]);
    |              ^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
-   = help: consider using a raw pointer instead
-   = note: slices have no C equivalent
+   = note: the function pointer to `for<'a> extern "C" fn(&'a [u8])` is FFI-unsafe due to `&[u8]`
+   = help: consider using a raw pointer to the slice's first element (and a length) instead
+   = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
 note: the lint level is defined here
   --> $DIR/extern-C-fnptr-lints-slices.rs:1:8
    |
diff --git a/tests/ui/lint/lint-ctypes-73249-2.stderr b/tests/ui/lint/lint-ctypes-73249-2.stderr
index ef30a406969..f035cdb213e 100644
--- a/tests/ui/lint/lint-ctypes-73249-2.stderr
+++ b/tests/ui/lint/lint-ctypes-73249-2.stderr
@@ -4,6 +4,7 @@ error: `extern` block uses type `Qux`, which is not FFI-safe
 LL |     fn lint_me() -> A<()>;
    |                     ^^^^^ not FFI-safe
    |
+   = note: this reference (`&Qux`) is ABI-compatible with a C pointer, but `Qux` itself does not have a C layout
    = note: opaque types have no C equivalent
 note: the lint level is defined here
   --> $DIR/lint-ctypes-73249-2.rs:2:9
diff --git a/tests/ui/lint/lint-ctypes-94223.stderr b/tests/ui/lint/lint-ctypes-94223.stderr
index bd127cf6004..4bebca69b7f 100644
--- a/tests/ui/lint/lint-ctypes-94223.stderr
+++ b/tests/ui/lint/lint-ctypes-94223.stderr
@@ -4,7 +4,8 @@ error: `extern` fn uses type `[u8]`, which is not FFI-safe
 LL | pub fn bad(f: extern "C" fn([u8])) {}
    |               ^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
-   = help: consider using a raw pointer instead
+   = note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]`
+   = help: consider using a raw pointer to the slice's first element (and a length) instead
    = note: slices have no C equivalent
 note: the lint level is defined here
   --> $DIR/lint-ctypes-94223.rs:2:9
@@ -18,7 +19,8 @@ error: `extern` fn uses type `[u8]`, which is not FFI-safe
 LL | pub fn bad_twice(f: Result<extern "C" fn([u8]), extern "C" fn([u8])>) {}
    |                            ^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
-   = help: consider using a raw pointer instead
+   = note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]`
+   = help: consider using a raw pointer to the slice's first element (and a length) instead
    = note: slices have no C equivalent
 
 error: `extern` fn uses type `[u8]`, which is not FFI-safe
@@ -27,7 +29,8 @@ error: `extern` fn uses type `[u8]`, which is not FFI-safe
 LL | pub fn bad_twice(f: Result<extern "C" fn([u8]), extern "C" fn([u8])>) {}
    |                                                 ^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
-   = help: consider using a raw pointer instead
+   = note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]`
+   = help: consider using a raw pointer to the slice's first element (and a length) instead
    = note: slices have no C equivalent
 
 error: `extern` fn uses type `[u8]`, which is not FFI-safe
@@ -36,7 +39,8 @@ error: `extern` fn uses type `[u8]`, which is not FFI-safe
 LL | struct BadStruct(extern "C" fn([u8]));
    |                  ^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
-   = help: consider using a raw pointer instead
+   = note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]`
+   = help: consider using a raw pointer to the slice's first element (and a length) instead
    = note: slices have no C equivalent
 
 error: `extern` fn uses type `[u8]`, which is not FFI-safe
@@ -45,7 +49,8 @@ error: `extern` fn uses type `[u8]`, which is not FFI-safe
 LL |     A(extern "C" fn([u8])),
    |       ^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
-   = help: consider using a raw pointer instead
+   = note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]`
+   = help: consider using a raw pointer to the slice's first element (and a length) instead
    = note: slices have no C equivalent
 
 error: `extern` fn uses type `[u8]`, which is not FFI-safe
@@ -54,7 +59,8 @@ error: `extern` fn uses type `[u8]`, which is not FFI-safe
 LL |     A(extern "C" fn([u8])),
    |       ^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
-   = help: consider using a raw pointer instead
+   = note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]`
+   = help: consider using a raw pointer to the slice's first element (and a length) instead
    = note: slices have no C equivalent
 
 error: `extern` fn uses type `[u8]`, which is not FFI-safe
@@ -63,7 +69,8 @@ error: `extern` fn uses type `[u8]`, which is not FFI-safe
 LL | type Foo = extern "C" fn([u8]);
    |            ^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
-   = help: consider using a raw pointer instead
+   = note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]`
+   = help: consider using a raw pointer to the slice's first element (and a length) instead
    = note: slices have no C equivalent
 
 error: `extern` fn uses type `Option<&<T as FooTrait>::FooType>`, which is not FFI-safe
@@ -72,6 +79,7 @@ error: `extern` fn uses type `Option<&<T as FooTrait>::FooType>`, which is not F
 LL | pub type Foo2<T> = extern "C" fn(Option<&<T as FooTrait>::FooType>);
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
+   = note: the function pointer to `for<'a> extern "C" fn(Option<&'a <T as FooTrait>::FooType>)` is FFI-unsafe due to `Option<&<T as FooTrait>::FooType>`
    = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
    = note: enum has no representation hint
 
@@ -81,6 +89,7 @@ error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe
 LL | pub static BAD: extern "C" fn(FfiUnsafe) = f;
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
+   = note: the function pointer to `extern "C" fn(FfiUnsafe)` is FFI-unsafe due to `FfiUnsafe`
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 note: the type is defined here
@@ -95,6 +104,7 @@ error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe
 LL | pub static BAD_TWICE: Result<extern "C" fn(FfiUnsafe), extern "C" fn(FfiUnsafe)> = Ok(f);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
+   = note: the function pointer to `extern "C" fn(FfiUnsafe)` is FFI-unsafe due to `FfiUnsafe`
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 note: the type is defined here
@@ -109,6 +119,7 @@ error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe
 LL | pub static BAD_TWICE: Result<extern "C" fn(FfiUnsafe), extern "C" fn(FfiUnsafe)> = Ok(f);
    |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
+   = note: the function pointer to `extern "C" fn(FfiUnsafe)` is FFI-unsafe due to `FfiUnsafe`
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 note: the type is defined here
@@ -123,6 +134,7 @@ error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe
 LL | pub const BAD_CONST: extern "C" fn(FfiUnsafe) = f;
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
+   = note: the function pointer to `extern "C" fn(FfiUnsafe)` is FFI-unsafe due to `FfiUnsafe`
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 note: the type is defined here
diff --git a/tests/ui/lint/lint-ctypes-cstr.rs b/tests/ui/lint/lint-ctypes-cstr.rs
index b04decd0bca..c4de5a44a96 100644
--- a/tests/ui/lint/lint-ctypes-cstr.rs
+++ b/tests/ui/lint/lint-ctypes-cstr.rs
@@ -8,7 +8,7 @@ extern "C" {
     //~^ ERROR `extern` block uses type `CStr`, which is not FFI-safe
     //~| HELP consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
     fn take_cstr_ref(s: &CStr);
-    //~^ ERROR `extern` block uses type `CStr`, which is not FFI-safe
+    //~^ ERROR `extern` block uses type `&CStr`, which is not FFI-safe
     //~| HELP consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
     fn take_cstring(s: CString);
     //~^ ERROR `extern` block uses type `CString`, which is not FFI-safe
@@ -27,7 +27,7 @@ extern "C" {
 }
 
 extern "C" fn rust_take_cstr_ref(s: &CStr) {}
-//~^ ERROR `extern` fn uses type `CStr`, which is not FFI-safe
+//~^ ERROR `extern` fn uses type `&CStr`, which is not FFI-safe
 //~| HELP consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
 extern "C" fn rust_take_cstring(s: CString) {}
 //~^ ERROR `extern` fn uses type `CString`, which is not FFI-safe
diff --git a/tests/ui/lint/lint-ctypes-cstr.stderr b/tests/ui/lint/lint-ctypes-cstr.stderr
index 8957758d577..da15b748f21 100644
--- a/tests/ui/lint/lint-ctypes-cstr.stderr
+++ b/tests/ui/lint/lint-ctypes-cstr.stderr
@@ -12,14 +12,14 @@ note: the lint level is defined here
 LL | #![deny(improper_ctypes, improper_ctypes_definitions)]
    |         ^^^^^^^^^^^^^^^
 
-error: `extern` block uses type `CStr`, which is not FFI-safe
+error: `extern` block uses type `&CStr`, which is not FFI-safe
   --> $DIR/lint-ctypes-cstr.rs:10:25
    |
 LL |     fn take_cstr_ref(s: &CStr);
    |                         ^^^^^ not FFI-safe
    |
    = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
-   = note: `CStr`/`CString` do not have a guaranteed layout
+   = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
 
 error: `extern` block uses type `CString`, which is not FFI-safe
   --> $DIR/lint-ctypes-cstr.rs:13:24
@@ -36,6 +36,7 @@ error: `extern` block uses type `CString`, which is not FFI-safe
 LL |     fn take_cstring_ref(s: &CString);
    |                            ^^^^^^^^ not FFI-safe
    |
+   = note: this reference (`&CString`) is ABI-compatible with a C pointer, but `CString` itself does not have a C layout
    = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
    = note: `CStr`/`CString` do not have a guaranteed layout
 
@@ -45,6 +46,7 @@ error: `extern` block uses type `CString`, which is not FFI-safe
 LL |     fn no_special_help_for_mut_cstring(s: *mut CString);
    |                                           ^^^^^^^^^^^^ not FFI-safe
    |
+   = note: this reference (`*mut CString`) is ABI-compatible with a C pointer, but `CString` itself does not have a C layout
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 
@@ -54,17 +56,18 @@ error: `extern` block uses type `CString`, which is not FFI-safe
 LL |     fn no_special_help_for_mut_cstring_ref(s: &mut CString);
    |                                               ^^^^^^^^^^^^ not FFI-safe
    |
+   = note: this reference (`&mut CString`) is ABI-compatible with a C pointer, but `CString` itself does not have a C layout
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 
-error: `extern` fn uses type `CStr`, which is not FFI-safe
+error: `extern` fn uses type `&CStr`, which is not FFI-safe
   --> $DIR/lint-ctypes-cstr.rs:29:37
    |
 LL | extern "C" fn rust_take_cstr_ref(s: &CStr) {}
    |                                     ^^^^^ not FFI-safe
    |
    = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
-   = note: `CStr`/`CString` do not have a guaranteed layout
+   = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
 note: the lint level is defined here
   --> $DIR/lint-ctypes-cstr.rs:2:26
    |
diff --git a/tests/ui/lint/lint-ctypes-fn.rs b/tests/ui/lint/lint-ctypes-fn.rs
index 73820c86d1a..e16ff9573fd 100644
--- a/tests/ui/lint/lint-ctypes-fn.rs
+++ b/tests/ui/lint/lint-ctypes-fn.rs
@@ -68,10 +68,10 @@ pub extern "C" fn ptr_unit(p: *const ()) { }
 pub extern "C" fn ptr_tuple(p: *const ((),)) { }
 
 pub extern "C" fn slice_type(p: &[u32]) { }
-//~^ ERROR: uses type `[u32]`
+//~^ ERROR: uses type `&[u32]`
 
 pub extern "C" fn str_type(p: &str) { }
-//~^ ERROR: uses type `str`
+//~^ ERROR: uses type `&str`
 
 pub extern "C" fn box_type(p: Box<u32>) { }
 
@@ -124,7 +124,7 @@ pub extern "C" fn transparent_i128(p: TransparentI128) { }
 //~^ ERROR: uses type `i128`
 
 pub extern "C" fn transparent_str(p: TransparentStr) { }
-//~^ ERROR: uses type `str`
+//~^ ERROR: uses type `&str`
 
 pub extern "C" fn transparent_fn(p: TransparentBadFn) { }
 
diff --git a/tests/ui/lint/lint-ctypes-fn.stderr b/tests/ui/lint/lint-ctypes-fn.stderr
index a62533a4be1..c86c02c8006 100644
--- a/tests/ui/lint/lint-ctypes-fn.stderr
+++ b/tests/ui/lint/lint-ctypes-fn.stderr
@@ -1,25 +1,25 @@
-error: `extern` fn uses type `[u32]`, which is not FFI-safe
+error: `extern` fn uses type `&[u32]`, which is not FFI-safe
   --> $DIR/lint-ctypes-fn.rs:70:33
    |
 LL | pub extern "C" fn slice_type(p: &[u32]) { }
    |                                 ^^^^^^ not FFI-safe
    |
-   = help: consider using a raw pointer instead
-   = note: slices have no C equivalent
+   = help: consider using a raw pointer to the slice's first element (and a length) instead
+   = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
 note: the lint level is defined here
   --> $DIR/lint-ctypes-fn.rs:2:9
    |
 LL | #![deny(improper_ctypes_definitions)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: `extern` fn uses type `str`, which is not FFI-safe
+error: `extern` fn uses type `&str`, which is not FFI-safe
   --> $DIR/lint-ctypes-fn.rs:73:31
    |
 LL | pub extern "C" fn str_type(p: &str) { }
    |                               ^^^^ not FFI-safe
    |
    = help: consider using `*const u8` and a length instead
-   = note: string slices have no C equivalent
+   = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
 
 error: `extern` fn uses type `Box<[u8]>`, which is not FFI-safe
   --> $DIR/lint-ctypes-fn.rs:80:34
@@ -27,7 +27,8 @@ error: `extern` fn uses type `Box<[u8]>`, which is not FFI-safe
 LL | pub extern "C" fn boxed_slice(p: Box<[u8]>) { }
    |                                  ^^^^^^^^^ not FFI-safe
    |
-   = note: box cannot be represented as a single pointer
+   = help: consider using a raw pointer to the slice's first element (and a length) instead
+   = note: this box for an unsized type contains metadata, which makes it incompatible with a C pointer
 
 error: `extern` fn uses type `Box<str>`, which is not FFI-safe
   --> $DIR/lint-ctypes-fn.rs:83:35
@@ -35,7 +36,8 @@ error: `extern` fn uses type `Box<str>`, which is not FFI-safe
 LL | pub extern "C" fn boxed_string(p: Box<str>) { }
    |                                   ^^^^^^^^ not FFI-safe
    |
-   = note: box cannot be represented as a single pointer
+   = help: consider using `*const u8` and a length instead
+   = note: this box for an unsized type contains metadata, which makes it incompatible with a C pointer
 
 error: `extern` fn uses type `Box<dyn Trait>`, which is not FFI-safe
   --> $DIR/lint-ctypes-fn.rs:86:34
@@ -43,7 +45,7 @@ error: `extern` fn uses type `Box<dyn Trait>`, which is not FFI-safe
 LL | pub extern "C" fn boxed_trait(p: Box<dyn Trait>) { }
    |                                  ^^^^^^^^^^^^^^ not FFI-safe
    |
-   = note: box cannot be represented as a single pointer
+   = note: this box for an unsized type contains metadata, which makes it incompatible with a C pointer
 
 error: `extern` fn uses type `char`, which is not FFI-safe
   --> $DIR/lint-ctypes-fn.rs:89:32
@@ -149,14 +151,14 @@ LL | pub extern "C" fn transparent_i128(p: TransparentI128) { }
    |
    = note: 128-bit integers don't currently have a known stable ABI
 
-error: `extern` fn uses type `str`, which is not FFI-safe
+error: `extern` fn uses type `&str`, which is not FFI-safe
   --> $DIR/lint-ctypes-fn.rs:126:38
    |
 LL | pub extern "C" fn transparent_str(p: TransparentStr) { }
    |                                      ^^^^^^^^^^^^^^ not FFI-safe
    |
    = help: consider using `*const u8` and a length instead
-   = note: string slices have no C equivalent
+   = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
 
 error: `extern` fn uses type `PhantomData<bool>`, which is not FFI-safe
   --> $DIR/lint-ctypes-fn.rs:172:43
diff --git a/tests/ui/lint/lint-ctypes.rs b/tests/ui/lint/lint-ctypes.rs
index dae07930aba..8c516ab8428 100644
--- a/tests/ui/lint/lint-ctypes.rs
+++ b/tests/ui/lint/lint-ctypes.rs
@@ -1,4 +1,5 @@
 #![feature(rustc_private)]
+#![feature(extern_types)]
 
 #![allow(private_interfaces)]
 #![deny(improper_ctypes)]
@@ -6,7 +7,9 @@
 use std::cell::UnsafeCell;
 use std::marker::PhantomData;
 use std::ffi::{c_int, c_uint};
+use std::fmt::Debug;
 
+unsafe extern "C" {type UnsizedOpaque;}
 trait Bar { }
 trait Mirror { type It: ?Sized; }
 impl<T: ?Sized> Mirror for T { type It = Self; }
@@ -20,7 +23,7 @@ pub type I32Pair = (i32, i32);
 #[repr(C)]
 pub struct ZeroSize;
 pub type RustFn = fn();
-pub type RustBadRet = extern "C" fn() -> Box<u32>;
+pub type RustBoxRet = extern "C" fn() -> Box<u32>;
 pub type CVoidRet = ();
 pub struct Foo;
 #[repr(transparent)]
@@ -28,7 +31,7 @@ pub struct TransparentI128(i128);
 #[repr(transparent)]
 pub struct TransparentStr(&'static str);
 #[repr(transparent)]
-pub struct TransparentBadFn(RustBadRet);
+pub struct TransparentBoxFn(RustBoxRet);
 #[repr(transparent)]
 pub struct TransparentInt(u32);
 #[repr(transparent)]
@@ -39,6 +42,16 @@ pub struct TransparentLifetime<'a>(*const u8, PhantomData<&'a ()>);
 pub struct TransparentUnit<U>(f32, PhantomData<U>);
 #[repr(transparent)]
 pub struct TransparentCustomZst(i32, ZeroSize);
+#[repr(C)]
+pub struct UnsizedStructBecauseForeign {
+    sized: u32,
+    unszd: UnsizedOpaque,
+}
+#[repr(C)]
+pub struct UnsizedStructBecauseDyn {
+    sized: u32,
+    unszd: dyn Debug,
+}
 
 #[repr(C)]
 pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData<i32>);
@@ -48,15 +61,14 @@ extern "C" {
     pub fn ptr_type2(size: *const Foo); //~ ERROR: uses type `Foo`
     pub fn ptr_unit(p: *const ());
     pub fn ptr_tuple(p: *const ((),)); //~ ERROR: uses type `((),)`
-    pub fn slice_type(p: &[u32]); //~ ERROR: uses type `[u32]`
-    pub fn str_type(p: &str); //~ ERROR: uses type `str`
-    pub fn box_type(p: Box<u32>); //~ ERROR uses type `Box<u32>`
+    pub fn slice_type(p: &[u32]); //~ ERROR: uses type `&[u32]`
+    pub fn str_type(p: &str); //~ ERROR: uses type `&str`
+    pub fn box_type(p: Box<u32>);
     pub fn opt_box_type(p: Option<Box<u32>>);
-    //~^ ERROR uses type `Option<Box<u32>>`
     pub fn char_type(p: char); //~ ERROR uses type `char`
     pub fn i128_type(p: i128); //~ ERROR uses type `i128`
     pub fn u128_type(p: u128); //~ ERROR uses type `u128`
-    pub fn trait_type(p: &dyn Bar); //~ ERROR uses type `dyn Bar`
+    pub fn trait_type(p: &dyn Bar); //~ ERROR uses type `&dyn Bar`
     pub fn tuple_type(p: (i32, i32)); //~ ERROR uses type `(i32, i32)`
     pub fn tuple_type2(p: I32Pair); //~ ERROR uses type `(i32, i32)`
     pub fn zero_size(p: ZeroSize); //~ ERROR uses type `ZeroSize`
@@ -66,12 +78,15 @@ extern "C" {
         -> ::std::marker::PhantomData<bool>; //~ ERROR uses type `PhantomData<bool>`
     pub fn fn_type(p: RustFn); //~ ERROR uses type `fn()`
     pub fn fn_type2(p: fn()); //~ ERROR uses type `fn()`
-    pub fn fn_contained(p: RustBadRet); //~ ERROR: uses type `Box<u32>`
+    pub fn fn_contained(p: RustBoxRet);
     pub fn transparent_i128(p: TransparentI128); //~ ERROR: uses type `i128`
-    pub fn transparent_str(p: TransparentStr); //~ ERROR: uses type `str`
-    pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: uses type `Box<u32>`
+    pub fn transparent_str(p: TransparentStr); //~ ERROR: uses type `&str`
+    pub fn transparent_fn(p: TransparentBoxFn);
     pub fn raw_array(arr: [u8; 8]); //~ ERROR: uses type `[u8; 8]`
 
+    pub fn struct_unsized_ptr_no_metadata(p: &UnsizedStructBecauseForeign);
+    pub fn struct_unsized_ptr_has_metadata(p: &UnsizedStructBecauseDyn); //~ ERROR uses type `&UnsizedStructBecauseDyn`
+
     pub fn no_niche_a(a: Option<UnsafeCell<extern fn()>>);
     //~^ ERROR: uses type `Option<UnsafeCell<extern "C" fn()>>`
     pub fn no_niche_b(b: Option<UnsafeCell<&i32>>);
diff --git a/tests/ui/lint/lint-ctypes.stderr b/tests/ui/lint/lint-ctypes.stderr
index 2c81c7b8e4b..8580a10b215 100644
--- a/tests/ui/lint/lint-ctypes.stderr
+++ b/tests/ui/lint/lint-ctypes.stderr
@@ -1,83 +1,68 @@
 error: `extern` block uses type `Foo`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:47:28
+  --> $DIR/lint-ctypes.rs:60:28
    |
 LL |     pub fn ptr_type1(size: *const Foo);
    |                            ^^^^^^^^^^ not FFI-safe
    |
+   = note: this reference (`*const Foo`) is ABI-compatible with a C pointer, but `Foo` itself does not have a C layout
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 note: the type is defined here
-  --> $DIR/lint-ctypes.rs:25:1
+  --> $DIR/lint-ctypes.rs:28:1
    |
 LL | pub struct Foo;
    | ^^^^^^^^^^^^^^
 note: the lint level is defined here
-  --> $DIR/lint-ctypes.rs:4:9
+  --> $DIR/lint-ctypes.rs:5:9
    |
 LL | #![deny(improper_ctypes)]
    |         ^^^^^^^^^^^^^^^
 
 error: `extern` block uses type `Foo`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:48:28
+  --> $DIR/lint-ctypes.rs:61:28
    |
 LL |     pub fn ptr_type2(size: *const Foo);
    |                            ^^^^^^^^^^ not FFI-safe
    |
+   = note: this reference (`*const Foo`) is ABI-compatible with a C pointer, but `Foo` itself does not have a C layout
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 note: the type is defined here
-  --> $DIR/lint-ctypes.rs:25:1
+  --> $DIR/lint-ctypes.rs:28:1
    |
 LL | pub struct Foo;
    | ^^^^^^^^^^^^^^
 
 error: `extern` block uses type `((),)`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:50:25
+  --> $DIR/lint-ctypes.rs:63:25
    |
 LL |     pub fn ptr_tuple(p: *const ((),));
    |                         ^^^^^^^^^^^^ not FFI-safe
    |
+   = note: this reference (`*const ((),)`) is ABI-compatible with a C pointer, but `((),)` itself does not have a C layout
    = help: consider using a struct instead
    = note: tuples have unspecified layout
 
-error: `extern` block uses type `[u32]`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:51:26
+error: `extern` block uses type `&[u32]`, which is not FFI-safe
+  --> $DIR/lint-ctypes.rs:64:26
    |
 LL |     pub fn slice_type(p: &[u32]);
    |                          ^^^^^^ not FFI-safe
    |
-   = help: consider using a raw pointer instead
-   = note: slices have no C equivalent
+   = help: consider using a raw pointer to the slice's first element (and a length) instead
+   = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
 
-error: `extern` block uses type `str`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:52:24
+error: `extern` block uses type `&str`, which is not FFI-safe
+  --> $DIR/lint-ctypes.rs:65:24
    |
 LL |     pub fn str_type(p: &str);
    |                        ^^^^ not FFI-safe
    |
    = help: consider using `*const u8` and a length instead
-   = note: string slices have no C equivalent
-
-error: `extern` block uses type `Box<u32>`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:53:24
-   |
-LL |     pub fn box_type(p: Box<u32>);
-   |                        ^^^^^^^^ not FFI-safe
-   |
-   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
-   = note: this struct has unspecified layout
-
-error: `extern` block uses type `Option<Box<u32>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:54:28
-   |
-LL |     pub fn opt_box_type(p: Option<Box<u32>>);
-   |                            ^^^^^^^^^^^^^^^^ not FFI-safe
-   |
-   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
-   = note: enum has no representation hint
+   = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
 
 error: `extern` block uses type `char`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:56:25
+  --> $DIR/lint-ctypes.rs:68:25
    |
 LL |     pub fn char_type(p: char);
    |                         ^^^^ not FFI-safe
@@ -86,7 +71,7 @@ LL |     pub fn char_type(p: char);
    = note: the `char` type has no C equivalent
 
 error: `extern` block uses type `i128`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:57:25
+  --> $DIR/lint-ctypes.rs:69:25
    |
 LL |     pub fn i128_type(p: i128);
    |                         ^^^^ not FFI-safe
@@ -94,23 +79,23 @@ LL |     pub fn i128_type(p: i128);
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` block uses type `u128`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:58:25
+  --> $DIR/lint-ctypes.rs:70:25
    |
 LL |     pub fn u128_type(p: u128);
    |                         ^^^^ not FFI-safe
    |
    = note: 128-bit integers don't currently have a known stable ABI
 
-error: `extern` block uses type `dyn Bar`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:59:26
+error: `extern` block uses type `&dyn Bar`, which is not FFI-safe
+  --> $DIR/lint-ctypes.rs:71:26
    |
 LL |     pub fn trait_type(p: &dyn Bar);
    |                          ^^^^^^^^ not FFI-safe
    |
-   = note: trait objects have no C equivalent
+   = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
 
 error: `extern` block uses type `(i32, i32)`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:60:26
+  --> $DIR/lint-ctypes.rs:72:26
    |
 LL |     pub fn tuple_type(p: (i32, i32));
    |                          ^^^^^^^^^^ not FFI-safe
@@ -119,7 +104,7 @@ LL |     pub fn tuple_type(p: (i32, i32));
    = note: tuples have unspecified layout
 
 error: `extern` block uses type `(i32, i32)`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:61:27
+  --> $DIR/lint-ctypes.rs:73:27
    |
 LL |     pub fn tuple_type2(p: I32Pair);
    |                           ^^^^^^^ not FFI-safe
@@ -128,7 +113,7 @@ LL |     pub fn tuple_type2(p: I32Pair);
    = note: tuples have unspecified layout
 
 error: `extern` block uses type `ZeroSize`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:62:25
+  --> $DIR/lint-ctypes.rs:74:25
    |
 LL |     pub fn zero_size(p: ZeroSize);
    |                         ^^^^^^^^ not FFI-safe
@@ -136,26 +121,26 @@ LL |     pub fn zero_size(p: ZeroSize);
    = help: consider adding a member to this struct
    = note: this struct has no fields
 note: the type is defined here
-  --> $DIR/lint-ctypes.rs:21:1
+  --> $DIR/lint-ctypes.rs:24:1
    |
 LL | pub struct ZeroSize;
    | ^^^^^^^^^^^^^^^^^^^
 
 error: `extern` block uses type `ZeroSizeWithPhantomData`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:63:33
+  --> $DIR/lint-ctypes.rs:75:33
    |
 LL |     pub fn zero_size_phantom(p: ZeroSizeWithPhantomData);
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
    = note: composed only of `PhantomData`
 note: the type is defined here
-  --> $DIR/lint-ctypes.rs:44:1
+  --> $DIR/lint-ctypes.rs:57:1
    |
 LL | pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData<i32>);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` block uses type `PhantomData<bool>`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:66:12
+  --> $DIR/lint-ctypes.rs:78:12
    |
 LL |         -> ::std::marker::PhantomData<bool>;
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -163,7 +148,7 @@ LL |         -> ::std::marker::PhantomData<bool>;
    = note: composed only of `PhantomData`
 
 error: `extern` block uses type `fn()`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:67:23
+  --> $DIR/lint-ctypes.rs:79:23
    |
 LL |     pub fn fn_type(p: RustFn);
    |                       ^^^^^^ not FFI-safe
@@ -172,7 +157,7 @@ LL |     pub fn fn_type(p: RustFn);
    = note: this function pointer has Rust-specific calling convention
 
 error: `extern` block uses type `fn()`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:68:24
+  --> $DIR/lint-ctypes.rs:80:24
    |
 LL |     pub fn fn_type2(p: fn());
    |                        ^^^^ not FFI-safe
@@ -180,43 +165,25 @@ LL |     pub fn fn_type2(p: fn());
    = help: consider using an `extern fn(...) -> ...` function pointer instead
    = note: this function pointer has Rust-specific calling convention
 
-error: `extern` block uses type `Box<u32>`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:69:28
-   |
-LL |     pub fn fn_contained(p: RustBadRet);
-   |                            ^^^^^^^^^^ not FFI-safe
-   |
-   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
-   = note: this struct has unspecified layout
-
 error: `extern` block uses type `i128`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:70:32
+  --> $DIR/lint-ctypes.rs:82:32
    |
 LL |     pub fn transparent_i128(p: TransparentI128);
    |                                ^^^^^^^^^^^^^^^ not FFI-safe
    |
    = note: 128-bit integers don't currently have a known stable ABI
 
-error: `extern` block uses type `str`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:71:31
+error: `extern` block uses type `&str`, which is not FFI-safe
+  --> $DIR/lint-ctypes.rs:83:31
    |
 LL |     pub fn transparent_str(p: TransparentStr);
    |                               ^^^^^^^^^^^^^^ not FFI-safe
    |
    = help: consider using `*const u8` and a length instead
-   = note: string slices have no C equivalent
-
-error: `extern` block uses type `Box<u32>`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:72:30
-   |
-LL |     pub fn transparent_fn(p: TransparentBadFn);
-   |                              ^^^^^^^^^^^^^^^^ not FFI-safe
-   |
-   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
-   = note: this struct has unspecified layout
+   = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
 
 error: `extern` block uses type `[u8; 8]`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:73:27
+  --> $DIR/lint-ctypes.rs:85:27
    |
 LL |     pub fn raw_array(arr: [u8; 8]);
    |                           ^^^^^^^ not FFI-safe
@@ -224,8 +191,16 @@ LL |     pub fn raw_array(arr: [u8; 8]);
    = help: consider passing a pointer to the array
    = note: passing raw arrays by value is not FFI-safe
 
+error: `extern` block uses type `&UnsizedStructBecauseDyn`, which is not FFI-safe
+  --> $DIR/lint-ctypes.rs:88:47
+   |
+LL |     pub fn struct_unsized_ptr_has_metadata(p: &UnsizedStructBecauseDyn);
+   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
+
 error: `extern` block uses type `Option<UnsafeCell<extern "C" fn()>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:75:26
+  --> $DIR/lint-ctypes.rs:90:26
    |
 LL |     pub fn no_niche_a(a: Option<UnsafeCell<extern fn()>>);
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -234,7 +209,7 @@ LL |     pub fn no_niche_a(a: Option<UnsafeCell<extern fn()>>);
    = note: enum has no representation hint
 
 error: `extern` block uses type `Option<UnsafeCell<&i32>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:77:26
+  --> $DIR/lint-ctypes.rs:92:26
    |
 LL |     pub fn no_niche_b(b: Option<UnsafeCell<&i32>>);
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -243,7 +218,7 @@ LL |     pub fn no_niche_b(b: Option<UnsafeCell<&i32>>);
    = note: enum has no representation hint
 
 error: `extern` block uses type `u128`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:80:34
+  --> $DIR/lint-ctypes.rs:95:34
    |
 LL |     pub static static_u128_type: u128;
    |                                  ^^^^ not FFI-safe
@@ -251,12 +226,12 @@ LL |     pub static static_u128_type: u128;
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` block uses type `u128`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:81:40
+  --> $DIR/lint-ctypes.rs:96:40
    |
 LL |     pub static static_u128_array_type: [u128; 16];
    |                                        ^^^^^^^^^^ not FFI-safe
    |
    = note: 128-bit integers don't currently have a known stable ABI
 
-error: aborting due to 27 previous errors
+error: aborting due to 24 previous errors
 
diff --git a/tests/ui/methods/filter-relevant-fn-bounds.stderr b/tests/ui/methods/filter-relevant-fn-bounds.stderr
index b737c0ab11f..0e00adf6ea6 100644
--- a/tests/ui/methods/filter-relevant-fn-bounds.stderr
+++ b/tests/ui/methods/filter-relevant-fn-bounds.stderr
@@ -8,7 +8,7 @@ LL | |     where
 LL | |         F: for<'a> FnOnce(<F as Output<'a>>::Type),
    | |___________________________________________________^ the trait `for<'a> Output<'a>` is not implemented for `F`
    |
-help: consider further restricting this bound
+help: consider further restricting type parameter `F` with trait `Output`
    |
 LL |         F: for<'a> FnOnce(<F as Output<'a>>::Type) + for<'a> Output<'a>,
    |                                                    ++++++++++++++++++++
@@ -19,7 +19,7 @@ error[E0277]: the trait bound `for<'a> F: Output<'a>` is not satisfied
 LL |     fn do_something_wrapper<O, F>(self, _: F)
    |        ^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Output<'a>` is not implemented for `F`
    |
-help: consider further restricting this bound
+help: consider further restricting type parameter `F` with trait `Output`
    |
 LL |         F: for<'a> FnOnce(<F as Output<'a>>::Type) + for<'a> Output<'a>,
    |                                                    ++++++++++++++++++++
@@ -30,7 +30,7 @@ error[E0277]: the trait bound `F: Output<'_>` is not satisfied
 LL |         F: for<'a> FnOnce(<F as Output<'a>>::Type),
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Output<'_>` is not implemented for `F`
    |
-help: consider further restricting this bound
+help: consider further restricting type parameter `F` with trait `Output`
    |
 LL |         F: for<'a> FnOnce(<F as Output<'a>>::Type) + Output<'_>,
    |                                                    ++++++++++++
@@ -41,7 +41,7 @@ error[E0277]: the trait bound `F: Output<'_>` is not satisfied
 LL |         F: for<'a> FnOnce(<F as Output<'a>>::Type),
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Output<'_>` is not implemented for `F`
    |
-help: consider further restricting this bound
+help: consider further restricting type parameter `F` with trait `Output`
    |
 LL |         F: for<'a> FnOnce(<F as Output<'a>>::Type) + Output<'_>,
    |                                                    ++++++++++++
diff --git a/tests/ui/mir/validate/validate-unsize-cast.stderr b/tests/ui/mir/validate/validate-unsize-cast.stderr
index cfb47b34e98..8449c6a24bd 100644
--- a/tests/ui/mir/validate/validate-unsize-cast.stderr
+++ b/tests/ui/mir/validate/validate-unsize-cast.stderr
@@ -10,7 +10,7 @@ note: required by a bound in `CastTo`
    |
 LL | pub trait CastTo<U: ?Sized>: Unsize<U> {}
    |                              ^^^^^^^^^ required by this bound in `CastTo`
-help: consider further restricting this bound
+help: consider further restricting type parameter `T` with unstable trait `Unsize`
    |
 LL | impl<T: ?Sized + std::marker::Unsize<U>, U: ?Sized> CastTo<U> for T {}
    |                ++++++++++++++++++++++++
diff --git a/tests/ui/mismatched_types/similar_paths_primitive.rs b/tests/ui/mismatched_types/similar_paths_primitive.rs
index 98890a15d98..a58fe68b863 100644
--- a/tests/ui/mismatched_types/similar_paths_primitive.rs
+++ b/tests/ui/mismatched_types/similar_paths_primitive.rs
@@ -1,14 +1,22 @@
 #![allow(non_camel_case_types)]
 
-struct bool;
-struct str;
+struct bool; //~ NOTE the other `bool` is defined in the current crate
+struct str; //~ NOTE the other `str` is defined in the current crate
 
-fn foo(_: bool) {}
-fn bar(_: &str) {}
+fn foo(_: bool) {} //~ NOTE function defined here
+fn bar(_: &str) {} //~ NOTE function defined here
 
 fn main() {
     foo(true);
     //~^ ERROR mismatched types [E0308]
+    //~| NOTE expected `bool`, found a different `bool`
+    //~| NOTE arguments to this function are incorrect
+    //~| NOTE `bool` and `bool` have similar names, but are actually distinct types
+    //~| NOTE one `bool` is a primitive defined by the language
     bar("hello");
     //~^ ERROR mismatched types [E0308]
+    //~| NOTE expected `str`, found a different `str`
+    //~| NOTE arguments to this function are incorrect
+    //~| NOTE `str` and `str` have similar names, but are actually distinct types
+    //~| NOTE one `str` is a primitive defined by the language
 }
diff --git a/tests/ui/mismatched_types/similar_paths_primitive.stderr b/tests/ui/mismatched_types/similar_paths_primitive.stderr
index 0530bf5863e..cf26234dba8 100644
--- a/tests/ui/mismatched_types/similar_paths_primitive.stderr
+++ b/tests/ui/mismatched_types/similar_paths_primitive.stderr
@@ -6,9 +6,9 @@ LL |     foo(true);
    |     |
    |     arguments to this function are incorrect
    |
-   = note: bool and `bool` have similar names, but are actually distinct types
-   = note: bool is a primitive defined by the language
-note: `bool` is defined in the current crate
+   = note: `bool` and `bool` have similar names, but are actually distinct types
+   = note: one `bool` is a primitive defined by the language
+note: the other `bool` is defined in the current crate
   --> $DIR/similar_paths_primitive.rs:3:1
    |
 LL | struct bool;
@@ -20,16 +20,16 @@ LL | fn foo(_: bool) {}
    |    ^^^ -------
 
 error[E0308]: mismatched types
-  --> $DIR/similar_paths_primitive.rs:12:9
+  --> $DIR/similar_paths_primitive.rs:16:9
    |
 LL |     bar("hello");
    |     --- ^^^^^^^ expected `str`, found a different `str`
    |     |
    |     arguments to this function are incorrect
    |
-   = note: str and `str` have similar names, but are actually distinct types
-   = note: str is a primitive defined by the language
-note: `str` is defined in the current crate
+   = note: `str` and `str` have similar names, but are actually distinct types
+   = note: one `str` is a primitive defined by the language
+note: the other `str` is defined in the current crate
   --> $DIR/similar_paths_primitive.rs:4:1
    |
 LL | struct str;
diff --git a/tests/ui/missing-trait-bounds/missing-trait-bound-for-op.stderr b/tests/ui/missing-trait-bounds/missing-trait-bound-for-op.stderr
index b3089cecfbb..80b003bbcc5 100644
--- a/tests/ui/missing-trait-bounds/missing-trait-bound-for-op.stderr
+++ b/tests/ui/missing-trait-bounds/missing-trait-bound-for-op.stderr
@@ -6,7 +6,7 @@ LL |     let _ = s == t;
    |             |
    |             &[T]
    |
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `PartialEq`
    |
 LL | pub fn foo<T: std::cmp::PartialEq>(s: &[T], t: &[T]) {
    |             +++++++++++++++++++++
diff --git a/tests/ui/moves/issue-34721.stderr b/tests/ui/moves/issue-34721.stderr
index 94780a04c1f..9834d009d22 100644
--- a/tests/ui/moves/issue-34721.stderr
+++ b/tests/ui/moves/issue-34721.stderr
@@ -18,7 +18,7 @@ note: `Foo::zero` takes ownership of the receiver `self`, which moves `x`
    |
 LL |     fn zero(self) -> Self;
    |             ^^^^
-help: consider further restricting this bound
+help: consider further restricting type parameter `T` with trait `Copy`
    |
 LL |     pub fn baz<T: Foo + Copy>(x: T) -> T {
    |                       ++++++
diff --git a/tests/ui/moves/use_of_moved_value_copy_suggestions.fixed b/tests/ui/moves/use_of_moved_value_copy_suggestions.fixed
index bfb855c7fb1..a5e0dd819b4 100644
--- a/tests/ui/moves/use_of_moved_value_copy_suggestions.fixed
+++ b/tests/ui/moves/use_of_moved_value_copy_suggestions.fixed
@@ -48,7 +48,7 @@ fn duplicate_custom_1<T: Copy + Trait>(t: S<T>) -> (S<T>, S<T>) where {
 fn duplicate_custom_2<T>(t: S<T>) -> (S<T>, S<T>)
 where
     T: A + Copy + Trait,
-    //~^ HELP consider further restricting this bound
+    //~^ HELP consider further restricting
 {
     (t, t) //~ use of moved value: `t`
 }
@@ -56,14 +56,14 @@ where
 fn duplicate_custom_3<T>(t: S<T>) -> (S<T>, S<T>)
 where
     T: A + Copy + Trait,
-    //~^ HELP consider further restricting this bound
+    //~^ HELP consider further restricting
     T: B,
 {
     (t, t) //~ use of moved value: `t`
 }
 
 fn duplicate_custom_4<T: A + Copy + Trait>(t: S<T>) -> (S<T>, S<T>)
-//~^ HELP consider further restricting this bound
+//~^ HELP consider further restricting
 where
     T: B,
 {
diff --git a/tests/ui/moves/use_of_moved_value_copy_suggestions.rs b/tests/ui/moves/use_of_moved_value_copy_suggestions.rs
index fbe5a1d74c3..60ca03ed698 100644
--- a/tests/ui/moves/use_of_moved_value_copy_suggestions.rs
+++ b/tests/ui/moves/use_of_moved_value_copy_suggestions.rs
@@ -48,7 +48,7 @@ fn duplicate_custom_1<T>(t: S<T>) -> (S<T>, S<T>) where {
 fn duplicate_custom_2<T>(t: S<T>) -> (S<T>, S<T>)
 where
     T: A,
-    //~^ HELP consider further restricting this bound
+    //~^ HELP consider further restricting
 {
     (t, t) //~ use of moved value: `t`
 }
@@ -56,14 +56,14 @@ where
 fn duplicate_custom_3<T>(t: S<T>) -> (S<T>, S<T>)
 where
     T: A,
-    //~^ HELP consider further restricting this bound
+    //~^ HELP consider further restricting
     T: B,
 {
     (t, t) //~ use of moved value: `t`
 }
 
 fn duplicate_custom_4<T: A>(t: S<T>) -> (S<T>, S<T>)
-//~^ HELP consider further restricting this bound
+//~^ HELP consider further restricting
 where
     T: B,
 {
diff --git a/tests/ui/moves/use_of_moved_value_copy_suggestions.stderr b/tests/ui/moves/use_of_moved_value_copy_suggestions.stderr
index c03204c7b9f..784945dbbae 100644
--- a/tests/ui/moves/use_of_moved_value_copy_suggestions.stderr
+++ b/tests/ui/moves/use_of_moved_value_copy_suggestions.stderr
@@ -17,7 +17,7 @@ LL | fn duplicate_t<T>(t: T) -> (T, T) {
 ...
 LL |     (t, t)
    |      - you could clone this value
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | fn duplicate_t<T: Copy>(t: T) -> (T, T) {
    |                 ++++++
@@ -33,7 +33,7 @@ LL |     (t, t)
    |      |
    |      value moved here
    |
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | fn duplicate_opt<T: Copy>(t: Option<T>) -> (Option<T>, Option<T>) {
    |                   ++++++
@@ -49,7 +49,7 @@ LL |     (t, t)
    |      |
    |      value moved here
    |
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | fn duplicate_tup1<T: Copy>(t: (T,)) -> ((T,), (T,)) {
    |                    ++++++
@@ -81,7 +81,7 @@ LL |     (t, t)
    |      |
    |      value moved here
    |
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with traits `Copy` and `Trait`
    |
 LL | fn duplicate_custom<T: Copy + Trait>(t: S<T>) -> (S<T>, S<T>) {
    |                      ++++++++++++++
@@ -97,7 +97,7 @@ LL |     (t, t)
    |      |
    |      value moved here
    |
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with traits `Copy` and `Trait`
    |
 LL | fn duplicate_custom_1<T: Copy + Trait>(t: S<T>) -> (S<T>, S<T>) where {
    |                        ++++++++++++++
@@ -113,7 +113,7 @@ LL |     (t, t)
    |      |
    |      value moved here
    |
-help: consider further restricting this bound
+help: consider further restricting type parameter `T` with traits `Copy` and `Trait`
    |
 LL |     T: A + Copy + Trait,
    |          ++++++++++++++
@@ -129,7 +129,7 @@ LL |     (t, t)
    |      |
    |      value moved here
    |
-help: consider further restricting this bound
+help: consider further restricting type parameter `T` with traits `Copy` and `Trait`
    |
 LL |     T: A + Copy + Trait,
    |          ++++++++++++++
@@ -145,7 +145,7 @@ LL |     (t, t)
    |      |
    |      value moved here
    |
-help: consider further restricting this bound
+help: consider further restricting type parameter `T` with traits `Copy` and `Trait`
    |
 LL | fn duplicate_custom_4<T: A + Copy + Trait>(t: S<T>) -> (S<T>, S<T>)
    |                            ++++++++++++++
@@ -169,7 +169,7 @@ LL | fn existing_colon<T:>(t: T) {
 ...
 LL |     [t, t];
    |      - you could clone this value
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | fn existing_colon<T: Copy>(t: T) {
    |                      ++++
@@ -193,7 +193,7 @@ LL | fn existing_colon_in_where<T>(t: T)
 ...
 LL |     [t, t];
    |      - you could clone this value
-help: consider further restricting type parameter `T`
+help: consider further restricting type parameter `T` with trait `Copy`
    |
 LL |     T:, T: Copy
    |       ~~~~~~~~~
diff --git a/tests/ui/parser/assoc/assoc-oddities-3.rs b/tests/ui/parser/assoc/assoc-oddities-3.rs
new file mode 100644
index 00000000000..1a41c4be023
--- /dev/null
+++ b/tests/ui/parser/assoc/assoc-oddities-3.rs
@@ -0,0 +1,41 @@
+//! Check that braces has the expected precedence in relation to index op and some arithmetic
+//! bin-ops involving nested braces.
+//!
+//! This is a regression test for [Wrapping expr in curly braces changes the operator precedence
+//! #28777](https://github.com/rust-lang/rust/issues/28777), which was fixed by
+//! <https://github.com/rust-lang/rust/pull/30375>.
+
+//@ run-pass
+
+fn that_odd_parse(c: bool, n: usize) -> u32 {
+    let x = 2;
+    let a = [1, 2, 3, 4];
+    let b = [5, 6, 7, 7];
+    x + if c { a } else { b }[n]
+}
+
+/// See [Wrapping expr in curly braces changes the operator precedence
+/// #28777](https://github.com/rust-lang/rust/issues/28777). This was fixed by
+/// <https://github.com/rust-lang/rust/pull/30375>. #30375 added the `that_odd_parse` example above,
+/// but that is not *quite* the same original example as reported in #28777, so we also include the
+/// original example here.
+fn check_issue_28777() {
+    // Before #30375 fixed the precedence...
+
+    // ... `v1` evaluated to 9, indicating a parse of `(1 + 2) * 3`, while
+    let v1 = { 1 + { 2 } * { 3 } };
+
+    // `v2` evaluated to 7, indicating a parse of `1 + (2 * 3)`.
+    let v2 = 1 + { 2 } * { 3 };
+
+    // Check that both now evaluate to 7, as was fixed by #30375.
+    assert_eq!(v1, 7);
+    assert_eq!(v2, 7);
+}
+
+fn main() {
+    assert_eq!(4, that_odd_parse(true, 1));
+    assert_eq!(8, that_odd_parse(false, 1));
+
+    check_issue_28777();
+}
diff --git a/tests/ui/parser/issues/issue-72373.rs b/tests/ui/parser/issues/issue-72373.rs
index 4da6061c27f..ed88d53539b 100644
--- a/tests/ui/parser/issues/issue-72373.rs
+++ b/tests/ui/parser/issues/issue-72373.rs
@@ -3,7 +3,7 @@ fn foo(c: &[u32], n: u32) -> u32 {
         [h, ..] if h > n => 0,
         [h, ..] if h == n => 1,
         [h, ref ts..] => foo(c, n - h) + foo(ts, n),
-        //~^ ERROR expected one of `,`, `@`, `]`, or `|`, found `..`
+        //~^ ERROR expected one of `,`, `@`, `]`, `if`, or `|`, found `..`
         [] => 0,
     }
 }
diff --git a/tests/ui/parser/issues/issue-72373.stderr b/tests/ui/parser/issues/issue-72373.stderr
index c596c6abda5..d566d6f5fd1 100644
--- a/tests/ui/parser/issues/issue-72373.stderr
+++ b/tests/ui/parser/issues/issue-72373.stderr
@@ -1,8 +1,8 @@
-error: expected one of `,`, `@`, `]`, or `|`, found `..`
+error: expected one of `,`, `@`, `]`, `if`, or `|`, found `..`
   --> $DIR/issue-72373.rs:5:19
    |
 LL |         [h, ref ts..] => foo(c, n - h) + foo(ts, n),
-   |                   ^^ expected one of `,`, `@`, `]`, or `|`
+   |                   ^^ expected one of `,`, `@`, `]`, `if`, or `|`
    |
 help: if you meant to bind the contents of the rest of the array pattern into `ts`, use `@`
    |
diff --git a/tests/ui/parser/misspelled-keywords/ref.stderr b/tests/ui/parser/misspelled-keywords/ref.stderr
index b8b52702314..398d9d6bb99 100644
--- a/tests/ui/parser/misspelled-keywords/ref.stderr
+++ b/tests/ui/parser/misspelled-keywords/ref.stderr
@@ -1,8 +1,8 @@
-error: expected one of `)`, `,`, `@`, or `|`, found `list`
+error: expected one of `)`, `,`, `@`, `if`, or `|`, found `list`
   --> $DIR/ref.rs:4:19
    |
 LL |         Some(refe list) => println!("{list:?}"),
-   |                   ^^^^ expected one of `)`, `,`, `@`, or `|`
+   |                   ^^^^ expected one of `)`, `,`, `@`, `if`, or `|`
    |
 help: there is a keyword `ref` with a similar name
    |
diff --git a/tests/ui/parser/pat-lt-bracket-7.rs b/tests/ui/parser/pat-lt-bracket-7.rs
index 327aef5ad15..abaeb4c83c0 100644
--- a/tests/ui/parser/pat-lt-bracket-7.rs
+++ b/tests/ui/parser/pat-lt-bracket-7.rs
@@ -3,7 +3,7 @@ fn main() {
     let foo = core::iter::empty();
 
     for Thing(x[]) in foo {}
-    //~^ ERROR: expected one of `)`, `,`, `@`, or `|`, found `[`
+    //~^ ERROR: expected one of `)`, `,`, `@`, `if`, or `|`, found `[`
 }
 
 const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types
diff --git a/tests/ui/parser/pat-lt-bracket-7.stderr b/tests/ui/parser/pat-lt-bracket-7.stderr
index 004dcfb2a7b..cc457a4e64e 100644
--- a/tests/ui/parser/pat-lt-bracket-7.stderr
+++ b/tests/ui/parser/pat-lt-bracket-7.stderr
@@ -1,10 +1,10 @@
-error: expected one of `)`, `,`, `@`, or `|`, found `[`
+error: expected one of `)`, `,`, `@`, `if`, or `|`, found `[`
   --> $DIR/pat-lt-bracket-7.rs:5:16
    |
 LL |     for Thing(x[]) in foo {}
    |                ^
    |                |
-   |                expected one of `)`, `,`, `@`, or `|`
+   |                expected one of `)`, `,`, `@`, `if`, or `|`
    |                help: missing `,`
 
 error[E0308]: mismatched types
diff --git a/tests/ui/parser/recover/recover-pat-exprs.rs b/tests/ui/parser/recover/recover-pat-exprs.rs
index e5e25df0c01..a78bb82828d 100644
--- a/tests/ui/parser/recover/recover-pat-exprs.rs
+++ b/tests/ui/parser/recover/recover-pat-exprs.rs
@@ -27,7 +27,7 @@ fn array_indexing() {
     { let x[0, 1, 2]; } //~ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[`
     { let x[0; 20]; } //~ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[`
     { let x[]; } //~ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[`
-    { let (x[]); } //~ error: expected one of `)`, `,`, `@`, or `|`, found `[`
+    { let (x[]); } //~ error: expected one of `)`, `,`, `@`, `if`, or `|`, found `[`
     //~^ missing `,`
 }
 
@@ -95,12 +95,12 @@ fn main() {
         f?() => (),
         //~^ error: expected a pattern, found an expression
         (_ + 1) => (),
-        //~^ error: expected one of `)`, `,`, or `|`, found `+`
+        //~^ error: expected one of `)`, `,`, `if`, or `|`, found `+`
     }
 
     let 1 + 1 = 2;
     //~^ error: expected a pattern, found an expression
 
     let b = matches!(x, (x * x | x.f()) | x[0]);
-    //~^ error: expected one of `)`, `,`, `@`, or `|`, found `*`
+    //~^ error: expected one of `)`, `,`, `@`, `if`, or `|`, found `*`
 }
diff --git a/tests/ui/parser/recover/recover-pat-exprs.stderr b/tests/ui/parser/recover/recover-pat-exprs.stderr
index 041dfd647ad..281eeced402 100644
--- a/tests/ui/parser/recover/recover-pat-exprs.stderr
+++ b/tests/ui/parser/recover/recover-pat-exprs.stderr
@@ -213,13 +213,13 @@ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[`
 LL |     { let x[]; }
    |            ^ expected one of `:`, `;`, `=`, `@`, or `|`
 
-error: expected one of `)`, `,`, `@`, or `|`, found `[`
+error: expected one of `)`, `,`, `@`, `if`, or `|`, found `[`
   --> $DIR/recover-pat-exprs.rs:30:13
    |
 LL |     { let (x[]); }
    |             ^
    |             |
-   |             expected one of `)`, `,`, `@`, or `|`
+   |             expected one of `)`, `,`, `@`, `if`, or `|`
    |             help: missing `,`
 
 error: expected a pattern, found an expression
@@ -611,11 +611,11 @@ LL |         x.sqrt() @ .. => (),
    |
    = note: bindings are `x`, `mut x`, `ref x`, and `ref mut x`
 
-error: expected one of `)`, `,`, or `|`, found `+`
+error: expected one of `)`, `,`, `if`, or `|`, found `+`
   --> $DIR/recover-pat-exprs.rs:97:12
    |
 LL |         (_ + 1) => (),
-   |            ^ expected one of `)`, `,`, or `|`
+   |            ^ expected one of `)`, `,`, `if`, or `|`
 
 error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:81:9
@@ -772,11 +772,11 @@ LL |     let 1 + 1 = 2;
    |
    = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch19-00-patterns.html>
 
-error: expected one of `)`, `,`, `@`, or `|`, found `*`
+error: expected one of `)`, `,`, `@`, `if`, or `|`, found `*`
   --> $DIR/recover-pat-exprs.rs:104:28
    |
 LL |     let b = matches!(x, (x * x | x.f()) | x[0]);
-   |                            ^ expected one of `)`, `,`, `@`, or `|`
+   |                            ^ expected one of `)`, `,`, `@`, `if`, or `|`
   --> $SRC_DIR/core/src/macros/mod.rs:LL:COL
    |
    = note: while parsing argument for this `pat` macro fragment
diff --git a/tests/ui/parser/recover/recover-pat-wildcards.rs b/tests/ui/parser/recover/recover-pat-wildcards.rs
index f506e2223d6..d4d28ce6358 100644
--- a/tests/ui/parser/recover/recover-pat-wildcards.rs
+++ b/tests/ui/parser/recover/recover-pat-wildcards.rs
@@ -8,7 +8,7 @@ fn a() {
 
 fn b() {
     match 2 {
-        (_ % 4) => () //~ error: expected one of `)`, `,`, or `|`, found `%`
+        (_ % 4) => () //~ error: expected one of `)`, `,`, `if`, or `|`, found `%`
     }
 }
 
@@ -40,7 +40,7 @@ fn f() {
 
 fn g() {
     match 7 {
-        (_ * 0)..5 => () //~ error: expected one of `)`, `,`, or `|`, found `*`
+        (_ * 0)..5 => () //~ error: expected one of `)`, `,`, `if`, or `|`, found `*`
     }
 }
 
diff --git a/tests/ui/parser/recover/recover-pat-wildcards.stderr b/tests/ui/parser/recover/recover-pat-wildcards.stderr
index 81a9920f6a2..f939e513370 100644
--- a/tests/ui/parser/recover/recover-pat-wildcards.stderr
+++ b/tests/ui/parser/recover/recover-pat-wildcards.stderr
@@ -4,11 +4,11 @@ error: expected one of `=>`, `if`, or `|`, found `+`
 LL |         _ + 1 => ()
    |           ^ expected one of `=>`, `if`, or `|`
 
-error: expected one of `)`, `,`, or `|`, found `%`
+error: expected one of `)`, `,`, `if`, or `|`, found `%`
   --> $DIR/recover-pat-wildcards.rs:11:12
    |
 LL |         (_ % 4) => ()
-   |            ^ expected one of `)`, `,`, or `|`
+   |            ^ expected one of `)`, `,`, `if`, or `|`
 
 error: expected one of `=>`, `if`, or `|`, found `.`
   --> $DIR/recover-pat-wildcards.rs:17:10
@@ -47,11 +47,11 @@ error: expected one of `=>`, `if`, or `|`, found reserved identifier `_`
 LL |         0..._ => ()
    |             ^ expected one of `=>`, `if`, or `|`
 
-error: expected one of `)`, `,`, or `|`, found `*`
+error: expected one of `)`, `,`, `if`, or `|`, found `*`
   --> $DIR/recover-pat-wildcards.rs:43:12
    |
 LL |         (_ * 0)..5 => ()
-   |            ^ expected one of `)`, `,`, or `|`
+   |            ^ expected one of `)`, `,`, `if`, or `|`
 
 error: expected one of `=>`, `if`, or `|`, found `(`
   --> $DIR/recover-pat-wildcards.rs:49:11
diff --git a/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr b/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr
index da8f4ca5f0c..6ce8f6d31a0 100644
--- a/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr
+++ b/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr
@@ -6,11 +6,11 @@ LL |     let a: u8 @ b = 0;
    |          |
    |          while parsing the type for `a`
 
-error: expected one of `)`, `,`, `@`, or `|`, found `:`
+error: expected one of `)`, `,`, `@`, `if`, or `|`, found `:`
   --> $DIR/nested-type-ascription-syntactically-invalid.rs:24:15
    |
 LL |     let a @ (b: u8);
-   |               ^ expected one of `)`, `,`, `@`, or `|`
+   |               ^ expected one of `)`, `,`, `@`, `if`, or `|`
    |
    = note: type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
 
diff --git a/tests/ui/pattern/rfc-3637-guard-patterns/macro-rules.rs b/tests/ui/pattern/rfc-3637-guard-patterns/macro-rules.rs
new file mode 100644
index 00000000000..76681f45bb3
--- /dev/null
+++ b/tests/ui/pattern/rfc-3637-guard-patterns/macro-rules.rs
@@ -0,0 +1,20 @@
+//@ run-pass
+//! Tests that the addition of guard patterns does not change the behavior of the `pat` macro
+//! fragment.
+#![feature(guard_patterns)]
+#![allow(incomplete_features)]
+
+macro_rules! has_guard {
+    ($p:pat) => {
+        false
+    };
+    ($p:pat if $e:expr) => {
+        true
+    };
+}
+
+fn main() {
+    assert_eq!(has_guard!(Some(_)), false);
+    assert_eq!(has_guard!(Some(_) if true), true);
+    assert_eq!(has_guard!((Some(_) if true)), false);
+}
diff --git a/tests/ui/phantom-auto-trait.stderr b/tests/ui/phantom-auto-trait.stderr
index 5af648f6a0c..ffd4c3a0e1a 100644
--- a/tests/ui/phantom-auto-trait.stderr
+++ b/tests/ui/phantom-auto-trait.stderr
@@ -23,7 +23,7 @@ note: required by a bound in `is_zen`
    |
 LL | fn is_zen<T: Zen>(_: T) {}
    |              ^^^ required by this bound in `is_zen`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Sync`
    |
 LL | fn not_sync<T: std::marker::Sync>(x: Guard<T>) {
    |              +++++++++++++++++++
@@ -58,7 +58,7 @@ note: required by a bound in `is_zen`
    |
 LL | fn is_zen<T: Zen>(_: T) {}
    |              ^^^ required by this bound in `is_zen`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Sync`
    |
 LL | fn nested_not_sync<T: std::marker::Sync>(x: Nested<Guard<T>>) {
    |                     +++++++++++++++++++
diff --git a/tests/ui/recursion/issue-83150.rs b/tests/ui/recursion/issue-83150.rs
index f91698d0637..e919a2d9309 100644
--- a/tests/ui/recursion/issue-83150.rs
+++ b/tests/ui/recursion/issue-83150.rs
@@ -1,8 +1,7 @@
-//~ ERROR overflow evaluating the requirement `Map<&mut std::ops::Range<u8>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>: Iterator`
+//~ ERROR overflow evaluating the requirement `Map<&mut std::ops::Range<u8>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>: Iterator`
 //@ build-fail
 //@ compile-flags: -Copt-level=0
 //@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash"
-//@ ignore-compare-mode-next-solver (hangs)
 
 fn main() {
     let mut iter = 0u8..1;
diff --git a/tests/ui/recursion/issue-83150.stderr b/tests/ui/recursion/issue-83150.stderr
index fb66436dbbd..92a39a44e4f 100644
--- a/tests/ui/recursion/issue-83150.stderr
+++ b/tests/ui/recursion/issue-83150.stderr
@@ -1,5 +1,5 @@
 warning: function cannot return without recursing
-  --> $DIR/issue-83150.rs:12:1
+  --> $DIR/issue-83150.rs:11:1
    |
 LL | fn func<T: Iterator<Item = u8>>(iter: &mut T) {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
@@ -10,12 +10,12 @@ LL |     func(&mut iter.map(|x| x + 1))
    = help: a `loop` may express intention better if this is on purpose
    = note: `#[warn(unconditional_recursion)]` on by default
 
-error[E0275]: overflow evaluating the requirement `Map<&mut std::ops::Range<u8>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>: Iterator`
+error[E0275]: overflow evaluating the requirement `Map<&mut std::ops::Range<u8>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>: Iterator`
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_83150`)
-   = note: required for `&mut Map<&mut std::ops::Range<u8>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>` to implement `Iterator`
+   = note: required for `&mut Map<&mut std::ops::Range<u8>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>` to implement `Iterator`
    = note: 65 redundant requirements hidden
-   = note: required for `&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range<u8>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>` to implement `Iterator`
+   = note: required for `&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range<u8>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>` to implement `Iterator`
 
 error: aborting due to 1 previous error; 1 warning emitted
 
diff --git a/tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr b/tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr
index b17d1e0ab11..87f0f47f240 100644
--- a/tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr
+++ b/tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr
@@ -4,7 +4,7 @@ error[E0277]: the trait bound `for<'z> T: Trait2<'y, 'z>` is not satisfied
 LL | fn callee<'x, 'y, T>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >)
    |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'z> Trait2<'y, 'z>` is not implemented for `T`
    |
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Trait2`
    |
 LL | fn callee<'x, 'y, T: for<'z> Trait2<'y, 'z>>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >)
    |                    ++++++++++++++++++++++++
@@ -17,7 +17,7 @@ LL | |
 LL | | }
    | |_^ the trait `for<'z> Trait2<'y, 'z>` is not implemented for `T`
    |
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Trait2`
    |
 LL | fn callee<'x, 'y, T: for<'z> Trait2<'y, 'z>>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >)
    |                    ++++++++++++++++++++++++
diff --git a/tests/ui/resolve/issue-55673.stderr b/tests/ui/resolve/issue-55673.stderr
index 4069b35a998..7d420126199 100644
--- a/tests/ui/resolve/issue-55673.stderr
+++ b/tests/ui/resolve/issue-55673.stderr
@@ -15,7 +15,7 @@ error[E0220]: associated type `Baa` not found for `T`
 LL |     T::Baa: std::fmt::Debug,
    |        ^^^ there is a similarly named associated type `Bar` in the trait `Foo`
    |
-help: consider further restricting type parameter `T`
+help: consider further restricting type parameter `T` with trait `Foo`
    |
 LL |     T::Baa: std::fmt::Debug, T: Foo
    |                            ~~~~~~~~
diff --git a/tests/ui/rust-2024/gen-kw.e2015.stderr b/tests/ui/rust-2024/gen-kw.e2015.stderr
index ff552f663c7..5c42d65abf0 100644
--- a/tests/ui/rust-2024/gen-kw.e2015.stderr
+++ b/tests/ui/rust-2024/gen-kw.e2015.stderr
@@ -34,11 +34,47 @@ LL |     () => { mod test { fn gen() {} } }
 error: `gen` is a keyword in the 2024 edition
   --> $DIR/gen-kw.rs:25:9
    |
-LL | fn test<'gen>() {}
+LL | fn test<'gen>(_: &'gen i32) {}
    |         ^^^^ help: you can use a raw identifier to stay compatible: `'r#gen`
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
-error: aborting due to 4 previous errors
+error: `gen` is a keyword in the 2024 edition
+  --> $DIR/gen-kw.rs:25:19
+   |
+LL | fn test<'gen>(_: &'gen i32) {}
+   |                   ^^^^ help: you can use a raw identifier to stay compatible: `'r#gen`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
+   = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: `gen` is a keyword in the 2024 edition
+  --> $DIR/gen-kw.rs:33:13
+   |
+LL | struct Test<'gen>(Box<Test<'gen>>, &'gen ());
+   |             ^^^^ help: you can use a raw identifier to stay compatible: `'r#gen`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
+   = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: `gen` is a keyword in the 2024 edition
+  --> $DIR/gen-kw.rs:33:28
+   |
+LL | struct Test<'gen>(Box<Test<'gen>>, &'gen ());
+   |                            ^^^^ help: you can use a raw identifier to stay compatible: `'r#gen`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
+   = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: `gen` is a keyword in the 2024 edition
+  --> $DIR/gen-kw.rs:33:37
+   |
+LL | struct Test<'gen>(Box<Test<'gen>>, &'gen ());
+   |                                     ^^^^ help: you can use a raw identifier to stay compatible: `'r#gen`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
+   = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: aborting due to 8 previous errors
 
diff --git a/tests/ui/rust-2024/gen-kw.e2018.stderr b/tests/ui/rust-2024/gen-kw.e2018.stderr
index efa812069c3..050e58c119b 100644
--- a/tests/ui/rust-2024/gen-kw.e2018.stderr
+++ b/tests/ui/rust-2024/gen-kw.e2018.stderr
@@ -34,11 +34,47 @@ LL |     () => { mod test { fn gen() {} } }
 error: `gen` is a keyword in the 2024 edition
   --> $DIR/gen-kw.rs:25:9
    |
-LL | fn test<'gen>() {}
+LL | fn test<'gen>(_: &'gen i32) {}
    |         ^^^^ help: you can use a raw identifier to stay compatible: `'r#gen`
    |
    = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024!
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
-error: aborting due to 4 previous errors
+error: `gen` is a keyword in the 2024 edition
+  --> $DIR/gen-kw.rs:25:19
+   |
+LL | fn test<'gen>(_: &'gen i32) {}
+   |                   ^^^^ help: you can use a raw identifier to stay compatible: `'r#gen`
+   |
+   = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024!
+   = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: `gen` is a keyword in the 2024 edition
+  --> $DIR/gen-kw.rs:33:13
+   |
+LL | struct Test<'gen>(Box<Test<'gen>>, &'gen ());
+   |             ^^^^ help: you can use a raw identifier to stay compatible: `'r#gen`
+   |
+   = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024!
+   = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: `gen` is a keyword in the 2024 edition
+  --> $DIR/gen-kw.rs:33:28
+   |
+LL | struct Test<'gen>(Box<Test<'gen>>, &'gen ());
+   |                            ^^^^ help: you can use a raw identifier to stay compatible: `'r#gen`
+   |
+   = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024!
+   = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: `gen` is a keyword in the 2024 edition
+  --> $DIR/gen-kw.rs:33:37
+   |
+LL | struct Test<'gen>(Box<Test<'gen>>, &'gen ());
+   |                                     ^^^^ help: you can use a raw identifier to stay compatible: `'r#gen`
+   |
+   = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024!
+   = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: aborting due to 8 previous errors
 
diff --git a/tests/ui/rust-2024/gen-kw.rs b/tests/ui/rust-2024/gen-kw.rs
index 5a658470c0a..3c075a4c022 100644
--- a/tests/ui/rust-2024/gen-kw.rs
+++ b/tests/ui/rust-2024/gen-kw.rs
@@ -22,9 +22,23 @@ macro_rules! t {
     //[e2018]~| WARNING this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024!
 }
 
-fn test<'gen>() {}
+fn test<'gen>(_: &'gen i32) {}
 //~^ ERROR `gen` is a keyword in the 2024 edition
+//~| ERROR `gen` is a keyword in the 2024 edition
 //[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
+//[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
+//[e2018]~| WARNING this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024!
+//[e2018]~| WARNING this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024!
+
+struct Test<'gen>(Box<Test<'gen>>, &'gen ());
+//~^ ERROR `gen` is a keyword in the 2024 edition
+//~| ERROR `gen` is a keyword in the 2024 edition
+//~| ERROR `gen` is a keyword in the 2024 edition
+//[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
+//[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
+//[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
+//[e2018]~| WARNING this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024!
+//[e2018]~| WARNING this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024!
 //[e2018]~| WARNING this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024!
 
 t!();
diff --git a/tests/ui/specialization/default-generic-associated-type-bound.stderr b/tests/ui/specialization/default-generic-associated-type-bound.stderr
index afdbe2eb226..57d67ac526a 100644
--- a/tests/ui/specialization/default-generic-associated-type-bound.stderr
+++ b/tests/ui/specialization/default-generic-associated-type-bound.stderr
@@ -20,7 +20,7 @@ note: required by a bound in `X::U`
    |
 LL |     type U<'a>: PartialEq<&'a Self> where Self: 'a;
    |                 ^^^^^^^^^^^^^^^^^^^ required by this bound in `X::U`
-help: consider further restricting this bound
+help: consider further restricting type parameter `T` with trait `PartialEq`
    |
 LL | impl<T: 'static + std::cmp::PartialEq> X for T {
    |                 +++++++++++++++++++++
diff --git a/tests/ui/specialization/defaultimpl/specialization-wfcheck.stderr b/tests/ui/specialization/defaultimpl/specialization-wfcheck.stderr
index 01188e293bd..4a51a7dfa47 100644
--- a/tests/ui/specialization/defaultimpl/specialization-wfcheck.stderr
+++ b/tests/ui/specialization/defaultimpl/specialization-wfcheck.stderr
@@ -19,7 +19,7 @@ note: required by a bound in `Foo`
    |
 LL | trait Foo<'a, T: Eq + 'a> { }
    |                  ^^ required by this bound in `Foo`
-help: consider restricting type parameter `U`
+help: consider restricting type parameter `U` with trait `Eq`
    |
 LL | default impl<U: std::cmp::Eq> Foo<'static, U> for () {}
    |               ++++++++++++++
diff --git a/tests/ui/specialization/issue-33017.stderr b/tests/ui/specialization/issue-33017.stderr
index 2c20077078f..29a82a4d875 100644
--- a/tests/ui/specialization/issue-33017.stderr
+++ b/tests/ui/specialization/issue-33017.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `UncheckedCopy::Output`
    |
 LL |     type Output: From<Self> + Copy + Into<Self>;
    |                               ^^^^ required by this bound in `UncheckedCopy::Output`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | impl<T: std::marker::Copy> UncheckedCopy for T {
    |       +++++++++++++++++++
diff --git a/tests/ui/specialization/min_specialization/issue-79224.stderr b/tests/ui/specialization/min_specialization/issue-79224.stderr
index 268fc3a9591..84e526f4597 100644
--- a/tests/ui/specialization/min_specialization/issue-79224.stderr
+++ b/tests/ui/specialization/min_specialization/issue-79224.stderr
@@ -5,7 +5,7 @@ LL | impl<B: ?Sized> Display for Cow<'_, B> {
    |                             ^^^^^^^^^^ the trait `Clone` is not implemented for `B`
    |
    = note: required for `B` to implement `ToOwned`
-help: consider further restricting this bound
+help: consider further restricting type parameter `B` with trait `Clone`
    |
 LL | impl<B: ?Sized + std::clone::Clone> Display for Cow<'_, B> {
    |                +++++++++++++++++++
@@ -17,7 +17,7 @@ LL |     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `B`
    |
    = note: required for `B` to implement `ToOwned`
-help: consider further restricting this bound
+help: consider further restricting type parameter `B` with trait `Clone`
    |
 LL | impl<B: ?Sized + std::clone::Clone> Display for Cow<'_, B> {
    |                +++++++++++++++++++
@@ -29,7 +29,7 @@ LL |     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    |             ^^^^ the trait `Clone` is not implemented for `B`
    |
    = note: required for `B` to implement `ToOwned`
-help: consider further restricting this bound
+help: consider further restricting type parameter `B` with trait `Clone`
    |
 LL | impl<B: ?Sized + std::clone::Clone> Display for Cow<'_, B> {
    |                +++++++++++++++++++
@@ -47,7 +47,7 @@ LL | |     }
    | |_____^ the trait `Clone` is not implemented for `B`
    |
    = note: required for `B` to implement `ToOwned`
-help: consider further restricting this bound
+help: consider further restricting type parameter `B` with trait `Clone`
    |
 LL | impl<B: ?Sized + std::clone::Clone> Display for Cow<'_, B> {
    |                +++++++++++++++++++
diff --git a/tests/ui/stdlib-unit-tests/atomic-from-mut-not-available.alignment_matches.stderr b/tests/ui/stdlib-unit-tests/atomic-from-mut-not-available.alignment_matches.stderr
new file mode 100644
index 00000000000..109985c0052
--- /dev/null
+++ b/tests/ui/stdlib-unit-tests/atomic-from-mut-not-available.alignment_matches.stderr
@@ -0,0 +1,13 @@
+error[E0658]: use of unstable library feature `atomic_from_mut`
+  --> $DIR/atomic-from-mut-not-available.rs:24:5
+   |
+LL |     core::sync::atomic::AtomicU64::from_mut(&mut 0u64);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #76314 <https://github.com/rust-lang/rust/issues/76314> for more information
+   = help: add `#![feature(atomic_from_mut)]` 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/atomic-from-mut-not-available.stderr b/tests/ui/stdlib-unit-tests/atomic-from-mut-not-available.alignment_mismatch.stderr
index a4514524f48..47b17f9fcd7 100644
--- a/tests/ui/atomic-from-mut-not-available.stderr
+++ b/tests/ui/stdlib-unit-tests/atomic-from-mut-not-available.alignment_mismatch.stderr
@@ -1,5 +1,5 @@
 error[E0599]: no function or associated item named `from_mut` found for struct `AtomicU64` in the current scope
-  --> $DIR/atomic-from-mut-not-available.rs:5:36
+  --> $DIR/atomic-from-mut-not-available.rs:24:36
    |
 LL |     core::sync::atomic::AtomicU64::from_mut(&mut 0u64);
    |                                    ^^^^^^^^ function or associated item not found in `AtomicU64`
diff --git a/tests/ui/stdlib-unit-tests/atomic-from-mut-not-available.rs b/tests/ui/stdlib-unit-tests/atomic-from-mut-not-available.rs
new file mode 100644
index 00000000000..7e9de3570eb
--- /dev/null
+++ b/tests/ui/stdlib-unit-tests/atomic-from-mut-not-available.rs
@@ -0,0 +1,27 @@
+//! This test exercises the combined effect of the `cfg(target_has_atomic_equal_alignment = "...")`
+//! implementation in the compiler plus usage of said `cfg(target_has_atomic_equal_alignment)` in
+//! `core` for the `Atomic64::from_mut` API.
+//!
+//! This test is a basic smoke test: that `AtomicU64::from_mut` is gated by
+//! `#[cfg(target_has_atomic_equal_alignment = "8")]`, which is only available on platforms where
+//! `AtomicU64` has the same alignment as `u64`. This is notably *not* satisfied by `x86_32`, where
+//! they have differing alignments. Thus, `AtomicU64::from_mut` should *not* be available on
+//! `x86_32` linux and should report assoc item not found, if the `cfg` is working correctly.
+//! Conversely, `AtomicU64::from_mut` *should* be available on `x86_64` linux where the alignment
+//! matches.
+
+//@ revisions: alignment_mismatch alignment_matches
+
+// This should fail on 32-bit x86 linux...
+//@[alignment_mismatch] only-x86
+//@[alignment_mismatch] only-linux
+
+// ... but pass on 64-bit x86_64 linux.
+//@[alignment_matches] only-x86_64
+//@[alignment_matches] only-linux
+
+fn main() {
+    core::sync::atomic::AtomicU64::from_mut(&mut 0u64);
+    //[alignment_mismatch]~^ ERROR no function or associated item named `from_mut` found for struct `AtomicU64`
+    //[alignment_matches]~^^ ERROR use of unstable library feature `atomic_from_mut`
+}
diff --git a/tests/ui/suggestions/assoc-const-as-fn.stderr b/tests/ui/suggestions/assoc-const-as-fn.stderr
index 69e9af72647..6732033e774 100644
--- a/tests/ui/suggestions/assoc-const-as-fn.stderr
+++ b/tests/ui/suggestions/assoc-const-as-fn.stderr
@@ -4,7 +4,7 @@ error[E0277]: the trait bound `T: GlUniformScalar` is not satisfied
 LL |     <T as GlUniformScalar>::FACTORY(1, value);
    |      ^ the trait `GlUniformScalar` is not implemented for `T`
    |
-help: consider further restricting this bound
+help: consider further restricting type parameter `T` with trait `GlUniformScalar`
    |
 LL | pub fn foo<T: UniformScalar + GlUniformScalar>(value: T) {
    |                             +++++++++++++++++
diff --git a/tests/ui/suggestions/bound-suggestions.stderr b/tests/ui/suggestions/bound-suggestions.stderr
index 4965e7439f8..e30deb11398 100644
--- a/tests/ui/suggestions/bound-suggestions.stderr
+++ b/tests/ui/suggestions/bound-suggestions.stderr
@@ -5,7 +5,7 @@ LL |     println!("{:?}", t);
    |                      ^ `impl Sized` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider further restricting this bound
+help: consider restricting opaque type `impl Sized` with trait `Debug`
    |
 LL | fn test_impl(t: impl Sized + std::fmt::Debug) {
    |                            +++++++++++++++++
@@ -17,7 +17,7 @@ LL |     println!("{:?}", t);
    |                      ^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Debug`
    |
 LL | fn test_no_bounds<T: std::fmt::Debug>(t: T) {
    |                    +++++++++++++++++
@@ -29,7 +29,7 @@ LL |     println!("{:?}", t);
    |                      ^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider further restricting this bound
+help: consider further restricting type parameter `T` with trait `Debug`
    |
 LL | fn test_one_bound<T: Sized + std::fmt::Debug>(t: T) {
    |                            +++++++++++++++++
@@ -41,7 +41,7 @@ LL |     println!("{:?} {:?}", x, y);
    |                              ^ `Y` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider further restricting type parameter `Y`
+help: consider further restricting type parameter `Y` with trait `Debug`
    |
 LL | fn test_no_bounds_where<X, Y>(x: X, y: Y) where X: std::fmt::Debug, Y: std::fmt::Debug {
    |                                                                   ~~~~~~~~~~~~~~~~~~~~
@@ -53,7 +53,7 @@ LL |     println!("{:?}", x);
    |                      ^ `X` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider further restricting this bound
+help: consider further restricting type parameter `X` with trait `Debug`
    |
 LL | fn test_one_bound_where<X>(x: X) where X: Sized + std::fmt::Debug {
    |                                                 +++++++++++++++++
@@ -65,7 +65,7 @@ LL |     println!("{:?}", x);
    |                      ^ `X` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider further restricting this bound
+help: consider further restricting type parameter `X` with trait `Debug`
    |
 LL | fn test_many_bounds_where<X>(x: X) where X: Sized + std::fmt::Debug, X: Sized {
    |                                                   +++++++++++++++++
diff --git a/tests/ui/suggestions/clone-bounds-121524.rs b/tests/ui/suggestions/clone-bounds-121524.rs
index 8cd60b452de..b7760584ebb 100644
--- a/tests/ui/suggestions/clone-bounds-121524.rs
+++ b/tests/ui/suggestions/clone-bounds-121524.rs
@@ -6,7 +6,7 @@ trait DoesAThing {}
 impl DoesAThing for ThingThatDoesAThing {}
 
 fn clones_impl_ref_inline(thing: &impl DoesAThing) {
-    //~^ HELP consider further restricting this bound
+    //~^ HELP consider restricting opaque type `impl DoesAThing` with trait `Clone`
     drops_impl_owned(thing.clone()); //~ ERROR E0277
     //~^ NOTE copies the reference
     //~| NOTE the trait `DoesAThing` is not implemented for `&impl DoesAThing`
diff --git a/tests/ui/suggestions/clone-bounds-121524.stderr b/tests/ui/suggestions/clone-bounds-121524.stderr
index 6d60508a4a1..bdba8d7e472 100644
--- a/tests/ui/suggestions/clone-bounds-121524.stderr
+++ b/tests/ui/suggestions/clone-bounds-121524.stderr
@@ -9,7 +9,7 @@ note: this `clone()` copies the reference, which does not do anything, because `
    |
 LL |     drops_impl_owned(thing.clone());
    |                            ^^^^^
-help: consider further restricting this bound
+help: consider restricting opaque type `impl DoesAThing` with trait `Clone`
    |
 LL | fn clones_impl_ref_inline(thing: &impl DoesAThing + Clone) {
    |                                                   +++++++
diff --git a/tests/ui/suggestions/clone-on-unconstrained-borrowed-type-param.stderr b/tests/ui/suggestions/clone-on-unconstrained-borrowed-type-param.stderr
index afbb9c32d51..03a14b03781 100644
--- a/tests/ui/suggestions/clone-on-unconstrained-borrowed-type-param.stderr
+++ b/tests/ui/suggestions/clone-on-unconstrained-borrowed-type-param.stderr
@@ -15,7 +15,7 @@ note: `T` does not implement `Clone`, so `&T` was cloned instead
    |
 LL |     t.clone()
    |     ^
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Clone`
    |
 LL | fn wat<T: Clone>(t: &T) -> T {
    |         +++++++
diff --git a/tests/ui/suggestions/derive-clone-for-eq.stderr b/tests/ui/suggestions/derive-clone-for-eq.stderr
index 680890e880c..eae0b0ae817 100644
--- a/tests/ui/suggestions/derive-clone-for-eq.stderr
+++ b/tests/ui/suggestions/derive-clone-for-eq.stderr
@@ -14,7 +14,7 @@ LL | impl<T: Clone, U> PartialEq<U> for Struct<T>
 note: required by a bound in `Eq`
   --> $SRC_DIR/core/src/cmp.rs:LL:COL
    = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Clone`
    |
 LL | pub struct Struct<T: std::clone::Clone>(T);
    |                    +++++++++++++++++++
diff --git a/tests/ui/suggestions/derive-macro-missing-bounds.stderr b/tests/ui/suggestions/derive-macro-missing-bounds.stderr
index bffcb1af487..37a5f4932ff 100644
--- a/tests/ui/suggestions/derive-macro-missing-bounds.stderr
+++ b/tests/ui/suggestions/derive-macro-missing-bounds.stderr
@@ -38,7 +38,7 @@ LL |     impl<T: Debug + Trait> Debug for Inner<T> {
    = note: required for `&c::Inner<T>` to implement `Debug`
    = note: required for the cast from `&&c::Inner<T>` to `&dyn Debug`
    = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Trait`
    |
 LL |     struct Outer<T: c::Trait>(Inner<T>);
    |                   ++++++++++
@@ -60,7 +60,7 @@ LL |     impl<T> Debug for Inner<T> where T: Debug, T: Trait {
    = note: required for `&d::Inner<T>` to implement `Debug`
    = note: required for the cast from `&&d::Inner<T>` to `&dyn Debug`
    = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Trait`
    |
 LL |     struct Outer<T: d::Trait>(Inner<T>);
    |                   ++++++++++
@@ -82,7 +82,7 @@ LL |     impl<T> Debug for Inner<T> where T: Debug + Trait {
    = note: required for `&e::Inner<T>` to implement `Debug`
    = note: required for the cast from `&&e::Inner<T>` to `&dyn Debug`
    = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Trait`
    |
 LL |     struct Outer<T: e::Trait>(Inner<T>);
    |                   ++++++++++
@@ -104,7 +104,7 @@ LL |     impl<T: Debug> Debug for Inner<T> where T: Trait {
    = note: required for `&f::Inner<T>` to implement `Debug`
    = note: required for the cast from `&&f::Inner<T>` to `&dyn Debug`
    = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Trait`
    |
 LL |     struct Outer<T: f::Trait>(Inner<T>);
    |                   ++++++++++
diff --git a/tests/ui/suggestions/issue-106443-sugg-clone-for-bound.stderr b/tests/ui/suggestions/issue-106443-sugg-clone-for-bound.stderr
index 8607917ede6..8b1c0b9a77a 100644
--- a/tests/ui/suggestions/issue-106443-sugg-clone-for-bound.stderr
+++ b/tests/ui/suggestions/issue-106443-sugg-clone-for-bound.stderr
@@ -4,7 +4,7 @@ error[E0277]: the trait bound `&T: X` is not satisfied
 LL |     foo(s);
    |         ^ the trait `X` is not implemented for `&T`
    |
-help: consider further restricting this bound
+help: consider further restricting type parameter `T` with trait `Clone`
    |
 LL | fn bar<T: X + Clone>(s: &T) {
    |             +++++++
diff --git a/tests/ui/suggestions/issue-97677.stderr b/tests/ui/suggestions/issue-97677.stderr
index 0e95167d851..7fe091ef71c 100644
--- a/tests/ui/suggestions/issue-97677.stderr
+++ b/tests/ui/suggestions/issue-97677.stderr
@@ -6,7 +6,7 @@ LL |     n + 10
    |     |
    |     N
    |
-help: consider restricting type parameter `N`
+help: consider restricting type parameter `N` with trait `Add`
    |
 LL | fn add_ten<N: std::ops::Add<i32, Output = N>>(n: N) -> N {
    |             ++++++++++++++++++++++++++++++++
diff --git a/tests/ui/suggestions/missing-bound-in-derive-copy-impl-2.stderr b/tests/ui/suggestions/missing-bound-in-derive-copy-impl-2.stderr
index d65ad109241..4408fe0a0a4 100644
--- a/tests/ui/suggestions/missing-bound-in-derive-copy-impl-2.stderr
+++ b/tests/ui/suggestions/missing-bound-in-derive-copy-impl-2.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `Vector2`
    |
 LL | pub struct Vector2<T: Debug + Copy + Clone> {
    |                               ^^^^ required by this bound in `Vector2`
-help: consider further restricting this bound
+help: consider further restricting type parameter `K` with trait `Copy`
    |
 LL | pub struct AABB<K: Debug + std::marker::Copy> {
    |                          +++++++++++++++++++
@@ -32,7 +32,7 @@ LL | pub struct Vector2<T: Debug + Copy + Clone> {
    |                               ---- unsatisfied trait bound introduced in this `derive` macro
    = note: required for the cast from `&Vector2<K>` to `&dyn Debug`
    = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider further restricting this bound
+help: consider further restricting type parameter `K` with trait `Copy`
    |
 LL | pub struct AABB<K: Debug + std::marker::Copy> {
    |                          +++++++++++++++++++
@@ -52,7 +52,7 @@ note: required by a bound in `Vector2`
 LL | pub struct Vector2<T: Debug + Copy + Clone> {
    |                               ^^^^ required by this bound in `Vector2`
    = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider further restricting this bound
+help: consider further restricting type parameter `K` with trait `Copy`
    |
 LL | pub struct AABB<K: Debug + std::marker::Copy> {
    |                          +++++++++++++++++++
@@ -74,7 +74,7 @@ LL | #[derive(Debug, Copy, Clone)]
 LL | pub struct Vector2<T: Debug + Copy + Clone> {
    |                               ---- unsatisfied trait bound introduced in this `derive` macro
    = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider further restricting this bound
+help: consider further restricting type parameter `K` with trait `Copy`
    |
 LL | pub struct AABB<K: Debug + std::marker::Copy> {
    |                          +++++++++++++++++++
diff --git a/tests/ui/suggestions/missing-bound-in-derive-copy-impl-3.stderr b/tests/ui/suggestions/missing-bound-in-derive-copy-impl-3.stderr
index 2ade0e974e4..1bbf6f66ab2 100644
--- a/tests/ui/suggestions/missing-bound-in-derive-copy-impl-3.stderr
+++ b/tests/ui/suggestions/missing-bound-in-derive-copy-impl-3.stderr
@@ -13,7 +13,7 @@ note: the `Copy` impl for `Vector2<K>` requires that `K: Debug`
 LL |     pub loc: Vector2<K>,
    |              ^^^^^^^^^^
    = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider further restricting this bound
+help: consider further restricting type parameter `K` with trait `Debug`
    |
 LL | pub struct AABB<K: Copy + Debug>{
    |                         +++++++
@@ -29,7 +29,7 @@ note: required by a bound in `Vector2`
    |
 LL | pub struct Vector2<T: Debug + Copy + Clone>{
    |                       ^^^^^ required by this bound in `Vector2`
-help: consider further restricting this bound
+help: consider further restricting type parameter `K` with trait `Debug`
    |
 LL | pub struct AABB<K: Copy + std::fmt::Debug>{
    |                         +++++++++++++++++
@@ -44,7 +44,7 @@ LL |     pub loc: Vector2<K>,
    |     ^^^^^^^^^^^^^^^^^^^ `K` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
    = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider further restricting this bound
+help: consider further restricting type parameter `K` with trait `Debug`
    |
 LL | pub struct AABB<K: Copy + std::fmt::Debug>{
    |                         +++++++++++++++++
@@ -59,7 +59,7 @@ LL |     pub size: Vector2<K>
    |     ^^^^^^^^^^^^^^^^^^^^ `K` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
    = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider further restricting this bound
+help: consider further restricting type parameter `K` with trait `Debug`
    |
 LL | pub struct AABB<K: Copy + std::fmt::Debug>{
    |                         +++++++++++++++++
diff --git a/tests/ui/suggestions/missing-bound-in-derive-copy-impl.stderr b/tests/ui/suggestions/missing-bound-in-derive-copy-impl.stderr
index 316c2fa0fc9..8b5cced4c4a 100644
--- a/tests/ui/suggestions/missing-bound-in-derive-copy-impl.stderr
+++ b/tests/ui/suggestions/missing-bound-in-derive-copy-impl.stderr
@@ -13,7 +13,7 @@ note: the `Copy` impl for `Vector2<K>` requires that `K: Debug`
 LL |     pub loc: Vector2<K>,
    |              ^^^^^^^^^^
    = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider restricting type parameter `K`
+help: consider restricting type parameter `K` with trait `Debug`
    |
 LL | pub struct AABB<K: Debug> {
    |                  +++++++
@@ -29,7 +29,7 @@ note: required by a bound in `Vector2`
    |
 LL | pub struct Vector2<T: Debug + Copy + Clone> {
    |                       ^^^^^ required by this bound in `Vector2`
-help: consider restricting type parameter `K`
+help: consider restricting type parameter `K` with trait `Debug`
    |
 LL | pub struct AABB<K: std::fmt::Debug> {
    |                  +++++++++++++++++
@@ -45,7 +45,7 @@ note: required by a bound in `Vector2`
    |
 LL | pub struct Vector2<T: Debug + Copy + Clone> {
    |                               ^^^^ required by this bound in `Vector2`
-help: consider restricting type parameter `K`
+help: consider restricting type parameter `K` with trait `Copy`
    |
 LL | pub struct AABB<K: std::marker::Copy> {
    |                  +++++++++++++++++++
@@ -68,7 +68,7 @@ LL | pub struct Vector2<T: Debug + Copy + Clone> {
    |                               ---- unsatisfied trait bound introduced in this `derive` macro
    = note: required for the cast from `&Vector2<K>` to `&dyn Debug`
    = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider restricting type parameter `K`
+help: consider restricting type parameter `K` with trait `Copy`
    |
 LL | pub struct AABB<K: std::marker::Copy> {
    |                  +++++++++++++++++++
@@ -83,7 +83,7 @@ LL |     pub loc: Vector2<K>,
    |     ^^^^^^^^^^^^^^^^^^^ `K` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
    = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider restricting type parameter `K`
+help: consider restricting type parameter `K` with trait `Debug`
    |
 LL | pub struct AABB<K: std::fmt::Debug> {
    |                  +++++++++++++++++
@@ -103,7 +103,7 @@ note: required by a bound in `Vector2`
 LL | pub struct Vector2<T: Debug + Copy + Clone> {
    |                               ^^^^ required by this bound in `Vector2`
    = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider restricting type parameter `K`
+help: consider restricting type parameter `K` with trait `Copy`
    |
 LL | pub struct AABB<K: std::marker::Copy> {
    |                  +++++++++++++++++++
@@ -118,7 +118,7 @@ LL |     pub size: Vector2<K>,
    |     ^^^^^^^^^^^^^^^^^^^^ `K` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
    = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider restricting type parameter `K`
+help: consider restricting type parameter `K` with trait `Debug`
    |
 LL | pub struct AABB<K: std::fmt::Debug> {
    |                  +++++++++++++++++
@@ -140,7 +140,7 @@ LL | #[derive(Debug, Copy, Clone)]
 LL | pub struct Vector2<T: Debug + Copy + Clone> {
    |                               ---- unsatisfied trait bound introduced in this `derive` macro
    = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider restricting type parameter `K`
+help: consider restricting type parameter `K` with trait `Copy`
    |
 LL | pub struct AABB<K: std::marker::Copy> {
    |                  +++++++++++++++++++
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 23a75154f20..600e5ae63d3 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
@@ -12,7 +12,7 @@ note: the `Copy` impl for `OnlyCopyIfDisplay<S>` requires that `S: std::fmt::Dis
    |
 LL | struct Wrapper<T>(T);
    |                   ^
-help: consider restricting type parameter `S`
+help: consider restricting type parameter `S` with trait `Display`
    |
 LL | impl<S: std::fmt::Display> Copy for Wrapper<OnlyCopyIfDisplay<S>> {}
    |       +++++++++++++++++++
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 c9f277fb350..b22aa35ef6d 100644
--- a/tests/ui/suggestions/missing-bound-in-manual-copy-impl.stderr
+++ b/tests/ui/suggestions/missing-bound-in-manual-copy-impl.stderr
@@ -7,7 +7,7 @@ LL |
 LL | impl<S> Copy for Wrapper<S> {}
    |                  ^^^^^^^^^^
    |
-help: consider restricting type parameter `S`
+help: consider restricting type parameter `S` with trait `Copy`
    |
 LL | impl<S: Copy> Copy for Wrapper<S> {}
    |       ++++++
diff --git a/tests/ui/suggestions/restrict-type-argument.stderr b/tests/ui/suggestions/restrict-type-argument.stderr
index 01c2de79864..4b6da8a9cd9 100644
--- a/tests/ui/suggestions/restrict-type-argument.stderr
+++ b/tests/ui/suggestions/restrict-type-argument.stderr
@@ -11,7 +11,7 @@ note: required by a bound in `is_send`
    |
 LL | fn is_send<T: Send>(val: T) {}
    |               ^^^^ required by this bound in `is_send`
-help: consider further restricting this bound
+help: consider restricting opaque type `impl Sync` with trait `Send`
    |
 LL | fn use_impl_sync(val: impl Sync + std::marker::Send) {
    |                                 +++++++++++++++++++
@@ -29,7 +29,7 @@ note: required by a bound in `is_send`
    |
 LL | fn is_send<T: Send>(val: T) {}
    |               ^^^^ required by this bound in `is_send`
-help: consider further restricting this bound
+help: consider further restricting type parameter `S` with trait `Send`
    |
 LL | fn use_where<S>(val: S) where S: Sync + std::marker::Send {
    |                                       +++++++++++++++++++
@@ -47,7 +47,7 @@ note: required by a bound in `is_send`
    |
 LL | fn is_send<T: Send>(val: T) {}
    |               ^^^^ required by this bound in `is_send`
-help: consider further restricting this bound
+help: consider further restricting type parameter `S` with trait `Send`
    |
 LL | fn use_bound<S: Sync + std::marker::Send>(val: S) {
    |                      +++++++++++++++++++
@@ -65,7 +65,7 @@ note: required by a bound in `is_send`
    |
 LL | fn is_send<T: Send>(val: T) {}
    |               ^^^^ required by this bound in `is_send`
-help: consider further restricting this bound
+help: consider further restricting type parameter `S` with trait `Send`
    |
 LL |     Sync + std::marker::Send
    |          +++++++++++++++++++
@@ -83,7 +83,7 @@ note: required by a bound in `is_send`
    |
 LL | fn is_send<T: Send>(val: T) {}
    |               ^^^^ required by this bound in `is_send`
-help: consider further restricting this bound
+help: consider further restricting type parameter `S` with trait `Send`
    |
 LL | fn use_bound_and_where<S: Sync + std::marker::Send>(val: S) where S: std::fmt::Debug {
    |                                +++++++++++++++++++
@@ -101,7 +101,7 @@ note: required by a bound in `is_send`
    |
 LL | fn is_send<T: Send>(val: T) {}
    |               ^^^^ required by this bound in `is_send`
-help: consider restricting type parameter `S`
+help: consider restricting type parameter `S` with trait `Send`
    |
 LL | fn use_unbound<S: std::marker::Send>(val: S) {
    |                 +++++++++++++++++++
diff --git a/tests/ui/suggestions/trait-impl-bound-suggestions.stderr b/tests/ui/suggestions/trait-impl-bound-suggestions.stderr
index 6a75cbdf639..346d19f1b77 100644
--- a/tests/ui/suggestions/trait-impl-bound-suggestions.stderr
+++ b/tests/ui/suggestions/trait-impl-bound-suggestions.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `ConstrainedStruct`
    |
 LL | struct ConstrainedStruct<X: Copy> {
    |                             ^^^^ required by this bound in `ConstrainedStruct`
-help: consider further restricting type parameter `X`
+help: consider further restricting type parameter `X` with trait `Copy`
    |
 LL | trait InsufficientlyConstrainedGeneric<X=()> where Self: Sized, X: std::marker::Copy {
    |                                                               ++++++++++++++++++++++
@@ -25,7 +25,7 @@ note: required by a bound in `ConstrainedStruct`
    |
 LL | struct ConstrainedStruct<X: Copy> {
    |                             ^^^^ required by this bound in `ConstrainedStruct`
-help: consider further restricting type parameter `X`
+help: consider further restricting type parameter `X` with trait `Copy`
    |
 LL | trait InsufficientlyConstrainedGenericWithEmptyWhere<X=()> where Self: Sized, X: std::marker::Copy {
    |                                                                             ++++++++++++++++++++++
@@ -41,7 +41,7 @@ note: required by a bound in `ConstrainedStruct`
    |
 LL | struct ConstrainedStruct<X: Copy> {
    |                             ^^^^ required by this bound in `ConstrainedStruct`
-help: consider further restricting type parameter `X`
+help: consider further restricting type parameter `X` with trait `Copy`
    |
 LL | trait InsufficientlyConstrainedGeneric<X=()> where Self: Sized, X: std::marker::Copy {
    |                                                               ++++++++++++++++++++++
@@ -57,7 +57,7 @@ note: required by a bound in `ConstrainedStruct`
    |
 LL | struct ConstrainedStruct<X: Copy> {
    |                             ^^^^ required by this bound in `ConstrainedStruct`
-help: consider further restricting type parameter `X`
+help: consider further restricting type parameter `X` with trait `Copy`
    |
 LL | trait InsufficientlyConstrainedGenericWithEmptyWhere<X=()> where Self: Sized, X: std::marker::Copy {
    |                                                                             ++++++++++++++++++++++
diff --git a/tests/ui/trait-bounds/unstable-trait-suggestion.rs b/tests/ui/trait-bounds/unstable-trait-suggestion.rs
new file mode 100644
index 00000000000..ba96b4f3f97
--- /dev/null
+++ b/tests/ui/trait-bounds/unstable-trait-suggestion.rs
@@ -0,0 +1,19 @@
+#![feature(staged_api)]
+#![allow(internal_features)]
+#![stable(feature = "unit_test", since = "1.0.0")]
+
+#[unstable(feature = "step_trait", issue = "42168")]
+pub trait Unstable {}
+
+#[stable(feature = "unit_test", since = "1.0.0")]
+fn foo<T: Unstable>(_: T) {}
+
+#[stable(feature = "unit_test", since = "1.0.0")]
+pub fn bar<T>(t: T) { //~ HELP consider restricting type parameter `T` with unstable trait `Unstable`
+    foo(t) //~ ERROR E0277
+}
+#[stable(feature = "unit_test", since = "1.0.0")]
+pub fn baz<T>(t: std::ops::Range<T>) { //~ HELP consider restricting type parameter `T` with unstable trait
+    for _ in t {} //~ ERROR E0277
+}
+fn main() {}
diff --git a/tests/ui/trait-bounds/unstable-trait-suggestion.stderr b/tests/ui/trait-bounds/unstable-trait-suggestion.stderr
new file mode 100644
index 00000000000..dfa47f2ab46
--- /dev/null
+++ b/tests/ui/trait-bounds/unstable-trait-suggestion.stderr
@@ -0,0 +1,34 @@
+error[E0277]: the trait bound `T: Unstable` is not satisfied
+  --> $DIR/unstable-trait-suggestion.rs:13:9
+   |
+LL |     foo(t)
+   |     --- ^ the trait `Unstable` is not implemented for `T`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `foo`
+  --> $DIR/unstable-trait-suggestion.rs:9:11
+   |
+LL | fn foo<T: Unstable>(_: T) {}
+   |           ^^^^^^^^ required by this bound in `foo`
+help: consider restricting type parameter `T` with unstable trait `Unstable`
+   |
+LL | pub fn bar<T: Unstable>(t: T) {
+   |             ++++++++++
+
+error[E0277]: the trait bound `T: Step` is not satisfied
+  --> $DIR/unstable-trait-suggestion.rs:17:14
+   |
+LL |     for _ in t {}
+   |              ^ the trait `Step` is not implemented for `T`
+   |
+   = note: required for `std::ops::Range<T>` to implement `Iterator`
+   = note: required for `std::ops::Range<T>` to implement `IntoIterator`
+help: consider restricting type parameter `T` with unstable trait `Step`
+   |
+LL | pub fn baz<T: std::iter::Step>(t: std::ops::Range<T>) {
+   |             +++++++++++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/alias/wf.stderr b/tests/ui/traits/alias/wf.stderr
index 3be6e8a49d6..42b0104e865 100644
--- a/tests/ui/traits/alias/wf.stderr
+++ b/tests/ui/traits/alias/wf.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `A`
    |
 LL | trait A<T: Foo> {}
    |            ^^^ required by this bound in `A`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Foo`
    |
 LL | trait B<T: Foo> = A<T>;
    |          +++++
diff --git a/tests/ui/traits/bad-method-typaram-kind.stderr b/tests/ui/traits/bad-method-typaram-kind.stderr
index 376a83e58a7..3b3d6e5f832 100644
--- a/tests/ui/traits/bad-method-typaram-kind.stderr
+++ b/tests/ui/traits/bad-method-typaram-kind.stderr
@@ -11,7 +11,7 @@ note: required by a bound in `Bar::bar`
    |
 LL |     fn bar<T:Send>(&self);
    |              ^^^^ required by this bound in `Bar::bar`
-help: consider further restricting this bound
+help: consider further restricting type parameter `T` with trait `Send`
    |
 LL | fn foo<T:'static + std::marker::Send>() {
    |                  +++++++++++++++++++
diff --git a/tests/ui/traits/bound/on-structs-and-enums.stderr b/tests/ui/traits/bound/on-structs-and-enums.stderr
index 606f764852f..7d6420c6482 100644
--- a/tests/ui/traits/bound/on-structs-and-enums.stderr
+++ b/tests/ui/traits/bound/on-structs-and-enums.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `Foo`
    |
 LL | struct Foo<T:Trait> {
    |              ^^^^^ required by this bound in `Foo`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Trait`
    |
 LL | impl<T: Trait> Foo<T> {
    |       +++++++
@@ -59,7 +59,7 @@ note: required by a bound in `Foo`
    |
 LL | struct Foo<T:Trait> {
    |              ^^^^^ required by this bound in `Foo`
-help: consider restricting type parameter `U`
+help: consider restricting type parameter `U` with trait `Trait`
    |
 LL | struct Badness<U: Trait> {
    |                 +++++++
@@ -75,7 +75,7 @@ note: required by a bound in `Bar`
    |
 LL | enum Bar<T:Trait> {
    |            ^^^^^ required by this bound in `Bar`
-help: consider restricting type parameter `V`
+help: consider restricting type parameter `V` with trait `Trait`
    |
 LL | enum MoreBadness<V: Trait> {
    |                   +++++++
diff --git a/tests/ui/traits/const-traits/call-generic-method-chain.stderr b/tests/ui/traits/const-traits/call-generic-method-chain.stderr
index 9a53c61d019..21fb19daad4 100644
--- a/tests/ui/traits/const-traits/call-generic-method-chain.stderr
+++ b/tests/ui/traits/const-traits/call-generic-method-chain.stderr
@@ -42,10 +42,6 @@ LL |     *t == *t
    |     ^^^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
-   |
-LL | const fn equals_self<T: ~const PartialEq + ~const std::cmp::PartialEq>(t: &T) -> bool {
-   |                                          ++++++++++++++++++++++++++++
 
 error[E0015]: cannot call non-const fn `<S as PartialEq>::eq` in constant functions
   --> $DIR/call-generic-method-chain.rs:16:15
diff --git a/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr b/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr
index a168171cfe8..845949a38bf 100644
--- a/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr
+++ b/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr
@@ -42,10 +42,6 @@ LL |     *t == *t
    |     ^^^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
-   |
-LL | const fn equals_self<T: PartialEq + ~const PartialEq + ~const std::cmp::PartialEq>(t: &T) -> bool {
-   |                                                      ++++++++++++++++++++++++++++
 
 error[E0015]: cannot call non-const fn `<S as PartialEq>::eq` in constant functions
   --> $DIR/call-generic-method-dup-bound.rs:14:15
@@ -62,10 +58,6 @@ LL |     *t == *t
    |     ^^^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
-   |
-LL | const fn equals_self2<T: A + ~const PartialEq + ~const std::cmp::PartialEq>(t: &T) -> bool {
-   |                                               ++++++++++++++++++++++++++++
 
 error: aborting due to 8 previous errors
 
diff --git a/tests/ui/traits/const-traits/call-generic-method-fail.stderr b/tests/ui/traits/const-traits/call-generic-method-fail.stderr
index 07e50a7f7da..6bacb986fef 100644
--- a/tests/ui/traits/const-traits/call-generic-method-fail.stderr
+++ b/tests/ui/traits/const-traits/call-generic-method-fail.stderr
@@ -5,10 +5,6 @@ LL |     *t == *t
    |     ^^^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
-   |
-LL | pub const fn equals_self<T: PartialEq + ~const std::cmp::PartialEq>(t: &T) -> bool {
-   |                                       ++++++++++++++++++++++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/traits/const-traits/call-generic-method-pass.stderr b/tests/ui/traits/const-traits/call-generic-method-pass.stderr
index af6e6d25dc9..0c0037e36b8 100644
--- a/tests/ui/traits/const-traits/call-generic-method-pass.stderr
+++ b/tests/ui/traits/const-traits/call-generic-method-pass.stderr
@@ -28,10 +28,6 @@ LL |     *t == *t
    |     ^^^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
-   |
-LL | const fn equals_self<T: ~const PartialEq + ~const std::cmp::PartialEq>(t: &T) -> bool {
-   |                                          ++++++++++++++++++++++++++++
 
 error[E0015]: cannot call non-const fn `<S as PartialEq>::eq` in constant functions
   --> $DIR/call-generic-method-pass.rs:16:15
diff --git a/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr b/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr
index cb4c994bc2f..a76dc3e82af 100644
--- a/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr
+++ b/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr
@@ -19,10 +19,6 @@ LL |     x(())
    |     ^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
-   |
-LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32 + ~const FnOnce(())>(x: T) -> i32 {
-   |                                                         +++++++++++++++++++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/traits/const-traits/const-closure-trait-method.stderr b/tests/ui/traits/const-traits/const-closure-trait-method.stderr
index 43af435ae64..d37ff3d727c 100644
--- a/tests/ui/traits/const-traits/const-closure-trait-method.stderr
+++ b/tests/ui/traits/const-traits/const-closure-trait-method.stderr
@@ -19,10 +19,6 @@ LL |     x(())
    |     ^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
-   |
-LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32 + ~const FnOnce(())>(x: T) -> i32 {
-   |                                                         +++++++++++++++++++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/traits/const-traits/const-closures.stderr b/tests/ui/traits/const-traits/const-closures.stderr
index 2e9e37ba321..8ceaae16d8e 100644
--- a/tests/ui/traits/const-traits/const-closures.stderr
+++ b/tests/ui/traits/const-traits/const-closures.stderr
@@ -61,10 +61,6 @@ LL |     f() + f()
    |     ^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
-   |
-LL | const fn answer<F: ~const Fn() -> u8 + ~const Fn()>(f: &F) -> u8 {
-   |                                      +++++++++++++
 
 error[E0015]: cannot call non-const closure in constant functions
   --> $DIR/const-closures.rs:24:11
@@ -73,10 +69,6 @@ LL |     f() + f()
    |           ^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
-   |
-LL | const fn answer<F: ~const Fn() -> u8 + ~const Fn()>(f: &F) -> u8 {
-   |                                      +++++++++++++
 
 error[E0015]: cannot call non-const closure in constant functions
   --> $DIR/const-closures.rs:12:5
@@ -85,10 +77,6 @@ LL |     f() * 7
    |     ^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
-   |
-LL |         F: ~const FnOnce() -> u8 + ~const Fn(),
-   |                                  +++++++++++++
 
 error: aborting due to 11 previous errors
 
diff --git a/tests/ui/traits/const-traits/trait-where-clause.stderr b/tests/ui/traits/const-traits/trait-where-clause.stderr
index abe24b662a2..3a15cc63f32 100644
--- a/tests/ui/traits/const-traits/trait-where-clause.stderr
+++ b/tests/ui/traits/const-traits/trait-where-clause.stderr
@@ -33,7 +33,7 @@ note: required by a bound in `Foo::b`
    |
 LL |     fn b() where Self: ~const Bar;
    |                        ^^^^^^^^^^ required by this bound in `Foo::b`
-help: consider further restricting this bound
+help: consider further restricting type parameter `T` with trait `Bar`
    |
 LL | fn test1<T: Foo + Bar>() {
    |                 +++++
@@ -49,7 +49,7 @@ note: required by a bound in `Foo::c`
    |
 LL |     fn c<T: ~const Bar>();
    |             ^^^^^^^^^^ required by this bound in `Foo::c`
-help: consider further restricting this bound
+help: consider further restricting type parameter `T` with trait `Bar`
    |
 LL | fn test1<T: Foo + Bar>() {
    |                 +++++
diff --git a/tests/ui/traits/copy-impl-cannot-normalize.stderr b/tests/ui/traits/copy-impl-cannot-normalize.stderr
index 3bdb8b70172..45c26ac9ef4 100644
--- a/tests/ui/traits/copy-impl-cannot-normalize.stderr
+++ b/tests/ui/traits/copy-impl-cannot-normalize.stderr
@@ -14,7 +14,7 @@ LL |     T: TraitFoo,
    |        -------- unsatisfied trait bound introduced here
 note: required by a bound in `Copy`
   --> $SRC_DIR/core/src/marker.rs:LL:COL
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `TraitFoo`
    |
 LL | impl<T: TraitFoo> Copy for Foo<T> {}
    |       ++++++++++
diff --git a/tests/ui/traits/copy-is-not-modulo-regions.not_static.stderr b/tests/ui/traits/copy-is-not-modulo-regions.not_static.stderr
index 56544dd4def..02170a127db 100644
--- a/tests/ui/traits/copy-is-not-modulo-regions.not_static.stderr
+++ b/tests/ui/traits/copy-is-not-modulo-regions.not_static.stderr
@@ -12,7 +12,7 @@ note: the `Copy` impl for `Foo<'any>` requires that `'any: 'static`
    |
 LL | struct Bar<'lt>(Foo<'lt>);
    |                 ^^^^^^^^
-help: consider restricting type parameter `'any`
+help: consider restricting type parameter `'any` with  `'static`
    |
 LL | impl<'any: 'static> Copy for Bar<'any> {}
    |          +++++++++
diff --git a/tests/ui/traits/inductive-overflow/two-traits.stderr b/tests/ui/traits/inductive-overflow/two-traits.stderr
index 6092c194a87..1816e029f18 100644
--- a/tests/ui/traits/inductive-overflow/two-traits.stderr
+++ b/tests/ui/traits/inductive-overflow/two-traits.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `Magic::X`
    |
 LL |     type X: Trait;
    |             ^^^^^ required by this bound in `Magic::X`
-help: consider further restricting this bound
+help: consider further restricting type parameter `T` with trait `Sync`
    |
 LL | impl<T: Magic + std::marker::Sync> Magic for T {
    |               +++++++++++++++++++
diff --git a/tests/ui/traits/inheritance/repeated-supertrait-ambig.stderr b/tests/ui/traits/inheritance/repeated-supertrait-ambig.stderr
index 6f7c9fa11d4..fdf0b1722be 100644
--- a/tests/ui/traits/inheritance/repeated-supertrait-ambig.stderr
+++ b/tests/ui/traits/inheritance/repeated-supertrait-ambig.stderr
@@ -18,7 +18,7 @@ LL |     c.same_as(22)
    |       |
    |       required by a bound introduced by this call
    |
-help: consider further restricting this bound
+help: consider further restricting type parameter `C` with trait `CompareTo`
    |
 LL | fn with_trait<C:CompareToInts + CompareTo<i32>>(c: &C) -> bool {
    |                               ++++++++++++++++
@@ -41,7 +41,7 @@ LL |     CompareTo::same_as(c, 22)
    |     |
    |     required by a bound introduced by this call
    |
-help: consider further restricting this bound
+help: consider further restricting type parameter `C` with trait `CompareTo`
    |
 LL | fn with_ufcs2<C:CompareToInts + CompareTo<i32>>(c: &C) -> bool {
    |                               ++++++++++++++++
diff --git a/tests/ui/traits/issue-21837.stderr b/tests/ui/traits/issue-21837.stderr
index f1989392688..06e79d40c7d 100644
--- a/tests/ui/traits/issue-21837.stderr
+++ b/tests/ui/traits/issue-21837.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `Foo`
    |
 LL | pub struct Foo<T: Bound>(T);
    |                   ^^^^^ required by this bound in `Foo`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Bound`
    |
 LL | impl<T: Bound> Trait2 for Foo<T> {}
    |       +++++++
diff --git a/tests/ui/traits/issue-43784-supertrait.stderr b/tests/ui/traits/issue-43784-supertrait.stderr
index 2bf365745a6..1a6da70d76d 100644
--- a/tests/ui/traits/issue-43784-supertrait.stderr
+++ b/tests/ui/traits/issue-43784-supertrait.stderr
@@ -14,7 +14,7 @@ note: required by a bound in `Complete`
    |
 LL | pub trait Complete: Partial {
    |                     ^^^^^^^ required by this bound in `Complete`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | impl<T: std::marker::Copy> Complete for T {}
    |       +++++++++++++++++++
diff --git a/tests/ui/traits/next-solver/diagnostics/projection-trait-ref.stderr b/tests/ui/traits/next-solver/diagnostics/projection-trait-ref.stderr
index cd8d8b3ffcd..463e50a2553 100644
--- a/tests/ui/traits/next-solver/diagnostics/projection-trait-ref.stderr
+++ b/tests/ui/traits/next-solver/diagnostics/projection-trait-ref.stderr
@@ -4,7 +4,7 @@ error[E0277]: the trait bound `T: Trait` is not satisfied
 LL |     let x: <T as Trait>::Assoc = ();
    |            ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T`
    |
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Trait`
    |
 LL | fn test_poly<T: Trait>() {
    |               +++++++
diff --git a/tests/ui/traits/next-solver/dyn-incompatibility.stderr b/tests/ui/traits/next-solver/dyn-incompatibility.stderr
index a720797efc4..6398fbddca5 100644
--- a/tests/ui/traits/next-solver/dyn-incompatibility.stderr
+++ b/tests/ui/traits/next-solver/dyn-incompatibility.stderr
@@ -10,7 +10,7 @@ note: required by a bound in `copy`
    |
 LL | fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From {
    |            ^^^^^ required by this bound in `copy`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | pub fn copy_any<T: std::marker::Copy>(t: &T) -> T {
    |                  +++++++++++++++++++
@@ -38,7 +38,7 @@ LL |     copy::<dyn Setup<From=T>>(t)
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `dyn Setup<From = T>`, the trait `Copy` is not implemented for `T`
    |
    = note: required because it appears within the type `dyn Setup<From = T>`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | pub fn copy_any<T: std::marker::Copy>(t: &T) -> T {
    |                  +++++++++++++++++++
diff --git a/tests/ui/traits/next-solver/global-cache-and-parallel-frontend.stderr b/tests/ui/traits/next-solver/global-cache-and-parallel-frontend.stderr
index 1f319cc6743..da269bbeae4 100644
--- a/tests/ui/traits/next-solver/global-cache-and-parallel-frontend.stderr
+++ b/tests/ui/traits/next-solver/global-cache-and-parallel-frontend.stderr
@@ -14,7 +14,7 @@ LL | impl<T: Clone, U> PartialEq<U> for Struct<T>
 note: required by a bound in `Eq`
   --> $SRC_DIR/core/src/cmp.rs:LL:COL
    = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Clone`
    |
 LL | pub struct Struct<T: std::clone::Clone>(T);
    |                    +++++++++++++++++++
diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.stderr b/tests/ui/traits/next-solver/issue-118950-root-region.stderr
index 09162970d33..d2a58e95629 100644
--- a/tests/ui/traits/next-solver/issue-118950-root-region.stderr
+++ b/tests/ui/traits/next-solver/issue-118950-root-region.stderr
@@ -32,7 +32,7 @@ error[E0277]: the trait bound `T: Overlap<for<'a> fn(Assoc<'a, T>)>` is not sati
 LL | impl<T> Overlap<for<'a> fn(Assoc<'a, T>)> for T where Missing: Overlap<T> {}
    |                                               ^ the trait `Overlap<for<'a> fn(Assoc<'a, T>)>` is not implemented for `T`
    |
-help: consider further restricting type parameter `T`
+help: consider further restricting type parameter `T` with trait `Overlap`
    |
 LL | impl<T> Overlap<for<'a> fn(Assoc<'a, T>)> for T where Missing: Overlap<T>, T: Overlap<for<'a> fn(Assoc<'a, T>)> {}
    |                                                                          ++++++++++++++++++++++++++++++++++++++
diff --git a/tests/ui/tuple/builtin-fail.stderr b/tests/ui/tuple/builtin-fail.stderr
index e3e29a73fdc..ccbc5ae2b75 100644
--- a/tests/ui/tuple/builtin-fail.stderr
+++ b/tests/ui/tuple/builtin-fail.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `assert_is_tuple`
    |
 LL | fn assert_is_tuple<T: std::marker::Tuple + ?Sized>() {}
    |                       ^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_tuple`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with unstable trait `Tuple`
    |
 LL | fn from_param_env<T: std::marker::Tuple>() {
    |                    ++++++++++++++++++++
diff --git a/tests/ui/type-alias-impl-trait/bounds-are-checked-2.stderr b/tests/ui/type-alias-impl-trait/bounds-are-checked-2.stderr
index 8f887a6ac68..bbb32b2d604 100644
--- a/tests/ui/type-alias-impl-trait/bounds-are-checked-2.stderr
+++ b/tests/ui/type-alias-impl-trait/bounds-are-checked-2.stderr
@@ -14,7 +14,7 @@ note: this definition site has more where clauses than the opaque type
    |
 LL |     fn f<T: Clone>(t: T) -> X<T> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Clone`
    |
 LL |     pub type X<T: std::clone::Clone> = impl Clone;
    |                 +++++++++++++++++++
diff --git a/tests/ui/type-alias-impl-trait/bounds-are-checked3.stderr b/tests/ui/type-alias-impl-trait/bounds-are-checked3.stderr
index bca88b5fae1..c0f6d678097 100644
--- a/tests/ui/type-alias-impl-trait/bounds-are-checked3.stderr
+++ b/tests/ui/type-alias-impl-trait/bounds-are-checked3.stderr
@@ -10,7 +10,7 @@ note: required by a bound in `Struct`
    |
 LL | struct Struct<V: Display>(Option<V>);
    |                  ^^^^^^^ required by this bound in `Struct`
-help: consider further restricting this bound
+help: consider further restricting type parameter `T` with trait `Display`
    |
 LL | type Foo<T: Debug + std::fmt::Display> = (impl Debug, Struct<T>);
    |                   +++++++++++++++++++
diff --git a/tests/ui/type-alias-impl-trait/future.stderr b/tests/ui/type-alias-impl-trait/future.stderr
index b20073fcdfc..047ad164239 100644
--- a/tests/ui/type-alias-impl-trait/future.stderr
+++ b/tests/ui/type-alias-impl-trait/future.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `foo`
    |
 LL | fn foo<B: Bar>(bar: B) -> FooFuture<B> {
    |           ^^^ required by this bound in `foo`
-help: consider restricting type parameter `B`
+help: consider restricting type parameter `B` with trait `Bar`
    |
 LL | type FooFuture<B: Bar> = impl Future<Output = ()>;
    |                 +++++
diff --git a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr
index af6e6e1e66e..cd6e85764bd 100644
--- a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr
+++ b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr
@@ -14,7 +14,7 @@ note: this definition site has more where clauses than the opaque type
    |
 LL | fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Debug`
    |
 LL | type Two<T: std::fmt::Debug, U> = impl Debug;
    |           +++++++++++++++++
diff --git a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr
index a847bed93da..bf3c4a0e04f 100644
--- a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr
+++ b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr
@@ -14,7 +14,7 @@ note: this definition site has more where clauses than the opaque type
    |
 LL | fn three<T, U: Debug>(_: T, u: U) -> Two<T, U> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: consider restricting type parameter `U`
+help: consider restricting type parameter `U` with trait `Debug`
    |
 LL | type Two<T, U: std::fmt::Debug> = impl Debug;
    |              +++++++++++++++++
diff --git a/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr b/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr
index 88529b370f1..98f99cdbfbd 100644
--- a/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr
+++ b/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr
@@ -9,7 +9,7 @@ note: required by a bound on the type alias `Underconstrained`
    |
 LL | type Underconstrained<T: Trait> = impl Send;
    |                          ^^^^^ required by this bound
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Trait`
    |
 LL | fn underconstrain<T: Trait>(_: T) -> Underconstrained<T> {
    |                    +++++++
@@ -30,7 +30,7 @@ note: required by a bound on the type alias `Underconstrained`
    |
 LL | type Underconstrained<T: Trait> = impl Send;
    |                          ^^^^^ required by this bound
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Trait`
    |
 LL | fn underconstrain<T: Trait>(_: T) -> Underconstrained<T> {
    |                    +++++++
diff --git a/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr b/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr
index b3b9cbca968..5506977a3e7 100644
--- a/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr
+++ b/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr
@@ -9,7 +9,7 @@ note: required by a bound on the type alias `Underconstrained`
    |
 LL | type Underconstrained<T: std::fmt::Debug> = impl Send;
    |                          ^^^^^^^^^^^^^^^ required by this bound
-help: consider restricting type parameter `U`
+help: consider restricting type parameter `U` with trait `Debug`
    |
 LL | fn underconstrained<U: std::fmt::Debug>(_: U) -> Underconstrained<U> {
    |                      +++++++++++++++++
@@ -25,7 +25,7 @@ note: required by a bound on the type alias `Underconstrained2`
    |
 LL | type Underconstrained2<T: std::fmt::Debug> = impl Send;
    |                           ^^^^^^^^^^^^^^^ required by this bound
-help: consider restricting type parameter `V`
+help: consider restricting type parameter `V` with trait `Debug`
    |
 LL | fn underconstrained2<U, V: std::fmt::Debug>(_: U, _: V) -> Underconstrained2<V> {
    |                          +++++++++++++++++
@@ -46,7 +46,7 @@ note: required by a bound on the type alias `Underconstrained`
    |
 LL | type Underconstrained<T: std::fmt::Debug> = impl Send;
    |                          ^^^^^^^^^^^^^^^ required by this bound
-help: consider restricting type parameter `U`
+help: consider restricting type parameter `U` with trait `Debug`
    |
 LL | fn underconstrained<U: std::fmt::Debug>(_: U) -> Underconstrained<U> {
    |                      +++++++++++++++++
@@ -67,7 +67,7 @@ note: required by a bound on the type alias `Underconstrained2`
    |
 LL | type Underconstrained2<T: std::fmt::Debug> = impl Send;
    |                           ^^^^^^^^^^^^^^^ required by this bound
-help: consider restricting type parameter `V`
+help: consider restricting type parameter `V` with trait `Debug`
    |
 LL | fn underconstrained2<U, V: std::fmt::Debug>(_: U, _: V) -> Underconstrained2<V> {
    |                          +++++++++++++++++
diff --git a/tests/ui/type-alias-impl-trait/issue-52843.stderr b/tests/ui/type-alias-impl-trait/issue-52843.stderr
index a6bdddbc98c..6673b03525d 100644
--- a/tests/ui/type-alias-impl-trait/issue-52843.stderr
+++ b/tests/ui/type-alias-impl-trait/issue-52843.stderr
@@ -14,7 +14,7 @@ note: this definition site has more where clauses than the opaque type
    |
 LL | fn foo<T: Default>(t: T) -> Foo<T> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Default`
    |
 LL | type Foo<T: std::default::Default> = impl Default;
    |           +++++++++++++++++++++++
diff --git a/tests/ui/type-alias-impl-trait/issue-53092.stderr b/tests/ui/type-alias-impl-trait/issue-53092.stderr
index f04750866c7..579902aa3ab 100644
--- a/tests/ui/type-alias-impl-trait/issue-53092.stderr
+++ b/tests/ui/type-alias-impl-trait/issue-53092.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `make_bug`
    |
 LL |     fn make_bug<T, U: From<T>>() -> Bug<T, U> {
    |                       ^^^^^^^ required by this bound in `make_bug`
-help: consider restricting type parameter `U`
+help: consider restricting type parameter `U` with trait `From`
    |
 LL |     pub type Bug<T, U: std::convert::From<T>> = impl Fn(T) -> U + Copy;
    |                      +++++++++++++++++++++++
diff --git a/tests/ui/type-alias-impl-trait/issue-89686.stderr b/tests/ui/type-alias-impl-trait/issue-89686.stderr
index 91d71339a08..6fa7e197c40 100644
--- a/tests/ui/type-alias-impl-trait/issue-89686.stderr
+++ b/tests/ui/type-alias-impl-trait/issue-89686.stderr
@@ -4,7 +4,7 @@ error[E0277]: the trait bound `T: Trait` is not satisfied
 LL |         async move { self.f().await }
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T`
    |
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Trait`
    |
 LL | type G<'a, T: Trait> = impl Future<Output = ()>;
    |             +++++++
diff --git a/tests/ui/type-alias-impl-trait/issue-90400-1.stderr b/tests/ui/type-alias-impl-trait/issue-90400-1.stderr
index bc233a53214..afdccd56a50 100644
--- a/tests/ui/type-alias-impl-trait/issue-90400-1.stderr
+++ b/tests/ui/type-alias-impl-trait/issue-90400-1.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `<MyFoo as Foo>::foo`
    |
 LL |     fn foo<B: Bar>(&self, bar: B) -> Self::FooFn<B> {
    |               ^^^ required by this bound in `<MyFoo as Foo>::foo`
-help: consider restricting type parameter `B`
+help: consider restricting type parameter `B` with trait `Bar`
    |
 LL |     type FooFn<B: Bar> = impl FnOnce();
    |                 +++++
diff --git a/tests/ui/type-alias-impl-trait/issue-90400-2.stderr b/tests/ui/type-alias-impl-trait/issue-90400-2.stderr
index 4a6a62bdf96..d4faa6e9392 100644
--- a/tests/ui/type-alias-impl-trait/issue-90400-2.stderr
+++ b/tests/ui/type-alias-impl-trait/issue-90400-2.stderr
@@ -21,7 +21,7 @@ note: this definition site has more where clauses than the opaque type
    |
 LL |     fn foo<B: Bar>(&self, bar: B) -> Self::FooFn<B> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: consider restricting type parameter `B`
+help: consider restricting type parameter `B` with trait `Bar`
    |
 LL |     type FooFn<B: Bar> = impl Baz;
    |                 +++++
diff --git a/tests/ui/type-alias-impl-trait/not_well_formed.stderr b/tests/ui/type-alias-impl-trait/not_well_formed.stderr
index a2944a1acb9..e2fa9442323 100644
--- a/tests/ui/type-alias-impl-trait/not_well_formed.stderr
+++ b/tests/ui/type-alias-impl-trait/not_well_formed.stderr
@@ -4,7 +4,7 @@ error[E0220]: associated type `Assoc` not found for `V`
 LL | type Foo<V> = impl Trait<V::Assoc>;
    |                             ^^^^^ there is an associated type `Assoc` in the trait `TraitWithAssoc`
    |
-help: consider restricting type parameter `V`
+help: consider restricting type parameter `V` with trait `TraitWithAssoc`
    |
 LL | type Foo<V: TraitWithAssoc> = impl Trait<V::Assoc>;
    |           ++++++++++++++++
@@ -16,7 +16,7 @@ LL | type Foo<V> = impl Trait<V::Assoc>;
    |                             ^^^^^ there is an associated type `Assoc` in the trait `TraitWithAssoc`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: consider restricting type parameter `V`
+help: consider restricting type parameter `V` with trait `TraitWithAssoc`
    |
 LL | type Foo<V: TraitWithAssoc> = impl Trait<V::Assoc>;
    |           ++++++++++++++++
diff --git a/tests/ui/type-alias-impl-trait/self-referential-3.rs b/tests/ui/type-alias-impl-trait/self-referential-3.rs
index b33051da2d7..18f09b54867 100644
--- a/tests/ui/type-alias-impl-trait/self-referential-3.rs
+++ b/tests/ui/type-alias-impl-trait/self-referential-3.rs
@@ -1,5 +1,3 @@
-//@ ignore-compare-mode-next-solver (hangs)
-
 #![feature(type_alias_impl_trait)]
 
 type Bar<'a, 'b> = impl PartialEq<Bar<'a, 'b>> + std::fmt::Debug;
diff --git a/tests/ui/type-alias-impl-trait/self-referential-3.stderr b/tests/ui/type-alias-impl-trait/self-referential-3.stderr
index 32eac622e51..15ebcdafca6 100644
--- a/tests/ui/type-alias-impl-trait/self-referential-3.stderr
+++ b/tests/ui/type-alias-impl-trait/self-referential-3.stderr
@@ -1,5 +1,5 @@
 error[E0277]: can't compare `&i32` with `Bar<'a, 'b>`
-  --> $DIR/self-referential-3.rs:7:31
+  --> $DIR/self-referential-3.rs:5:31
    |
 LL | fn bar<'a, 'b>(i: &'a i32) -> Bar<'a, 'b> {
    |                               ^^^^^^^^^^^ no implementation for `&i32 == Bar<'a, 'b>`
diff --git a/tests/ui/type-alias-impl-trait/self-referential-4.rs b/tests/ui/type-alias-impl-trait/self-referential-4.rs
index 29b5a042b7d..36742c8ad57 100644
--- a/tests/ui/type-alias-impl-trait/self-referential-4.rs
+++ b/tests/ui/type-alias-impl-trait/self-referential-4.rs
@@ -1,5 +1,3 @@
-//@ ignore-compare-mode-next-solver (hangs)
-
 #![feature(type_alias_impl_trait)]
 
 type Bar<'a, 'b> = impl PartialEq<Bar<'b, 'static>> + std::fmt::Debug;
diff --git a/tests/ui/type-alias-impl-trait/self-referential-4.stderr b/tests/ui/type-alias-impl-trait/self-referential-4.stderr
index e7f9e232a27..98c762e3d38 100644
--- a/tests/ui/type-alias-impl-trait/self-referential-4.stderr
+++ b/tests/ui/type-alias-impl-trait/self-referential-4.stderr
@@ -1,5 +1,5 @@
 error[E0277]: can't compare `&i32` with `Bar<'b, 'static>`
-  --> $DIR/self-referential-4.rs:7:31
+  --> $DIR/self-referential-4.rs:5:31
    |
 LL | fn bar<'a, 'b>(i: &'a i32) -> Bar<'a, 'b> {
    |                               ^^^^^^^^^^^ no implementation for `&i32 == Bar<'b, 'static>`
@@ -10,7 +10,7 @@ LL |     i
    = help: the trait `PartialEq` is implemented for `i32`
 
 error[E0277]: can't compare `&i32` with `Foo<'static, 'b>`
-  --> $DIR/self-referential-4.rs:13:31
+  --> $DIR/self-referential-4.rs:11:31
    |
 LL | fn foo<'a, 'b>(i: &'a i32) -> Foo<'a, 'b> {
    |                               ^^^^^^^^^^^ no implementation for `&i32 == Foo<'static, 'b>`
@@ -21,7 +21,7 @@ LL |     i
    = help: the trait `PartialEq` is implemented for `i32`
 
 error[E0277]: can't compare `&i32` with `Moo<'static, 'a>`
-  --> $DIR/self-referential-4.rs:19:31
+  --> $DIR/self-referential-4.rs:17:31
    |
 LL | fn moo<'a, 'b>(i: &'a i32) -> Moo<'a, 'b> {
    |                               ^^^^^^^^^^^ no implementation for `&i32 == Moo<'static, 'a>`
diff --git a/tests/ui/type-alias-impl-trait/self-referential.rs b/tests/ui/type-alias-impl-trait/self-referential.rs
index 2bd450e6c86..b899b12cc4a 100644
--- a/tests/ui/type-alias-impl-trait/self-referential.rs
+++ b/tests/ui/type-alias-impl-trait/self-referential.rs
@@ -1,5 +1,3 @@
-//@ ignore-compare-mode-next-solver (hangs)
-
 #![feature(type_alias_impl_trait)]
 
 type Bar<'a, 'b> = impl PartialEq<Bar<'b, 'a>> + std::fmt::Debug;
diff --git a/tests/ui/type-alias-impl-trait/self-referential.stderr b/tests/ui/type-alias-impl-trait/self-referential.stderr
index 396237c7898..57d67f69376 100644
--- a/tests/ui/type-alias-impl-trait/self-referential.stderr
+++ b/tests/ui/type-alias-impl-trait/self-referential.stderr
@@ -1,5 +1,5 @@
 error[E0277]: can't compare `&i32` with `Bar<'b, 'a>`
-  --> $DIR/self-referential.rs:7:31
+  --> $DIR/self-referential.rs:5:31
    |
 LL | fn bar<'a, 'b>(i: &'a i32) -> Bar<'a, 'b> {
    |                               ^^^^^^^^^^^ no implementation for `&i32 == Bar<'b, 'a>`
@@ -11,7 +11,7 @@ LL |     i
    = help: the trait `PartialEq` is implemented for `i32`
 
 error[E0277]: can't compare `&i32` with `(i32, Foo<'a, 'b>::{opaque#0}<'a, 'b>)`
-  --> $DIR/self-referential.rs:14:31
+  --> $DIR/self-referential.rs:12:31
    |
 LL | fn foo<'a, 'b>(i: &'a i32) -> Foo<'a, 'b> {
    |                               ^^^^^^^^^^^ no implementation for `&i32 == (i32, Foo<'a, 'b>::{opaque#0}<'a, 'b>)`
@@ -23,7 +23,7 @@ LL |     (42, i)
    = help: the trait `PartialEq` is implemented for `i32`
 
 error[E0277]: can't compare `&i32` with `(i32, Moo<'b, 'a>::{opaque#0}<'b, 'a>)`
-  --> $DIR/self-referential.rs:21:31
+  --> $DIR/self-referential.rs:19:31
    |
 LL | fn moo<'a, 'b>(i: &'a i32) -> Moo<'a, 'b> {
    |                               ^^^^^^^^^^^ no implementation for `&i32 == (i32, Moo<'b, 'a>::{opaque#0}<'b, 'a>)`
diff --git a/tests/ui/type-alias-impl-trait/underconstrained_generic.stderr b/tests/ui/type-alias-impl-trait/underconstrained_generic.stderr
index 48cef847fbb..e50949ed8f3 100644
--- a/tests/ui/type-alias-impl-trait/underconstrained_generic.stderr
+++ b/tests/ui/type-alias-impl-trait/underconstrained_generic.stderr
@@ -21,7 +21,7 @@ note: this definition site has more where clauses than the opaque type
    |
 LL | fn _defining_use<T: Trait>() -> Converter<T> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Trait`
    |
 LL | type Converter<T: Trait> = impl ProofForConversion<T>;
    |                 +++++++
diff --git a/tests/ui/type-alias-impl-trait/wf-check-fn-def.stderr b/tests/ui/type-alias-impl-trait/wf-check-fn-def.stderr
index 47bea7bbe60..9046a8a76b8 100644
--- a/tests/ui/type-alias-impl-trait/wf-check-fn-def.stderr
+++ b/tests/ui/type-alias-impl-trait/wf-check-fn-def.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `mop`
    |
 LL |     fn mop<B: Bar>(bar: B) { bar.bar() }
    |               ^^^ required by this bound in `mop`
-help: consider restricting type parameter `B`
+help: consider restricting type parameter `B` with trait `Bar`
    |
 LL | type FooFn<B: Bar> = impl FnOnce(B);
    |             +++++
diff --git a/tests/ui/type-alias-impl-trait/wf_check_closures.stderr b/tests/ui/type-alias-impl-trait/wf_check_closures.stderr
index 09a42f73490..4156f0ca96a 100644
--- a/tests/ui/type-alias-impl-trait/wf_check_closures.stderr
+++ b/tests/ui/type-alias-impl-trait/wf_check_closures.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `foo`
    |
 LL | fn foo<B: Bar>(bar: B) -> FooFn<B> {
    |           ^^^ required by this bound in `foo`
-help: consider restricting type parameter `B`
+help: consider restricting type parameter `B` with trait `Bar`
    |
 LL | type FooFn<B: Bar> = impl FnOnce();
    |             +++++
diff --git a/tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.lazy.stderr b/tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.lazy.stderr
index 96179a7b484..885c6ec9d8e 100644
--- a/tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.lazy.stderr
+++ b/tests/ui/type-alias/unresolved-assoc-ty-suggest-trait.lazy.stderr
@@ -4,7 +4,7 @@ error[E0220]: associated type `Assoc` not found for `T`
 LL | type AssocOf<T> = T::Assoc;
    |                      ^^^^^ there is an associated type `Assoc` in the trait `Trait`
    |
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Trait`
    |
 LL | type AssocOf<T: Trait> = T::Assoc;
    |               +++++++
@@ -15,7 +15,7 @@ error[E0220]: associated type `Assok` not found for `T`
 LL | type AssokOf<T> = T::Assok;
    |                      ^^^^^ there is a similarly named associated type `Assoc` in the trait `Trait`
    |
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Trait`
    |
 LL | type AssokOf<T: Trait> = T::Assok;
    |               +++++++
@@ -30,7 +30,7 @@ error[E0220]: associated type `Proj` not found for `T`
 LL | type ProjOf<T> = T::Proj;
    |                     ^^^^ there is an associated type `Proj` in the trait `Parametrized`
    |
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Parametrized`
    |
 LL | type ProjOf<T: Parametrized</* 'a, T, N */>> = T::Proj;
    |              ++++++++++++++++++++++++++++++
diff --git a/tests/ui/type/auxiliary/crate_a1.rs b/tests/ui/type/auxiliary/crate_a1.rs
index e2e18500541..616493193fd 100644
--- a/tests/ui/type/auxiliary/crate_a1.rs
+++ b/tests/ui/type/auxiliary/crate_a1.rs
@@ -1,6 +1,6 @@
 pub struct Foo;
 
-pub trait Bar{}
+pub trait Bar {}
 
 pub fn bar() -> Box<Bar> {
     unimplemented!()
diff --git a/tests/ui/type/auxiliary/crate_a2.rs b/tests/ui/type/auxiliary/crate_a2.rs
index d16a4ac10e0..57a7685b77c 100644
--- a/tests/ui/type/auxiliary/crate_a2.rs
+++ b/tests/ui/type/auxiliary/crate_a2.rs
@@ -1,6 +1,6 @@
 pub struct Foo;
 
-pub trait Bar{}
+pub trait Bar {}
 
 pub fn bar() -> Box<Bar> {
     unimplemented!()
diff --git a/tests/ui/type/type-check-defaults.stderr b/tests/ui/type/type-check-defaults.stderr
index 9c482506129..ab3378eaa4a 100644
--- a/tests/ui/type/type-check-defaults.stderr
+++ b/tests/ui/type/type-check-defaults.stderr
@@ -53,7 +53,7 @@ note: required by a bound in `Super`
    |
 LL | trait Super<T: Copy> { }
    |                ^^^^ required by this bound in `Super`
-help: consider further restricting type parameter `T`
+help: consider further restricting type parameter `T` with trait `Copy`
    |
 LL | trait Base<T = String>: Super<T> where T: std::marker::Copy { }
    |                                  ++++++++++++++++++++++++++
diff --git a/tests/ui/type/type-check/missing_trait_impl.stderr b/tests/ui/type/type-check/missing_trait_impl.stderr
index 2b58cd4180b..033b42e6736 100644
--- a/tests/ui/type/type-check/missing_trait_impl.stderr
+++ b/tests/ui/type/type-check/missing_trait_impl.stderr
@@ -6,7 +6,7 @@ LL |     let z = x + y;
    |             |
    |             T
    |
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Add`
    |
 LL | fn foo<T: std::ops::Add>(x: T, y: T) {
    |         +++++++++++++++
@@ -19,7 +19,7 @@ LL |     x += x;
    |     |
    |     cannot use `+=` on type `T`
    |
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `AddAssign`
    |
 LL | fn bar<T: std::ops::AddAssign>(x: T) {
    |         +++++++++++++++++++++
@@ -30,7 +30,7 @@ error[E0600]: cannot apply unary operator `-` to type `T`
 LL |     let y = -x;
    |             ^^ cannot apply unary operator `-`
    |
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Neg`
    |
 LL | fn baz<T: std::ops::Neg>(x: T) {
    |         +++++++++++++++
@@ -41,7 +41,7 @@ error[E0600]: cannot apply unary operator `!` to type `T`
 LL |     let y = !x;
    |             ^^ cannot apply unary operator `!`
    |
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Not`
    |
 LL | fn baz<T: std::ops::Not>(x: T) {
    |         +++++++++++++++
diff --git a/tests/ui/type/type-mismatch-same-crate-name.rs b/tests/ui/type/type-mismatch-same-crate-name.rs
index da766165238..e88960364a2 100644
--- a/tests/ui/type/type-mismatch-same-crate-name.rs
+++ b/tests/ui/type/type-mismatch-same-crate-name.rs
@@ -3,25 +3,32 @@
 
 // This tests the extra note reported when a type error deals with
 // seemingly identical types.
-// The main use case of this error is when there are two crates
-// (generally different versions of the same crate) with the same name
-// causing a type mismatch. Here, we simulate that error using block-scoped
-// aliased `extern crate` declarations.
+// The main use case of this error is when there are two crates imported
+// with the same name, causing a type mismatch. Here, we simulate that error
+// using block-scoped aliased `extern crate` declarations.
+// This is *not* the same case as two different crate versions in the
+// dependency tree. That is tested in `tests/run-make/crate-loading/`.
 
 fn main() {
     let foo2 = {extern crate crate_a2 as a; a::Foo};
+        //~^ NOTE one type comes from crate `crate_a2` used here, which is renamed locally to `a`
+        //~| NOTE one trait comes from crate `crate_a2` used here, which is renamed locally to `a`
     let bar2 = {extern crate crate_a2 as a; a::bar()};
     {
         extern crate crate_a1 as a;
+        //~^ NOTE one type comes from crate `crate_a1` used here, which is renamed locally to `a`
+        //~| NOTE one trait comes from crate `crate_a1` used here, which is renamed locally to `a`
         a::try_foo(foo2);
         //~^ ERROR mismatched types
-        //~| perhaps two different versions of crate `crate_a1`
-        //~| expected `main::a::Foo`, found a different `main::a::Foo`
+        //~| NOTE expected `main::a::Foo`, found a different `main::a::Foo`
+        //~| NOTE arguments to this function are incorrect
+        //~| NOTE two types coming from two different crates are different types even if they look the same
+        //~| NOTE function defined here
         a::try_bar(bar2);
         //~^ ERROR mismatched types
-        //~| perhaps two different versions of crate `crate_a1`
-        //~| expected trait `main::a::Bar`
-        //~| expected struct `Box<(dyn main::a::Bar + 'static)>`
-        //~| found struct `Box<dyn main::a::Bar>`
+        //~| NOTE expected trait `main::a::Bar`, found a different trait `main::a::Bar`
+        //~| NOTE arguments to this function are incorrect
+        //~| NOTE two types coming from two different crates are different types even if they look the same
+        //~| NOTE function defined here
     }
 }
diff --git a/tests/ui/type/type-mismatch-same-crate-name.stderr b/tests/ui/type/type-mismatch-same-crate-name.stderr
index 504812f5867..7b791549f56 100644
--- a/tests/ui/type/type-mismatch-same-crate-name.stderr
+++ b/tests/ui/type/type-mismatch-same-crate-name.stderr
@@ -1,23 +1,29 @@
 error[E0308]: mismatched types
-  --> $DIR/type-mismatch-same-crate-name.rs:16:20
+  --> $DIR/type-mismatch-same-crate-name.rs:21:20
    |
 LL |         a::try_foo(foo2);
    |         ---------- ^^^^ expected `main::a::Foo`, found a different `main::a::Foo`
    |         |
    |         arguments to this function are incorrect
    |
-   = note: `main::a::Foo` and `main::a::Foo` have similar names, but are actually distinct types
-note: `main::a::Foo` is defined in crate `crate_a2`
+note: two types coming from two different crates are different types even if they look the same
   --> $DIR/auxiliary/crate_a2.rs:1:1
    |
 LL | pub struct Foo;
-   | ^^^^^^^^^^^^^^
-note: `main::a::Foo` is defined in crate `crate_a1`
-  --> $DIR/auxiliary/crate_a1.rs:1:1
+   | ^^^^^^^^^^^^^^ this is the found type `crate_a2::Foo`
+   |
+  ::: $DIR/auxiliary/crate_a1.rs:1:1
    |
 LL | pub struct Foo;
-   | ^^^^^^^^^^^^^^
-   = note: perhaps two different versions of crate `crate_a1` are being used?
+   | ^^^^^^^^^^^^^^ this is the expected type `crate_a1::Foo`
+   |
+  ::: $DIR/type-mismatch-same-crate-name.rs:13:17
+   |
+LL |     let foo2 = {extern crate crate_a2 as a; a::Foo};
+   |                 --------------------------- one type comes from crate `crate_a2` used here, which is renamed locally to `a`
+...
+LL |         extern crate crate_a1 as a;
+   |         --------------------------- one type comes from crate `crate_a1` used here, which is renamed locally to `a`
 note: function defined here
   --> $DIR/auxiliary/crate_a1.rs:10:8
    |
@@ -25,16 +31,31 @@ LL | pub fn try_foo(x: Foo){}
    |        ^^^^^^^
 
 error[E0308]: mismatched types
-  --> $DIR/type-mismatch-same-crate-name.rs:20:20
+  --> $DIR/type-mismatch-same-crate-name.rs:27:20
    |
 LL |         a::try_bar(bar2);
    |         ---------- ^^^^ expected trait `main::a::Bar`, found a different trait `main::a::Bar`
    |         |
    |         arguments to this function are incorrect
    |
-   = note: expected struct `Box<(dyn main::a::Bar + 'static)>`
-              found struct `Box<dyn main::a::Bar>`
-   = note: perhaps two different versions of crate `crate_a1` are being used?
+note: two types coming from two different crates are different types even if they look the same
+  --> $DIR/auxiliary/crate_a2.rs:3:1
+   |
+LL | pub trait Bar {}
+   | ^^^^^^^^^^^^^ this is the found trait `crate_a2::Bar`
+   |
+  ::: $DIR/auxiliary/crate_a1.rs:3:1
+   |
+LL | pub trait Bar {}
+   | ^^^^^^^^^^^^^ this is the expected trait `crate_a1::Bar`
+   |
+  ::: $DIR/type-mismatch-same-crate-name.rs:13:17
+   |
+LL |     let foo2 = {extern crate crate_a2 as a; a::Foo};
+   |                 --------------------------- one trait comes from crate `crate_a2` used here, which is renamed locally to `a`
+...
+LL |         extern crate crate_a1 as a;
+   |         --------------------------- one trait comes from crate `crate_a1` used here, which is renamed locally to `a`
 note: function defined here
   --> $DIR/auxiliary/crate_a1.rs:11:8
    |
diff --git a/tests/ui/typeck/bad-index-due-to-nested.stderr b/tests/ui/typeck/bad-index-due-to-nested.stderr
index bd7fd0392c3..dd2ce092368 100644
--- a/tests/ui/typeck/bad-index-due-to-nested.stderr
+++ b/tests/ui/typeck/bad-index-due-to-nested.stderr
@@ -12,7 +12,7 @@ LL | impl<K, V> Index<&K> for HashMap<K, V>
 LL | where
 LL |     K: Hash,
    |        ---- unsatisfied trait bound introduced here
-help: consider restricting type parameter `K`
+help: consider restricting type parameter `K` with trait `Hash`
    |
 LL | fn index<'a, K: std::hash::Hash, V>(map: &'a HashMap<K, V>, k: K) -> &'a V {
    |               +++++++++++++++++
@@ -31,7 +31,7 @@ LL | impl<K, V> Index<&K> for HashMap<K, V>
 ...
 LL |     V: Copy,
    |        ---- unsatisfied trait bound introduced here
-help: consider restricting type parameter `V`
+help: consider restricting type parameter `V` with trait `Copy`
    |
 LL | fn index<'a, K, V: std::marker::Copy>(map: &'a HashMap<K, V>, k: K) -> &'a V {
    |                  +++++++++++++++++++
diff --git a/tests/ui/typeck/issue-90164.stderr b/tests/ui/typeck/issue-90164.stderr
index 43e96e1adc6..1be9c1a0b6e 100644
--- a/tests/ui/typeck/issue-90164.stderr
+++ b/tests/ui/typeck/issue-90164.stderr
@@ -13,7 +13,7 @@ note: required by a bound in `copy`
    |
 LL | fn copy<R: Unpin, W>(_: R, _: W) {}
    |            ^^^^^ required by this bound in `copy`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Unpin`
    |
 LL | fn f<T: std::marker::Unpin>(r: T) {
    |       ++++++++++++++++++++
diff --git a/tests/ui/typeck/typeck-default-trait-impl-send-param.stderr b/tests/ui/typeck/typeck-default-trait-impl-send-param.stderr
index 537ae6b2b5f..d72c56ac712 100644
--- a/tests/ui/typeck/typeck-default-trait-impl-send-param.stderr
+++ b/tests/ui/typeck/typeck-default-trait-impl-send-param.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `is_send`
    |
 LL | fn is_send<T:Send>() {
    |              ^^^^ required by this bound in `is_send`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Send`
    |
 LL | fn foo<T: std::marker::Send>() {
    |         +++++++++++++++++++
diff --git a/tests/ui/union/issue-81199.stderr b/tests/ui/union/issue-81199.stderr
index 0dd894beb2a..8b78ddcf4a5 100644
--- a/tests/ui/union/issue-81199.stderr
+++ b/tests/ui/union/issue-81199.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `PtrComponents`
    |
 LL | struct PtrComponents<T: Pointee + ?Sized> {
    |                         ^^^^^^^ required by this bound in `PtrComponents`
-help: consider further restricting this bound
+help: consider further restricting type parameter `T` with trait `Pointee`
    |
 LL | union PtrRepr<T: ?Sized + Pointee> {
    |                         +++++++++
diff --git a/tests/ui/unop/unop-move-semantics.stderr b/tests/ui/unop/unop-move-semantics.stderr
index 0ae918d434a..5b81feaa578 100644
--- a/tests/ui/unop/unop-move-semantics.stderr
+++ b/tests/ui/unop/unop-move-semantics.stderr
@@ -15,7 +15,7 @@ help: consider cloning the value if the performance cost is acceptable
    |
 LL |     !x.clone();
    |       ++++++++
-help: consider further restricting this bound
+help: consider further restricting type parameter `T` with trait `Copy`
    |
 LL | fn move_then_borrow<T: Not<Output=T> + Clone + Copy>(x: T) {
    |                                              ++++++
diff --git a/tests/ui/wf/issue-96810.stderr b/tests/ui/wf/issue-96810.stderr
index 622d72f791e..3f87d3e0786 100644
--- a/tests/ui/wf/issue-96810.stderr
+++ b/tests/ui/wf/issue-96810.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `S`
    |
 LL | struct S<T: Tr>(T::Assoc);
    |             ^^ required by this bound in `S`
-help: consider restricting type parameter `K`
+help: consider restricting type parameter `K` with trait `Tr`
    |
 LL | struct Hoge<K: Tr> {
    |              ++++
diff --git a/tests/ui/wf/wf-enum-bound.stderr b/tests/ui/wf/wf-enum-bound.stderr
index 78b5c6ec20e..1f37dc409fc 100644
--- a/tests/ui/wf/wf-enum-bound.stderr
+++ b/tests/ui/wf/wf-enum-bound.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `ExtraCopy`
    |
 LL | trait ExtraCopy<T:Copy> { }
    |                   ^^^^ required by this bound in `ExtraCopy`
-help: consider further restricting type parameter `U`
+help: consider further restricting type parameter `U` with trait `Copy`
    |
 LL |     where T: ExtraCopy<U>, U: std::marker::Copy
    |                          ++++++++++++++++++++++
diff --git a/tests/ui/wf/wf-enum-fields-struct-variant.stderr b/tests/ui/wf/wf-enum-fields-struct-variant.stderr
index 2f2c1c2d266..f15a31887a2 100644
--- a/tests/ui/wf/wf-enum-fields-struct-variant.stderr
+++ b/tests/ui/wf/wf-enum-fields-struct-variant.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `IsCopy`
    |
 LL | struct IsCopy<T:Copy> {
    |                 ^^^^ required by this bound in `IsCopy`
-help: consider restricting type parameter `A`
+help: consider restricting type parameter `A` with trait `Copy`
    |
 LL | enum AnotherEnum<A: std::marker::Copy> {
    |                   +++++++++++++++++++
diff --git a/tests/ui/wf/wf-enum-fields.stderr b/tests/ui/wf/wf-enum-fields.stderr
index a5feaadfc75..3b4de77efdc 100644
--- a/tests/ui/wf/wf-enum-fields.stderr
+++ b/tests/ui/wf/wf-enum-fields.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `IsCopy`
    |
 LL | struct IsCopy<T:Copy> {
    |                 ^^^^ required by this bound in `IsCopy`
-help: consider restricting type parameter `A`
+help: consider restricting type parameter `A` with trait `Copy`
    |
 LL | enum SomeEnum<A: std::marker::Copy> {
    |                +++++++++++++++++++
diff --git a/tests/ui/wf/wf-fn-where-clause.stderr b/tests/ui/wf/wf-fn-where-clause.stderr
index fbfe42ac624..76671dedabf 100644
--- a/tests/ui/wf/wf-fn-where-clause.stderr
+++ b/tests/ui/wf/wf-fn-where-clause.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `ExtraCopy`
    |
 LL | trait ExtraCopy<T:Copy> { }
    |                   ^^^^ required by this bound in `ExtraCopy`
-help: consider further restricting type parameter `U`
+help: consider further restricting type parameter `U` with trait `Copy`
    |
 LL | fn foo<T,U>() where T: ExtraCopy<U>, U: std::marker::Copy
    |                                    ++++++++++++++++++++++
diff --git a/tests/ui/wf/wf-impl-associated-type-trait.stderr b/tests/ui/wf/wf-impl-associated-type-trait.stderr
index 09e255bead0..47962c75d69 100644
--- a/tests/ui/wf/wf-impl-associated-type-trait.stderr
+++ b/tests/ui/wf/wf-impl-associated-type-trait.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `MySet`
    |
 LL | pub struct MySet<T:MyHash> {
    |                    ^^^^^^ required by this bound in `MySet`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `MyHash`
    |
 LL | impl<T: MyHash> Foo for T {
    |       ++++++++
diff --git a/tests/ui/wf/wf-in-fn-arg.stderr b/tests/ui/wf/wf-in-fn-arg.stderr
index 8f22edd17a1..a65f621526b 100644
--- a/tests/ui/wf/wf-in-fn-arg.stderr
+++ b/tests/ui/wf/wf-in-fn-arg.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `MustBeCopy`
    |
 LL | struct MustBeCopy<T:Copy> {
    |                     ^^^^ required by this bound in `MustBeCopy`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | fn bar<T: std::marker::Copy>(_: &MustBeCopy<T>)
    |         +++++++++++++++++++
diff --git a/tests/ui/wf/wf-in-fn-ret.stderr b/tests/ui/wf/wf-in-fn-ret.stderr
index 1ae49a348cc..3f2b46f8478 100644
--- a/tests/ui/wf/wf-in-fn-ret.stderr
+++ b/tests/ui/wf/wf-in-fn-ret.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `MustBeCopy`
    |
 LL | struct MustBeCopy<T: Copy> {
    |                      ^^^^ required by this bound in `MustBeCopy`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | fn bar<T: std::marker::Copy>() -> MustBeCopy<T>
    |         +++++++++++++++++++
diff --git a/tests/ui/wf/wf-in-fn-type-arg.stderr b/tests/ui/wf/wf-in-fn-type-arg.stderr
index 17594c813da..4626b90500a 100644
--- a/tests/ui/wf/wf-in-fn-type-arg.stderr
+++ b/tests/ui/wf/wf-in-fn-type-arg.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `MustBeCopy`
    |
 LL | struct MustBeCopy<T:Copy> {
    |                     ^^^^ required by this bound in `MustBeCopy`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | struct Bar<T: std::marker::Copy> {
    |             +++++++++++++++++++
diff --git a/tests/ui/wf/wf-in-fn-type-ret.stderr b/tests/ui/wf/wf-in-fn-type-ret.stderr
index fac535a1126..2ad405b4451 100644
--- a/tests/ui/wf/wf-in-fn-type-ret.stderr
+++ b/tests/ui/wf/wf-in-fn-type-ret.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `MustBeCopy`
    |
 LL | struct MustBeCopy<T:Copy> {
    |                     ^^^^ required by this bound in `MustBeCopy`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | struct Foo<T: std::marker::Copy> {
    |             +++++++++++++++++++
diff --git a/tests/ui/wf/wf-in-fn-where-clause.stderr b/tests/ui/wf/wf-in-fn-where-clause.stderr
index 4c556d3d77d..6a56d1c032f 100644
--- a/tests/ui/wf/wf-in-fn-where-clause.stderr
+++ b/tests/ui/wf/wf-in-fn-where-clause.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `MustBeCopy`
    |
 LL | trait MustBeCopy<T:Copy> {
    |                    ^^^^ required by this bound in `MustBeCopy`
-help: consider further restricting type parameter `U`
+help: consider further restricting type parameter `U` with trait `Copy`
    |
 LL |     where T: MustBeCopy<U>, U: std::marker::Copy
    |                           ++++++++++++++++++++++
diff --git a/tests/ui/wf/wf-in-obj-type-trait.stderr b/tests/ui/wf/wf-in-obj-type-trait.stderr
index b96f56a12a5..5cd5bf5e24e 100644
--- a/tests/ui/wf/wf-in-obj-type-trait.stderr
+++ b/tests/ui/wf/wf-in-obj-type-trait.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `MustBeCopy`
    |
 LL | struct MustBeCopy<T:Copy> {
    |                     ^^^^ required by this bound in `MustBeCopy`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | struct Bar<T: std::marker::Copy> {
    |             +++++++++++++++++++
diff --git a/tests/ui/wf/wf-inherent-impl-method-where-clause.stderr b/tests/ui/wf/wf-inherent-impl-method-where-clause.stderr
index 4cfbec12b6e..8b41bb17d2f 100644
--- a/tests/ui/wf/wf-inherent-impl-method-where-clause.stderr
+++ b/tests/ui/wf/wf-inherent-impl-method-where-clause.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `ExtraCopy`
    |
 LL | trait ExtraCopy<T:Copy> { }
    |                   ^^^^ required by this bound in `ExtraCopy`
-help: consider restricting type parameter `U`
+help: consider restricting type parameter `U` with trait `Copy`
    |
 LL | impl<T,U: std::marker::Copy> Foo<T,U> {
    |         +++++++++++++++++++
diff --git a/tests/ui/wf/wf-inherent-impl-where-clause.stderr b/tests/ui/wf/wf-inherent-impl-where-clause.stderr
index bdc1ee3e0e2..216b7a98b13 100644
--- a/tests/ui/wf/wf-inherent-impl-where-clause.stderr
+++ b/tests/ui/wf/wf-inherent-impl-where-clause.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `ExtraCopy`
    |
 LL | trait ExtraCopy<T:Copy> { }
    |                   ^^^^ required by this bound in `ExtraCopy`
-help: consider further restricting type parameter `U`
+help: consider further restricting type parameter `U` with trait `Copy`
    |
 LL | impl<T,U> Foo<T,U> where T: ExtraCopy<U>, U: std::marker::Copy
    |                                         ++++++++++++++++++++++
diff --git a/tests/ui/wf/wf-struct-bound.stderr b/tests/ui/wf/wf-struct-bound.stderr
index 4ac7f4634e4..24b4282538d 100644
--- a/tests/ui/wf/wf-struct-bound.stderr
+++ b/tests/ui/wf/wf-struct-bound.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `ExtraCopy`
    |
 LL | trait ExtraCopy<T:Copy> { }
    |                   ^^^^ required by this bound in `ExtraCopy`
-help: consider further restricting type parameter `U`
+help: consider further restricting type parameter `U` with trait `Copy`
    |
 LL |     where T: ExtraCopy<U>, U: std::marker::Copy
    |                          ++++++++++++++++++++++
diff --git a/tests/ui/wf/wf-struct-field.stderr b/tests/ui/wf/wf-struct-field.stderr
index 241ced3c2db..4449b71bd88 100644
--- a/tests/ui/wf/wf-struct-field.stderr
+++ b/tests/ui/wf/wf-struct-field.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `IsCopy`
    |
 LL | struct IsCopy<T:Copy> {
    |                 ^^^^ required by this bound in `IsCopy`
-help: consider restricting type parameter `A`
+help: consider restricting type parameter `A` with trait `Copy`
    |
 LL | struct SomeStruct<A: std::marker::Copy> {
    |                    +++++++++++++++++++
diff --git a/tests/ui/wf/wf-trait-associated-type-bound.stderr b/tests/ui/wf/wf-trait-associated-type-bound.stderr
index 4ea895a9b03..fe6a848f866 100644
--- a/tests/ui/wf/wf-trait-associated-type-bound.stderr
+++ b/tests/ui/wf/wf-trait-associated-type-bound.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `ExtraCopy`
    |
 LL | trait ExtraCopy<T:Copy> { }
    |                   ^^^^ required by this bound in `ExtraCopy`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | trait SomeTrait<T: std::marker::Copy> {
    |                  +++++++++++++++++++
diff --git a/tests/ui/wf/wf-trait-bound.stderr b/tests/ui/wf/wf-trait-bound.stderr
index 5845d05b38e..0a8d9aa7be8 100644
--- a/tests/ui/wf/wf-trait-bound.stderr
+++ b/tests/ui/wf/wf-trait-bound.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `ExtraCopy`
    |
 LL | trait ExtraCopy<T:Copy> { }
    |                   ^^^^ required by this bound in `ExtraCopy`
-help: consider further restricting type parameter `U`
+help: consider further restricting type parameter `U` with trait `Copy`
    |
 LL |     where T: ExtraCopy<U>, U: std::marker::Copy
    |                          ++++++++++++++++++++++
diff --git a/tests/ui/wf/wf-trait-superbound.stderr b/tests/ui/wf/wf-trait-superbound.stderr
index 3c05065e57f..9b0205bfe39 100644
--- a/tests/ui/wf/wf-trait-superbound.stderr
+++ b/tests/ui/wf/wf-trait-superbound.stderr
@@ -9,7 +9,7 @@ note: required by a bound in `ExtraCopy`
    |
 LL | trait ExtraCopy<T:Copy> { }
    |                   ^^^^ required by this bound in `ExtraCopy`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | trait SomeTrait<T: std::marker::Copy>: ExtraCopy<T> {
    |                  +++++++++++++++++++
diff --git a/tests/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr b/tests/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr
index 2612cefef28..955ec18f465 100644
--- a/tests/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr
+++ b/tests/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr
@@ -11,7 +11,7 @@ note: required by a bound in `require_copy`
    |
 LL | fn require_copy<T: Copy>(x: T) {}
    |                    ^^^^ required by this bound in `require_copy`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | impl<T: std::marker::Copy> Foo<T> {
    |       +++++++++++++++++++
diff --git a/tests/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr b/tests/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr
index 090df26a39e..793851a2871 100644
--- a/tests/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr
+++ b/tests/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr
@@ -11,7 +11,7 @@ note: required by a bound in `require_copy`
    |
 LL | fn require_copy<T: Copy>(x: T) {}
    |                    ^^^^ required by this bound in `require_copy`
-help: consider restricting type parameter `T`
+help: consider restricting type parameter `T` with trait `Copy`
    |
 LL | impl<T: std::marker::Copy> Foo<T> for Bar<T> {
    |       +++++++++++++++++++
diff --git a/triagebot.toml b/triagebot.toml
index 4d6806711fb..c5dbd538f6c 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -644,7 +644,7 @@ cc = ["@rust-lang/wg-const-eval"]
 message = "Some changes occurred to the CTFE / Miri interpreter"
 cc = ["@rust-lang/miri"]
 
-[mentions."compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs"]
+[mentions."compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs"]
 message = "Some changes occurred in need_type_info.rs"
 cc = ["@lcnr"]
 
@@ -656,7 +656,7 @@ cc = ["@compiler-errors", "@lcnr"]
 message = "changes to the core type system"
 cc = ["@compiler-errors", "@lcnr"]
 
-[mentions."compiler/rustc_hir_analysis/src/fn_ctxt/inspect_obligations.rs"]
+[mentions."compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs"]
 message = "changes to `inspect_obligations.rs`"
 cc = ["@compiler-errors", "@lcnr"]
 
@@ -761,10 +761,6 @@ cc = [
     "@jsha",
 ]
 
-[mentions."src/librustdoc/html/static/css/themes"]
-message = "Some changes occurred in HTML/CSS themes."
-cc = ["@GuillaumeGomez"]
-
 [mentions."tests/rustdoc-gui/"]
 message = "Some changes occurred in GUI tests."
 cc = ["@GuillaumeGomez"]
@@ -779,10 +775,6 @@ directly, or you can comment on the tracking issue and link this PR.
 """
 cc = ["@jieyouxu"]
 
-[mentions."src/librustdoc/html/static/css/themes/ayu.css"]
-message = "A change occurred in the Ayu theme."
-cc = ["@Cldfire"]
-
 [mentions."src/rustdoc-json-types"]
 message = """
 rustdoc-json-types is a **public** (although nightly-only) API. \