about summary refs log tree commit diff
diff options
context:
space:
mode:
-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_const_eval/src/check_consts/ops.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs45
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0751.md2
-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_hir_analysis/src/hir_ty_lowering/mod.rs3
-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/ty/context.rs4
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs126
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs8
-rw-r--r--compiler/rustc_mir_build/src/thir/constant.rs6
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs24
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs8
-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_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--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs9
-rw-r--r--compiler/rustc_type_ir/src/inherent.rs3
-rw-r--r--compiler/rustc_type_ir/src/interner.rs3
-rw-r--r--library/core/src/intrinsics/mod.rs66
-rw-r--r--library/core/src/iter/traits/collect.rs239
-rw-r--r--library/core/tests/iter/traits/iterator.rs13
-rw-r--r--library/std/src/io/error.rs18
-rw-r--r--library/std/src/io/error/repr_bitpacked.rs2
-rw-r--r--library/std/src/sys/pal/teeos/mod.rs2
-rw-r--r--library/std/src/sys/pal/unix/mod.rs2
-rw-r--r--library/std/src/sys/pal/windows/mod.rs4
-rw-r--r--library/std/src/thread/local.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs37
-rw-r--r--src/librustdoc/clean/types.rs13
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs2
-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/src/shims/io_error.rs2
-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/123809.rs4
-rw-r--r--tests/crashes/131451.rs9
-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/associated-consts/assoc-const-eq-ambiguity.stderr6
-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/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/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/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/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/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/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/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/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/unsafe-fields/auto-traits.current.stderr17
-rw-r--r--tests/ui/unsafe-fields/auto-traits.next.stderr17
-rw-r--r--tests/ui/unsafe-fields/auto-traits.rs26
-rw-r--r--tests/ui/unsafe-fields/auxiliary/unsafe-fields-crate-dep.rs (renamed from tests/ui/auxiliary/unsafe-fields-crate-dep.rs)0
-rw-r--r--tests/ui/unsafe-fields/unsafe-fields-crate.rs (renamed from tests/ui/unsafe-fields-crate.rs)0
-rw-r--r--tests/ui/unsafe-fields/unsafe-fields-crate.stderr (renamed from tests/ui/unsafe-fields-crate.stderr)0
-rw-r--r--tests/ui/unsafe-fields/unsafe-fields-parse.rs (renamed from tests/ui/unsafe-fields-parse.rs)0
-rw-r--r--tests/ui/unsafe-fields/unsafe-fields-parse.stderr (renamed from tests/ui/unsafe-fields-parse.stderr)0
-rw-r--r--tests/ui/unsafe-fields/unsafe-fields.rs (renamed from tests/ui/unsafe-fields.rs)0
-rw-r--r--tests/ui/unsafe-fields/unsafe-fields.stderr (renamed from tests/ui/unsafe-fields.stderr)0
-rw-r--r--tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs4
-rw-r--r--tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr71
-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
270 files changed, 2174 insertions, 1054 deletions
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_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_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_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_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 7ab254e5f4b..3313339abb3 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -998,6 +998,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                                         self.lower_const_arg(ct, FeedConstTy::No).into()
                                     }
                                 };
+                                if term.references_error() {
+                                    continue;
+                                }
                                 // FIXME(#97583): This isn't syntactically well-formed!
                                 where_bounds.push(format!(
                                     "        T: {trait}::{assoc_name} = {term}",
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/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 3cbb2a3acf5..d4835bb07f6 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -585,6 +585,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         self.trait_def(trait_def_id).implement_via_object
     }
 
+    fn trait_is_unsafe(self, trait_def_id: Self::DefId) -> bool {
+        self.trait_def(trait_def_id).safety == hir::Safety::Unsafe
+    }
+
     fn is_impl_trait_in_trait(self, def_id: DefId) -> bool {
         self.is_impl_trait_in_trait(def_id)
     }
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_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 142db8a17f0..474062218c9 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -978,6 +978,14 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
     fn async_destructor_ty(self, interner: TyCtxt<'tcx>) -> Ty<'tcx> {
         self.async_destructor_ty(interner)
     }
+
+    fn has_unsafe_fields(self) -> bool {
+        if let ty::Adt(adt_def, ..) = self.kind() {
+            adt_def.all_fields().any(|x| x.safety == hir::Safety::Unsafe)
+        } else {
+            false
+        }
+    }
 }
 
 /// Type utilities
diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs
index 3fa0e4def82..30b6718683b 100644
--- a/compiler/rustc_mir_build/src/thir/constant.rs
+++ b/compiler/rustc_mir_build/src/thir/constant.rs
@@ -2,7 +2,7 @@ use rustc_ast as ast;
 use rustc_hir::LangItem;
 use rustc_middle::bug;
 use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
-use rustc_middle::ty::{self, ScalarInt, TyCtxt};
+use rustc_middle::ty::{self, ScalarInt, TyCtxt, TypeVisitableExt as _};
 use tracing::trace;
 
 use crate::build::parse_float_into_scalar;
@@ -13,6 +13,10 @@ pub(crate) fn lit_to_const<'tcx>(
 ) -> Result<ty::Const<'tcx>, LitToConstError> {
     let LitToConstInput { lit, ty, neg } = lit_input;
 
+    if let Err(guar) = ty.error_reported() {
+        return Ok(ty::Const::new_error(tcx, guar));
+    }
+
     let trunc = |n| {
         let width = match tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) {
             Ok(layout) => layout.size,
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 3ac53fa6272..2dbc8b7b573 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -626,32 +626,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
     ) -> PatKind<'tcx> {
         let tcx = self.tcx;
         let def_id = block.def_id;
-        let body_id = block.body;
-        let expr = &tcx.hir().body(body_id).value;
         let ty = tcx.typeck(def_id).node_type(block.hir_id);
 
-        // Special case inline consts that are just literals. This is solely
-        // a performance optimization, as we could also just go through the regular
-        // const eval path below.
-        // FIXME: investigate the performance impact of removing this.
-        let lit_input = match expr.kind {
-            hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
-            hir::ExprKind::Unary(hir::UnOp::Neg, expr) => match expr.kind {
-                hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: true }),
-                _ => None,
-            },
-            _ => None,
-        };
-        if let Some(lit_input) = lit_input {
-            match tcx.at(expr.span).lit_to_const(lit_input) {
-                Ok(c) => return self.const_to_pat(c, ty, id, span).kind,
-                // If an error occurred, ignore that it's a literal
-                // and leave reporting the error up to const eval of
-                // the unevaluated constant below.
-                Err(_) => {}
-            }
-        }
-
         let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id());
         let parent_args =
             tcx.erase_regions(ty::GenericArgs::identity_for_item(tcx, typeck_root_def_id));
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index 6641d2bf924..12df35d30b8 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -169,6 +169,14 @@ where
             return result;
         }
 
+        // Only consider auto impls of unsafe traits when there are no unsafe
+        // fields.
+        if ecx.cx().trait_is_unsafe(goal.predicate.def_id())
+            && goal.predicate.self_ty().has_unsafe_fields()
+        {
+            return Err(NoSolution);
+        }
+
         // We only look into opaque types during analysis for opaque types
         // outside of their defining scope. Doing so for opaques in the
         // defining scope may require calling `typeck` on the same item we're
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_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/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 32b4567aba4..3e2c8467d32 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -18,6 +18,7 @@ use rustc_infer::traits::{
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
 use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt, TypingMode};
 use rustc_middle::{bug, span_bug};
+use rustc_type_ir::Interner;
 use tracing::{debug, instrument, trace};
 
 use super::SelectionCandidate::*;
@@ -794,6 +795,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 | ty::Never
                 | ty::Tuple(_)
                 | ty::CoroutineWitness(..) => {
+                    use rustc_type_ir::inherent::*;
+
+                    // Only consider auto impls of unsafe traits when there are
+                    // no unsafe fields.
+                    if self.tcx().trait_is_unsafe(def_id) && self_ty.has_unsafe_fields() {
+                        return;
+                    }
+
                     // Only consider auto impls if there are no manual impls for the root of `self_ty`.
                     //
                     // For example, we only consider auto candidates for `&i32: Auto` if no explicit impl
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index a201f2b1c11..f45c94127bd 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -136,6 +136,9 @@ pub trait Ty<I: Interner<Ty = Self>>:
         matches!(self.kind(), ty::FnPtr(..))
     }
 
+    /// Checks whether this type is an ADT that has unsafe fields.
+    fn has_unsafe_fields(self) -> bool;
+
     fn fn_sig(self, interner: I) -> ty::Binder<I, ty::FnSig<I>> {
         match self.kind() {
             ty::FnPtr(sig_tys, hdr) => sig_tys.with(hdr),
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index 0ae688848eb..025ec7ae896 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -270,6 +270,9 @@ pub trait Interner:
 
     fn trait_may_be_implemented_via_object(self, trait_def_id: Self::DefId) -> bool;
 
+    /// Returns `true` if this is an `unsafe trait`.
+    fn trait_is_unsafe(self, trait_def_id: Self::DefId) -> bool;
+
     fn is_impl_trait_in_trait(self, def_id: Self::DefId) -> bool;
 
     fn delay_bug(self, msg: impl ToString) -> Self::ErrorGuaranteed;
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/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs
index 2cf2ea58fd4..c3c7288e389 100644
--- a/library/core/src/iter/traits/collect.rs
+++ b/library/core/src/iter/traits/collect.rs
@@ -492,131 +492,150 @@ impl Extend<()> for () {
     fn extend_one(&mut self, _item: ()) {}
 }
 
-#[stable(feature = "extend_for_tuple", since = "1.56.0")]
-impl<A, B, ExtendA, ExtendB> Extend<(A, B)> for (ExtendA, ExtendB)
-where
-    ExtendA: Extend<A>,
-    ExtendB: Extend<B>,
-{
-    /// Allows to `extend` a tuple of collections that also implement `Extend`.
-    ///
-    /// See also: [`Iterator::unzip`]
-    ///
-    /// # Examples
-    /// ```
-    /// let mut tuple = (vec![0], vec![1]);
-    /// tuple.extend([(2, 3), (4, 5), (6, 7)]);
-    /// assert_eq!(tuple.0, [0, 2, 4, 6]);
-    /// assert_eq!(tuple.1, [1, 3, 5, 7]);
-    ///
-    /// // also allows for arbitrarily nested tuples as elements
-    /// let mut nested_tuple = (vec![1], (vec![2], vec![3]));
-    /// nested_tuple.extend([(4, (5, 6)), (7, (8, 9))]);
-    ///
-    /// let (a, (b, c)) = nested_tuple;
-    /// assert_eq!(a, [1, 4, 7]);
-    /// assert_eq!(b, [2, 5, 8]);
-    /// assert_eq!(c, [3, 6, 9]);
-    /// ```
-    fn extend<T: IntoIterator<Item = (A, B)>>(&mut self, into_iter: T) {
-        let (a, b) = self;
-        let iter = into_iter.into_iter();
-        SpecTupleExtend::extend(iter, a, b);
-    }
+macro_rules! spec_tuple_impl {
+    ( ($ty_name:ident, $var_name:ident, $extend_ty_name: ident, $trait_name:ident, $default_fn_name:ident, $cnt:tt), ) => {
+        spec_tuple_impl!($trait_name, $default_fn_name, #[doc(fake_variadic)] #[doc = "This trait is implemented for tuples up to twelve items long. The `impl`s for 1- and 3- through 12-ary tuples were stabilized after 2-tuples, in RUSTC_CURRENT_VERSION."] => ($ty_name, $var_name, $extend_ty_name, $cnt),);
+    };
+    ( ($ty_name:ident, $var_name:ident, $extend_ty_name: ident, $trait_name:ident, $default_fn_name:ident, $cnt:tt), $(($ty_names:ident, $var_names:ident,  $extend_ty_names:ident, $trait_names:ident, $default_fn_names:ident, $cnts:tt),)*) => {
 
-    fn extend_one(&mut self, item: (A, B)) {
-        self.0.extend_one(item.0);
-        self.1.extend_one(item.1);
-    }
+        spec_tuple_impl!($(($ty_names, $var_names, $extend_ty_names, $trait_names, $default_fn_names, $cnts),)*);
+        spec_tuple_impl!($trait_name, $default_fn_name, #[doc(hidden)] => ($ty_name, $var_name, $extend_ty_name, $cnt), $(($ty_names, $var_names, $extend_ty_names, $cnts),)*);
+    };
+    ($trait_name:ident, $default_fn_name:ident, #[$meta:meta] $(#[$doctext:meta])? => $(($ty_names:ident, $var_names:ident, $extend_ty_names:ident, $cnts:tt),)*) => {
+        #[$meta]
+        $(#[$doctext])?
+        #[stable(feature = "extend_for_tuple", since = "1.56.0")]
+        impl<$($ty_names,)* $($extend_ty_names,)*> Extend<($($ty_names,)*)> for ($($extend_ty_names,)*)
+        where
+            $($extend_ty_names: Extend<$ty_names>,)*
+        {
+            /// Allows to `extend` a tuple of collections that also implement `Extend`.
+            ///
+            /// See also: [`Iterator::unzip`]
+            ///
+            /// # Examples
+            /// ```
+            /// // Example given for a 2-tuple, but 1- through 12-tuples are supported
+            /// let mut tuple = (vec![0], vec![1]);
+            /// tuple.extend([(2, 3), (4, 5), (6, 7)]);
+            /// assert_eq!(tuple.0, [0, 2, 4, 6]);
+            /// assert_eq!(tuple.1, [1, 3, 5, 7]);
+            ///
+            /// // also allows for arbitrarily nested tuples as elements
+            /// let mut nested_tuple = (vec![1], (vec![2], vec![3]));
+            /// nested_tuple.extend([(4, (5, 6)), (7, (8, 9))]);
+            ///
+            /// let (a, (b, c)) = nested_tuple;
+            /// assert_eq!(a, [1, 4, 7]);
+            /// assert_eq!(b, [2, 5, 8]);
+            /// assert_eq!(c, [3, 6, 9]);
+            /// ```
+            fn extend<T: IntoIterator<Item = ($($ty_names,)*)>>(&mut self, into_iter: T) {
+                let ($($var_names,)*) = self;
+                let iter = into_iter.into_iter();
+                $trait_name::extend(iter, $($var_names,)*);
+            }
 
-    fn extend_reserve(&mut self, additional: usize) {
-        self.0.extend_reserve(additional);
-        self.1.extend_reserve(additional);
-    }
+            fn extend_one(&mut self, item: ($($ty_names,)*)) {
+                $(self.$cnts.extend_one(item.$cnts);)*
+            }
 
-    unsafe fn extend_one_unchecked(&mut self, item: (A, B)) {
-        // SAFETY: Those are our safety preconditions, and we correctly forward `extend_reserve`.
-        unsafe {
-            self.0.extend_one_unchecked(item.0);
-            self.1.extend_one_unchecked(item.1);
-        }
-    }
-}
+            fn extend_reserve(&mut self, additional: usize) {
+                $(self.$cnts.extend_reserve(additional);)*
+            }
 
-fn default_extend_tuple<A, B, ExtendA, ExtendB>(
-    iter: impl Iterator<Item = (A, B)>,
-    a: &mut ExtendA,
-    b: &mut ExtendB,
-) where
-    ExtendA: Extend<A>,
-    ExtendB: Extend<B>,
-{
-    fn extend<'a, A, B>(
-        a: &'a mut impl Extend<A>,
-        b: &'a mut impl Extend<B>,
-    ) -> impl FnMut((), (A, B)) + 'a {
-        move |(), (t, u)| {
-            a.extend_one(t);
-            b.extend_one(u);
+            unsafe fn extend_one_unchecked(&mut self, item: ($($ty_names,)*)) {
+                // SAFETY: Those are our safety preconditions, and we correctly forward `extend_reserve`.
+                unsafe {
+                     $(self.$cnts.extend_one_unchecked(item.$cnts);)*
+                }
+            }
         }
-    }
 
-    let (lower_bound, _) = iter.size_hint();
-    if lower_bound > 0 {
-        a.extend_reserve(lower_bound);
-        b.extend_reserve(lower_bound);
-    }
+        trait $trait_name<$($ty_names),*> {
+            fn extend(self, $($var_names: &mut $ty_names,)*);
+        }
 
-    iter.fold((), extend(a, b));
-}
+        fn $default_fn_name<$($ty_names,)* $($extend_ty_names,)*>(
+            iter: impl Iterator<Item = ($($ty_names,)*)>,
+            $($var_names: &mut $extend_ty_names,)*
+        ) where
+            $($extend_ty_names: Extend<$ty_names>,)*
+        {
+            fn extend<'a, $($ty_names,)*>(
+                $($var_names: &'a mut impl Extend<$ty_names>,)*
+            ) -> impl FnMut((), ($($ty_names,)*)) + 'a {
+                #[allow(non_snake_case)]
+                move |(), ($($extend_ty_names,)*)| {
+                    $($var_names.extend_one($extend_ty_names);)*
+                }
+            }
 
-trait SpecTupleExtend<A, B> {
-    fn extend(self, a: &mut A, b: &mut B);
-}
+            let (lower_bound, _) = iter.size_hint();
+            if lower_bound > 0 {
+                $($var_names.extend_reserve(lower_bound);)*
+            }
 
-impl<A, B, ExtendA, ExtendB, Iter> SpecTupleExtend<ExtendA, ExtendB> for Iter
-where
-    ExtendA: Extend<A>,
-    ExtendB: Extend<B>,
-    Iter: Iterator<Item = (A, B)>,
-{
-    default fn extend(self, a: &mut ExtendA, b: &mut ExtendB) {
-        default_extend_tuple(self, a, b);
-    }
-}
+            iter.fold((), extend($($var_names,)*));
+        }
 
-impl<A, B, ExtendA, ExtendB, Iter> SpecTupleExtend<ExtendA, ExtendB> for Iter
-where
-    ExtendA: Extend<A>,
-    ExtendB: Extend<B>,
-    Iter: TrustedLen<Item = (A, B)>,
-{
-    fn extend(self, a: &mut ExtendA, b: &mut ExtendB) {
-        fn extend<'a, A, B>(
-            a: &'a mut impl Extend<A>,
-            b: &'a mut impl Extend<B>,
-        ) -> impl FnMut((), (A, B)) + 'a {
-            // SAFETY: We reserve enough space for the `size_hint`, and the iterator is `TrustedLen`
-            // so its `size_hint` is exact.
-            move |(), (t, u)| unsafe {
-                a.extend_one_unchecked(t);
-                b.extend_one_unchecked(u);
+        impl<$($ty_names,)* $($extend_ty_names,)* Iter> $trait_name<$($extend_ty_names),*> for Iter
+            where
+            $($extend_ty_names: Extend<$ty_names>,)*
+            Iter: Iterator<Item = ($($ty_names,)*)>,
+        {
+            default fn extend(self, $($var_names: &mut $extend_ty_names),*) {
+                $default_fn_name(self, $($var_names),*);
             }
         }
 
-        let (lower_bound, upper_bound) = self.size_hint();
+        impl<$($ty_names,)* $($extend_ty_names,)* Iter> $trait_name<$($extend_ty_names),*> for Iter
+            where
+            $($extend_ty_names: Extend<$ty_names>,)*
+            Iter: TrustedLen<Item = ($($ty_names,)*)>,
+        {
+            fn extend(self, $($var_names: &mut $extend_ty_names,)*) {
+                fn extend<'a, $($ty_names,)*>(
+                    $($var_names: &'a mut impl Extend<$ty_names>,)*
+                ) -> impl FnMut((), ($($ty_names,)*)) + 'a {
+                #[allow(non_snake_case)]
+                // SAFETY: We reserve enough space for the `size_hint`, and the iterator is `TrustedLen`
+                // so its `size_hint` is exact.
+                move |(), ($($extend_ty_names,)*)| unsafe {
+                    $($var_names.extend_one_unchecked($extend_ty_names);)*
+                }
+            }
 
-        if upper_bound.is_none() {
-            // We cannot reserve more than `usize::MAX` items, and this is likely to go out of memory anyway.
-            default_extend_tuple(self, a, b);
-            return;
-        }
+            let (lower_bound, upper_bound) = self.size_hint();
 
-        if lower_bound > 0 {
-            a.extend_reserve(lower_bound);
-            b.extend_reserve(lower_bound);
-        }
+            if upper_bound.is_none() {
+                // We cannot reserve more than `usize::MAX` items, and this is likely to go out of memory anyway.
+                $default_fn_name(self, $($var_names,)*);
+                return;
+            }
 
-        self.fold((), extend(a, b));
+            if lower_bound > 0 {
+                $($var_names.extend_reserve(lower_bound);)*
+            }
+
+            self.fold((), extend($($var_names,)*));
+        }
     }
+
+    };
 }
+
+spec_tuple_impl!(
+    (L, l, EL, TraitL, default_extend_tuple_l, 11),
+    (K, k, EK, TraitK, default_extend_tuple_k, 10),
+    (J, j, EJ, TraitJ, default_extend_tuple_j, 9),
+    (I, i, EI, TraitI, default_extend_tuple_i, 8),
+    (H, h, EH, TraitH, default_extend_tuple_h, 7),
+    (G, g, EG, TraitG, default_extend_tuple_g, 6),
+    (F, f, EF, TraitF, default_extend_tuple_f, 5),
+    (E, e, EE, TraitE, default_extend_tuple_e, 4),
+    (D, d, ED, TraitD, default_extend_tuple_d, 3),
+    (C, c, EC, TraitC, default_extend_tuple_c, 2),
+    (B, b, EB, TraitB, default_extend_tuple_b, 1),
+    (A, a, EA, TraitA, default_extend_tuple_a, 0),
+);
diff --git a/library/core/tests/iter/traits/iterator.rs b/library/core/tests/iter/traits/iterator.rs
index 93ef9c0812b..76f1e3319d4 100644
--- a/library/core/tests/iter/traits/iterator.rs
+++ b/library/core/tests/iter/traits/iterator.rs
@@ -617,6 +617,19 @@ fn test_next_chunk() {
     assert_eq!(it.next_chunk::<0>().unwrap(), []);
 }
 
+#[test]
+fn test_collect_into_tuples() {
+    let a = vec![(1, 2, 3), (4, 5, 6), (7, 8, 9)];
+    let b = vec![1, 4, 7];
+    let c = vec![2, 5, 8];
+    let d = vec![3, 6, 9];
+    let mut e = (Vec::new(), Vec::new(), Vec::new());
+    a.iter().cloned().collect_into(&mut e);
+    assert!(e.0 == b);
+    assert!(e.1 == c);
+    assert!(e.2 == d);
+}
+
 // just tests by whether or not this compiles
 fn _empty_impl_all_auto_traits<T>() {
     use std::panic::{RefUnwindSafe, UnwindSafe};
diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs
index 03f38e220a5..476c403c21f 100644
--- a/library/std/src/io/error.rs
+++ b/library/std/src/io/error.rs
@@ -338,9 +338,9 @@ pub enum ErrorKind {
     /// example, on Unix, a named pipe opened with `File::open`.
     #[stable(feature = "io_error_a_bit_more", since = "1.83.0")]
     NotSeekable,
-    /// Filesystem quota was exceeded.
-    #[unstable(feature = "io_error_more", issue = "86442")]
-    FilesystemQuotaExceeded,
+    /// Filesystem quota or some other kind of quota was exceeded.
+    #[stable(feature = "io_error_quota_exceeded", since = "CURRENT_RUSTC_VERSION")]
+    QuotaExceeded,
     /// File larger than allowed or supported.
     ///
     /// This might arise from a hard limit of the underlying filesystem or file access API, or from
@@ -364,7 +364,7 @@ pub enum ErrorKind {
     #[stable(feature = "io_error_a_bit_more", since = "1.83.0")]
     Deadlock,
     /// Cross-device or cross-filesystem (hard) link or rename.
-    #[unstable(feature = "io_error_more", issue = "86442")]
+    #[stable(feature = "io_error_crosses_devices", since = "CURRENT_RUSTC_VERSION")]
     CrossesDevices,
     /// Too many (hard) links to the same filesystem object.
     ///
@@ -446,8 +446,8 @@ pub enum ErrorKind {
 impl ErrorKind {
     pub(crate) fn as_str(&self) -> &'static str {
         use ErrorKind::*;
-        // tidy-alphabetical-start
         match *self {
+            // tidy-alphabetical-start
             AddrInUse => "address in use",
             AddrNotAvailable => "address not available",
             AlreadyExists => "entity already exists",
@@ -460,12 +460,11 @@ impl ErrorKind {
             Deadlock => "deadlock",
             DirectoryNotEmpty => "directory not empty",
             ExecutableFileBusy => "executable file busy",
-            FileTooLarge => "file too large",
             FilesystemLoop => "filesystem loop or indirection limit (e.g. symlink loop)",
-            FilesystemQuotaExceeded => "filesystem quota exceeded",
+            FileTooLarge => "file too large",
             HostUnreachable => "host unreachable",
-            Interrupted => "operation interrupted",
             InProgress => "in progress",
+            Interrupted => "operation interrupted",
             InvalidData => "invalid data",
             InvalidFilename => "invalid filename",
             InvalidInput => "invalid input parameter",
@@ -479,6 +478,7 @@ impl ErrorKind {
             Other => "other error",
             OutOfMemory => "out of memory",
             PermissionDenied => "permission denied",
+            QuotaExceeded => "quota exceeded",
             ReadOnlyFilesystem => "read-only filesystem or storage medium",
             ResourceBusy => "resource busy",
             StaleNetworkFileHandle => "stale network file handle",
@@ -490,8 +490,8 @@ impl ErrorKind {
             Unsupported => "unsupported",
             WouldBlock => "operation would block",
             WriteZero => "write zero",
+            // tidy-alphabetical-end
         }
-        // tidy-alphabetical-end
     }
 }
 
diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs
index a839a2fbac1..f958a938646 100644
--- a/library/std/src/io/error/repr_bitpacked.rs
+++ b/library/std/src/io/error/repr_bitpacked.rs
@@ -335,7 +335,7 @@ fn kind_from_prim(ek: u32) -> Option<ErrorKind> {
         WriteZero,
         StorageFull,
         NotSeekable,
-        FilesystemQuotaExceeded,
+        QuotaExceeded,
         FileTooLarge,
         ResourceBusy,
         ExecutableFileBusy,
diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs
index 2bf2e2ceb31..a9900f55b19 100644
--- a/library/std/src/sys/pal/teeos/mod.rs
+++ b/library/std/src/sys/pal/teeos/mod.rs
@@ -71,7 +71,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
         libc::ECONNREFUSED => ConnectionRefused,
         libc::ECONNRESET => ConnectionReset,
         libc::EDEADLK => Deadlock,
-        libc::EDQUOT => FilesystemQuotaExceeded,
+        libc::EDQUOT => QuotaExceeded,
         libc::EEXIST => AlreadyExists,
         libc::EFBIG => FileTooLarge,
         libc::EHOSTUNREACH => HostUnreachable,
diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs
index 8eaa50d7f81..3cc1cae8d00 100644
--- a/library/std/src/sys/pal/unix/mod.rs
+++ b/library/std/src/sys/pal/unix/mod.rs
@@ -254,7 +254,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
         libc::ECONNREFUSED => ConnectionRefused,
         libc::ECONNRESET => ConnectionReset,
         libc::EDEADLK => Deadlock,
-        libc::EDQUOT => FilesystemQuotaExceeded,
+        libc::EDQUOT => QuotaExceeded,
         libc::EEXIST => AlreadyExists,
         libc::EFBIG => FileTooLarge,
         libc::EHOSTUNREACH => HostUnreachable,
diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs
index d66ff15e10b..88e6def7a75 100644
--- a/library/std/src/sys/pal/windows/mod.rs
+++ b/library/std/src/sys/pal/windows/mod.rs
@@ -113,7 +113,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
         c::ERROR_WRITE_PROTECT => return ReadOnlyFilesystem,
         c::ERROR_DISK_FULL | c::ERROR_HANDLE_DISK_FULL => return StorageFull,
         c::ERROR_SEEK_ON_DEVICE => return NotSeekable,
-        c::ERROR_DISK_QUOTA_EXCEEDED => return FilesystemQuotaExceeded,
+        c::ERROR_DISK_QUOTA_EXCEEDED => return QuotaExceeded,
         c::ERROR_FILE_TOO_LARGE => return FileTooLarge,
         c::ERROR_BUSY => return ResourceBusy,
         c::ERROR_POSSIBLE_DEADLOCK => return Deadlock,
@@ -138,7 +138,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
         c::WSAEHOSTUNREACH => HostUnreachable,
         c::WSAENETDOWN => NetworkDown,
         c::WSAENETUNREACH => NetworkUnreachable,
-        c::WSAEDQUOT => FilesystemQuotaExceeded,
+        c::WSAEDQUOT => QuotaExceeded,
 
         _ => Uncategorized,
     }
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/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 161157acffe..30fdea7e19e 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -1070,23 +1070,33 @@ impl Step for Tidy {
         }
 
         if builder.config.channel == "dev" || builder.config.channel == "nightly" {
-            builder.info("fmt check");
-            if builder.initial_rustfmt().is_none() {
-                let inferred_rustfmt_dir = builder.initial_sysroot.join("bin");
-                eprintln!(
-                    "\
+            if !builder.config.json_output {
+                builder.info("fmt check");
+                if builder.initial_rustfmt().is_none() {
+                    let inferred_rustfmt_dir = builder.initial_sysroot.join("bin");
+                    eprintln!(
+                        "\
 ERROR: no `rustfmt` binary found in {PATH}
 INFO: `rust.channel` is currently set to \"{CHAN}\"
 HELP: if you are testing a beta branch, set `rust.channel` to \"beta\" in the `config.toml` file
 HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to `x.py test`",
-                    PATH = inferred_rustfmt_dir.display(),
-                    CHAN = builder.config.channel,
+                        PATH = inferred_rustfmt_dir.display(),
+                        CHAN = builder.config.channel,
+                    );
+                    crate::exit!(1);
+                }
+                let all = false;
+                crate::core::build_steps::format::format(
+                    builder,
+                    !builder.config.cmd.bless(),
+                    all,
+                    &[],
+                );
+            } else {
+                eprintln!(
+                    "WARNING: `--json-output` is not supported on rustfmt, formatting will be skipped"
                 );
-                crate::exit!(1);
             }
-            let all = false;
-            crate::core::build_steps::format::format(builder, !builder.config.cmd.bless(), all, &[
-            ]);
         }
 
         builder.info("tidy check");
@@ -2624,6 +2634,11 @@ fn prepare_cargo_test(
     if builder.kind == Kind::Test && !builder.fail_fast {
         cargo.arg("--no-fail-fast");
     }
+
+    if builder.config.json_output {
+        cargo.arg("--message-format=json");
+    }
+
     match builder.doc_tests {
         DocTests::Only => {
             cargo.arg("--doc");
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 715bf68374a..cba947eb833 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1241,19 +1241,6 @@ impl Attributes {
     }
 }
 
-impl PartialEq for Attributes {
-    fn eq(&self, rhs: &Self) -> bool {
-        self.doc_strings == rhs.doc_strings
-            && self
-                .other_attrs
-                .iter()
-                .map(|attr| attr.id)
-                .eq(rhs.other_attrs.iter().map(|attr| attr.id))
-    }
-}
-
-impl Eq for Attributes {}
-
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub(crate) enum GenericBound {
     TraitBound(PolyTrait, hir::TraitBoundModifiers),
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 05f54fdc34310f458033af8a63ce1d699fae8bf
+Subproject 20a443231846b81c7b909691ec3f15eb173f2b1
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/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/src/shims/io_error.rs b/src/tools/miri/src/shims/io_error.rs
index 0cbb4850b7f..634dbd9f953 100644
--- a/src/tools/miri/src/shims/io_error.rs
+++ b/src/tools/miri/src/shims/io_error.rs
@@ -44,7 +44,7 @@ const UNIX_IO_ERROR_TABLE: &[(&str, std::io::ErrorKind)] = {
         ("ECONNREFUSED", ConnectionRefused),
         ("ECONNRESET", ConnectionReset),
         ("EDEADLK", Deadlock),
-        ("EDQUOT", FilesystemQuotaExceeded),
+        ("EDQUOT", QuotaExceeded),
         ("EEXIST", AlreadyExists),
         ("EFBIG", FileTooLarge),
         ("EHOSTUNREACH", HostUnreachable),
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/123809.rs b/tests/crashes/123809.rs
deleted file mode 100644
index 75abe6dc0cd..00000000000
--- a/tests/crashes/123809.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-//@ known-bug: #123809
-type Positive = std::pat::pattern_type!(std::pat is 0..);
-
-pub fn main() {}
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/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/associated-consts/assoc-const-eq-ambiguity.stderr b/tests/ui/associated-consts/assoc-const-eq-ambiguity.stderr
index ba3a8701316..aa1db4cb032 100644
--- a/tests/ui/associated-consts/assoc-const-eq-ambiguity.stderr
+++ b/tests/ui/associated-consts/assoc-const-eq-ambiguity.stderr
@@ -26,12 +26,6 @@ LL | trait Parent2 { const C: &'static str; }
 LL |
 LL | fn take1(_: impl Trait1<C = "?">) {}
    |                         ^^^^^^^ ambiguous associated constant `C`
-   |
-   = help: consider introducing a new type parameter `T` and adding `where` constraints:
-               where
-                   T: Trait1,
-                   T: Parent2::C = "?",
-                   T: Parent1::C = "?"
 
 error: aborting due to 2 previous errors
 
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/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/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/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/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/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/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/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/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/unsafe-fields/auto-traits.current.stderr b/tests/ui/unsafe-fields/auto-traits.current.stderr
new file mode 100644
index 00000000000..53a97458b7c
--- /dev/null
+++ b/tests/ui/unsafe-fields/auto-traits.current.stderr
@@ -0,0 +1,17 @@
+error[E0277]: the trait bound `UnsafeEnum: UnsafeAuto` is not satisfied
+  --> $DIR/auto-traits.rs:24:22
+   |
+LL |     impl_unsafe_auto(UnsafeEnum::Safe(42));
+   |     ---------------- ^^^^^^^^^^^^^^^^^^^^ the trait `UnsafeAuto` is not implemented for `UnsafeEnum`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `impl_unsafe_auto`
+  --> $DIR/auto-traits.rs:20:29
+   |
+LL | fn impl_unsafe_auto(_: impl UnsafeAuto) {}
+   |                             ^^^^^^^^^^ required by this bound in `impl_unsafe_auto`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/unsafe-fields/auto-traits.next.stderr b/tests/ui/unsafe-fields/auto-traits.next.stderr
new file mode 100644
index 00000000000..53a97458b7c
--- /dev/null
+++ b/tests/ui/unsafe-fields/auto-traits.next.stderr
@@ -0,0 +1,17 @@
+error[E0277]: the trait bound `UnsafeEnum: UnsafeAuto` is not satisfied
+  --> $DIR/auto-traits.rs:24:22
+   |
+LL |     impl_unsafe_auto(UnsafeEnum::Safe(42));
+   |     ---------------- ^^^^^^^^^^^^^^^^^^^^ the trait `UnsafeAuto` is not implemented for `UnsafeEnum`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `impl_unsafe_auto`
+  --> $DIR/auto-traits.rs:20:29
+   |
+LL | fn impl_unsafe_auto(_: impl UnsafeAuto) {}
+   |                             ^^^^^^^^^^ required by this bound in `impl_unsafe_auto`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/unsafe-fields/auto-traits.rs b/tests/ui/unsafe-fields/auto-traits.rs
new file mode 100644
index 00000000000..e15d0000079
--- /dev/null
+++ b/tests/ui/unsafe-fields/auto-traits.rs
@@ -0,0 +1,26 @@
+//@ compile-flags: --crate-type=lib
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+
+#![feature(auto_traits)]
+#![feature(unsafe_fields)]
+#![allow(incomplete_features)]
+
+enum UnsafeEnum {
+    Safe(u8),
+    Unsafe { unsafe field: u8 },
+}
+
+auto trait SafeAuto {}
+
+fn impl_safe_auto(_: impl SafeAuto) {}
+
+unsafe auto trait UnsafeAuto {}
+
+fn impl_unsafe_auto(_: impl UnsafeAuto) {}
+
+fn tests() {
+    impl_safe_auto(UnsafeEnum::Safe(42));
+    impl_unsafe_auto(UnsafeEnum::Safe(42));
+    //~^ ERROR the trait bound `UnsafeEnum: UnsafeAuto` is not satisfied
+}
diff --git a/tests/ui/auxiliary/unsafe-fields-crate-dep.rs b/tests/ui/unsafe-fields/auxiliary/unsafe-fields-crate-dep.rs
index 95b928402a9..95b928402a9 100644
--- a/tests/ui/auxiliary/unsafe-fields-crate-dep.rs
+++ b/tests/ui/unsafe-fields/auxiliary/unsafe-fields-crate-dep.rs
diff --git a/tests/ui/unsafe-fields-crate.rs b/tests/ui/unsafe-fields/unsafe-fields-crate.rs
index cfb9ad6b544..cfb9ad6b544 100644
--- a/tests/ui/unsafe-fields-crate.rs
+++ b/tests/ui/unsafe-fields/unsafe-fields-crate.rs
diff --git a/tests/ui/unsafe-fields-crate.stderr b/tests/ui/unsafe-fields/unsafe-fields-crate.stderr
index 778c26e0a43..778c26e0a43 100644
--- a/tests/ui/unsafe-fields-crate.stderr
+++ b/tests/ui/unsafe-fields/unsafe-fields-crate.stderr
diff --git a/tests/ui/unsafe-fields-parse.rs b/tests/ui/unsafe-fields/unsafe-fields-parse.rs
index 67277731293..67277731293 100644
--- a/tests/ui/unsafe-fields-parse.rs
+++ b/tests/ui/unsafe-fields/unsafe-fields-parse.rs
diff --git a/tests/ui/unsafe-fields-parse.stderr b/tests/ui/unsafe-fields/unsafe-fields-parse.stderr
index 5a45ab03ffe..5a45ab03ffe 100644
--- a/tests/ui/unsafe-fields-parse.stderr
+++ b/tests/ui/unsafe-fields/unsafe-fields-parse.stderr
diff --git a/tests/ui/unsafe-fields.rs b/tests/ui/unsafe-fields/unsafe-fields.rs
index 637471582d7..637471582d7 100644
--- a/tests/ui/unsafe-fields.rs
+++ b/tests/ui/unsafe-fields/unsafe-fields.rs
diff --git a/tests/ui/unsafe-fields.stderr b/tests/ui/unsafe-fields/unsafe-fields.stderr
index a1c5d2b44cd..a1c5d2b44cd 100644
--- a/tests/ui/unsafe-fields.stderr
+++ b/tests/ui/unsafe-fields/unsafe-fields.stderr
diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs
index a953f1818c5..997bee1e600 100644
--- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs
+++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs
@@ -3,15 +3,11 @@ trait Foo<const N: Bar<2>> {
     //~^ WARN trait objects without an explicit `dyn` are deprecated
     //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
     //~| ERROR cycle detected when computing type of `Foo::N`
-    //~| ERROR the trait `Foo` cannot be made into an object
-    //~| ERROR `(dyn Bar<2> + 'static)` is forbidden as the type of a const generic parameter
     fn func() {}
 }
 
 trait Bar<const M: Foo<2>> {}
 //~^ WARN trait objects without an explicit `dyn` are deprecated
 //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
-//~| ERROR the trait `Foo` cannot be made into an object
-//~| ERROR `(dyn Foo<2> + 'static)` is forbidden as the type of a const generic parameter
 
 fn main() {}
diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr
index f8905437c6e..733b729faf0 100644
--- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr
+++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr
@@ -13,7 +13,7 @@ LL | trait Foo<const N: dyn Bar<2>> {
    |                    +++
 
 warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:20
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:9:20
    |
 LL | trait Bar<const M: Foo<2>> {}
    |                    ^^^^^^
@@ -32,7 +32,7 @@ LL | trait Foo<const N: Bar<2>> {
    |           ^^^^^^^^^^^^^^^
    |
 note: ...which requires computing type of `Bar::M`...
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:11
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:9:11
    |
 LL | trait Bar<const M: Foo<2>> {}
    |           ^^^^^^^^^^^^^^^
@@ -44,69 +44,6 @@ LL | trait Foo<const N: Bar<2>> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
-error[E0038]: the trait `Foo` cannot be made into an object
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:2:24
-   |
-LL | trait Foo<const N: Bar<2>> {
-   |                        ^ `Foo` cannot be made into an object
-   |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:8:8
-   |
-LL | trait Foo<const N: Bar<2>> {
-   |       --- this trait cannot be made into an object...
-...
-LL |     fn func() {}
-   |        ^^^^ ...because associated function `func` has no `self` parameter
-help: consider turning `func` into a method by giving it a `&self` argument
-   |
-LL |     fn func(&self) {}
-   |             +++++
-help: alternatively, consider constraining `func` so it does not apply to trait objects
-   |
-LL |     fn func() where Self: Sized {}
-   |               +++++++++++++++++
-
-error: `(dyn Bar<2> + 'static)` is forbidden as the type of a const generic parameter
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:2:20
-   |
-LL | trait Foo<const N: Bar<2>> {
-   |                    ^^^^^^
-   |
-   = note: the only supported types are integers, `bool`, and `char`
-
-error[E0038]: the trait `Foo` cannot be made into an object
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:11
-   |
-LL | trait Bar<const M: Foo<2>> {}
-   |           ^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
-   |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:8:8
-   |
-LL | trait Foo<const N: Bar<2>> {
-   |       --- this trait cannot be made into an object...
-...
-LL |     fn func() {}
-   |        ^^^^ ...because associated function `func` has no `self` parameter
-help: consider turning `func` into a method by giving it a `&self` argument
-   |
-LL |     fn func(&self) {}
-   |             +++++
-help: alternatively, consider constraining `func` so it does not apply to trait objects
-   |
-LL |     fn func() where Self: Sized {}
-   |               +++++++++++++++++
-
-error: `(dyn Foo<2> + 'static)` is forbidden as the type of a const generic parameter
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:20
-   |
-LL | trait Bar<const M: Foo<2>> {}
-   |                    ^^^^^^
-   |
-   = note: the only supported types are integers, `bool`, and `char`
-
-error: aborting due to 5 previous errors; 2 warnings emitted
+error: aborting due to 1 previous error; 2 warnings emitted
 
-Some errors have detailed explanations: E0038, E0391.
-For more information about an error, try `rustc --explain E0038`.
+For more information about this error, try `rustc --explain E0391`.
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> {
    |       +++++++++++++++++++