about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2019-10-07 14:23:56 -0700
committerEsteban Küber <esteban@kuber.com.ar>2019-10-15 13:55:43 -0700
commit190589f8a732393047bd0dc10b27a9aae4410944 (patch)
treeb22eab92f84259e3bea7c3f7bdbecec7f339ccb2
parent237d54ff6c4fb3577e02d4c5af02813c11b63d01 (diff)
downloadrust-190589f8a732393047bd0dc10b27a9aae4410944.tar.gz
rust-190589f8a732393047bd0dc10b27a9aae4410944.zip
Use structured suggestion for restricting bounds
When a trait bound is not met and restricting a type parameter would
make the restriction hold, use a structured suggestion pointing at an
appropriate place (type param in param list or `where` clause).

Account for opaque parameters where instead of suggesting extending
the `where` clause, we suggest appending the new restriction:
`fn foo(impl Trait + UnmetTrait)`.
-rw-r--r--src/librustc/traits/error_reporting.rs97
-rw-r--r--src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr4
-rw-r--r--src/test/ui/associated-const/associated-const-type-parameter-arrays.stderr4
-rw-r--r--src/test/ui/associated-types/associated-types-invalid-trait-ref-issue-18865.stderr4
-rw-r--r--src/test/ui/bad/bad-method-typaram-kind.stderr3
-rw-r--r--src/test/ui/closures/closure-bounds-subtype.stderr4
-rw-r--r--src/test/ui/dst/dst-object-from-unsized-type.stderr6
-rw-r--r--src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr5
-rw-r--r--src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr10
-rw-r--r--src/test/ui/kindck/kindck-impl-type-params.stderr16
-rw-r--r--src/test/ui/phantom-oibit.stderr8
-rw-r--r--src/test/ui/suggestions/restrict-type-argument.rs31
-rw-r--r--src/test/ui/suggestions/restrict-type-argument.stderr83
-rw-r--r--src/test/ui/traits/trait-suggest-where-clause.stderr8
-rw-r--r--src/test/ui/traits/traits-repeated-supertrait-ambig.stderr8
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr4
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr8
-rw-r--r--src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr3
-rw-r--r--src/test/ui/unsized/unsized-bare-typaram.stderr5
-rw-r--r--src/test/ui/unsized/unsized-enum.stderr5
-rw-r--r--src/test/ui/unsized/unsized-struct.stderr10
-rw-r--r--src/test/ui/unsized3.stderr18
-rw-r--r--src/test/ui/unsized6.stderr51
-rw-r--r--src/test/ui/wf/wf-impl-associated-type-trait.stderr4
-rw-r--r--src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr4
25 files changed, 335 insertions, 68 deletions
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 9eb91569ed5..b7c7fd4729f 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -715,8 +715,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                             // these notes will often be of the form
                             //     "the type `T` can't be frobnicated"
                             // which is somewhat confusing.
-                            err.help(&format!("consider adding a `where {}` bound",
-                                              trait_ref.to_predicate()));
+                            self.suggest_restricting_param_bound(
+                                &mut err,
+                                &trait_ref,
+                                obligation.cause.body_id,
+                            );
                         } else {
                             if !have_alt_message {
                                 // Can't show anything else useful, try to find similar impls.
@@ -960,6 +963,96 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         err.emit();
     }
 
+    fn suggest_restricting_param_bound(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        trait_ref: &ty::PolyTraitRef<'_>,
+        body_id: hir::HirId,
+    ) {
+        let node = self.tcx.hir().find(self.tcx.hir().get_parent_item(body_id));
+        if let ty::Param(param_ty) = &trait_ref.self_ty().kind {
+            let restrict_msg = "consider further restricting this bound";
+            let param_name = param_ty.name.as_str();
+
+            if let Some(hir::Node::Item(hir::Item {
+                kind: hir::ItemKind::Struct(_, generics), span, ..
+            })) |
+            Some(hir::Node::Item(hir::Item {
+                kind: hir::ItemKind::Enum(_, generics), span, ..
+            })) |
+            Some(hir::Node::Item(hir::Item {
+                kind: hir::ItemKind::Union(_, generics), span, ..
+            })) |
+            Some(hir::Node::Item(hir::Item {
+                kind: hir::ItemKind::Trait(_, _, generics, ..), span, ..
+            })) |
+            Some(hir::Node::Item(hir::Item {
+                kind: hir::ItemKind::Impl(_, _, _, generics, ..), span, ..
+            })) |
+            Some(hir::Node::Item(hir::Item {
+                kind: hir::ItemKind::Fn(_, _, generics, _), span, ..
+            })) = &node {
+                for param in &generics.params {
+                    if param_name == param.name.ident().as_str() {
+                        if param_name.starts_with("impl ") {
+                            err.span_suggestion(
+                                param.span,
+                                restrict_msg,
+                                // `impl CurrentTrait + MissingTrait`
+                                format!("{} + {}", param.name.ident(), trait_ref),
+                                Applicability::MachineApplicable,
+                            );
+                        } else {
+                            if generics.where_clause.predicates.is_empty() &&
+                                param.bounds.is_empty()
+                            {
+                                err.span_suggestion(
+                                    param.span,
+                                    "consider restricting this bound",
+                                    format!("{}", trait_ref.to_predicate()),
+                                    Applicability::MachineApplicable,
+                                );
+                            } else if !generics.where_clause.predicates.is_empty() {
+                                err.span_suggestion(
+                                    generics.where_clause.span().unwrap().shrink_to_hi(),
+                                    &format!(
+                                        "consider further restricting type parameter `{}`",
+                                        param_ty,
+                                    ),
+                                    format!(", {}", trait_ref.to_predicate()),
+                                    Applicability::MachineApplicable,
+                                );
+                            } else {
+                                let sp = param.span.with_hi(span.hi());
+                                let span = self.tcx.sess.source_map().span_through_char(sp, ':');
+                                if sp != param.span && sp != span {
+                                    // Only suggest if we have high certainty that the span covers
+                                    // the colon in `foo<T: Trait>`.
+                                    err.span_suggestion(span, restrict_msg, format!(
+                                        "{} + ",
+                                        trait_ref.to_predicate(),
+                                    ), Applicability::MachineApplicable);
+                                } else {
+                                    err.span_label(param.span, &format!(
+                                        "consider adding a `where {}` bound",
+                                        trait_ref.to_predicate(),
+                                    ));
+                                }
+                            }
+                        }
+                        return;
+                    }
+                }
+            }
+        }
+        // FIXME: Add special check for `?Sized` so we don't suggest `T: Sized + ?Sized`.
+
+        // Fallback in case we didn't find the type argument. Can happen on associated types
+        // bounds and when `Self` needs to be restricted, like in the ui test
+        // `associated-types-projection-to-unrelated-trait-in-method-without-default.rs`.
+        err.help(&format!("consider adding a `where {}` bound", trait_ref.to_predicate()));
+    }
+
     /// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a
     /// suggestion to borrow the initializer in order to use have a slice instead.
     fn suggest_borrow_on_unsized_slice(
diff --git a/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr b/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr
index 30b6b4f3909..c258892057b 100644
--- a/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr
+++ b/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr
@@ -4,10 +4,10 @@ error[E0277]: the trait bound `A: Foo` is not satisfied
 LL |     const Y: usize;
    |     --------------- required by `Foo::Y`
 ...
+LL | pub fn test<A: Foo, B: Foo>() {
+   |             -- help: consider further restricting this bound: `A: Foo +`
 LL |     let _array = [4; <A as Foo>::Y];
    |                      ^^^^^^^^^^^^^ the trait `Foo` is not implemented for `A`
-   |
-   = help: consider adding a `where A: Foo` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-const/associated-const-type-parameter-arrays.stderr b/src/test/ui/associated-const/associated-const-type-parameter-arrays.stderr
index 30fa9891a13..f6c8e99e27a 100644
--- a/src/test/ui/associated-const/associated-const-type-parameter-arrays.stderr
+++ b/src/test/ui/associated-const/associated-const-type-parameter-arrays.stderr
@@ -4,10 +4,10 @@ error[E0277]: the trait bound `A: Foo` is not satisfied
 LL |     const Y: usize;
    |     --------------- required by `Foo::Y`
 ...
+LL | pub fn test<A: Foo, B: Foo>() {
+   |             -- help: consider further restricting this bound: `A: Foo +`
 LL |     let _array: [u32; <A as Foo>::Y];
    |                       ^^^^^^^^^^^^^ the trait `Foo` is not implemented for `A`
-   |
-   = help: consider adding a `where A: Foo` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-types/associated-types-invalid-trait-ref-issue-18865.stderr b/src/test/ui/associated-types/associated-types-invalid-trait-ref-issue-18865.stderr
index 01f66a18d25..0b8b7fab135 100644
--- a/src/test/ui/associated-types/associated-types-invalid-trait-ref-issue-18865.stderr
+++ b/src/test/ui/associated-types/associated-types-invalid-trait-ref-issue-18865.stderr
@@ -1,10 +1,10 @@
 error[E0277]: the trait bound `T: Foo<usize>` is not satisfied
   --> $DIR/associated-types-invalid-trait-ref-issue-18865.rs:10:12
    |
+LL | fn f<T:Foo<isize>>(t: &T) {
+   |      -- help: consider further restricting this bound: `T: Foo<usize> +`
 LL |     let u: <T as Foo<usize>>::Bar = t.get_bar();
    |            ^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo<usize>` is not implemented for `T`
-   |
-   = help: consider adding a `where T: Foo<usize>` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/bad/bad-method-typaram-kind.stderr b/src/test/ui/bad/bad-method-typaram-kind.stderr
index c72b9652360..740667f1466 100644
--- a/src/test/ui/bad/bad-method-typaram-kind.stderr
+++ b/src/test/ui/bad/bad-method-typaram-kind.stderr
@@ -1,11 +1,12 @@
 error[E0277]: `T` cannot be sent between threads safely
   --> $DIR/bad-method-typaram-kind.rs:2:7
    |
+LL | fn foo<T:'static>() {
+   |        -- help: consider further restricting this bound: `T: std::marker::Send +`
 LL |     1.bar::<T>();
    |       ^^^ `T` cannot be sent between threads safely
    |
    = help: the trait `std::marker::Send` is not implemented for `T`
-   = help: consider adding a `where T: std::marker::Send` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/closures/closure-bounds-subtype.stderr b/src/test/ui/closures/closure-bounds-subtype.stderr
index 4b703eded69..05d5bb1e8d5 100644
--- a/src/test/ui/closures/closure-bounds-subtype.stderr
+++ b/src/test/ui/closures/closure-bounds-subtype.stderr
@@ -4,11 +4,13 @@ error[E0277]: `F` cannot be shared between threads safely
 LL | fn take_const_owned<F>(_: F) where F: FnOnce() + Sync + Send {
    |    ----------------                              ---- required by this bound in `take_const_owned`
 ...
+LL | fn give_owned<F>(f: F) where F: FnOnce() + Send {
+   |                                                - help: consider further restricting type parameter `F`: `, F: std::marker::Sync`
+LL |     take_any(f);
 LL |     take_const_owned(f);
    |                      ^ `F` cannot be shared between threads safely
    |
    = help: the trait `std::marker::Sync` is not implemented for `F`
-   = help: consider adding a `where F: std::marker::Sync` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/dst/dst-object-from-unsized-type.stderr b/src/test/ui/dst/dst-object-from-unsized-type.stderr
index 55ac625fc98..40db575eabd 100644
--- a/src/test/ui/dst/dst-object-from-unsized-type.stderr
+++ b/src/test/ui/dst/dst-object-from-unsized-type.stderr
@@ -1,23 +1,25 @@
 error[E0277]: the size for values of type `T` cannot be known at compilation time
   --> $DIR/dst-object-from-unsized-type.rs:8:23
    |
+LL | fn test1<T: ?Sized + Foo>(t: &T) {
+   |          -- help: consider further restricting this bound: `T: std::marker::Sized +`
 LL |     let u: &dyn Foo = t;
    |                       ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where T: std::marker::Sized` bound
    = note: required for the cast to the object type `dyn Foo`
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
   --> $DIR/dst-object-from-unsized-type.rs:13:23
    |
+LL | fn test2<T: ?Sized + Foo>(t: &T) {
+   |          -- help: consider further restricting this bound: `T: std::marker::Sized +`
 LL |     let v: &dyn Foo = t as &dyn Foo;
    |                       ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where T: std::marker::Sized` bound
    = note: required for the cast to the object type `dyn Foo`
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
diff --git a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr
index c2cc8ebad27..afcb467ad47 100644
--- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr
+++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr
@@ -6,10 +6,11 @@ LL | fn want_bar_for_any_ccx<B>(b: &B)
 LL |     where B : for<'ccx> Bar<'ccx>
    |               ------------------- required by this bound in `want_bar_for_any_ccx`
 ...
+LL |     where B : Qux
+   |                  - help: consider further restricting type parameter `B`: `, for<'ccx> B: Bar<'ccx>`
+...
 LL |     want_bar_for_any_ccx(b);
    |                          ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B`
-   |
-   = help: consider adding a `where for<'ccx> B: Bar<'ccx>` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr
index a93814ad4c2..20913b4f28c 100644
--- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr
+++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr
@@ -1,6 +1,9 @@
 error[E0277]: the trait bound `for<'tcx> F: Foo<'tcx>` is not satisfied
   --> $DIR/hrtb-higher-ranker-supertraits.rs:18:26
    |
+LL |     where F : Foo<'x>
+   |                      - help: consider further restricting type parameter `F`: `, for<'tcx> F: Foo<'tcx>`
+...
 LL |     want_foo_for_any_tcx(f);
    |                          ^ the trait `for<'tcx> Foo<'tcx>` is not implemented for `F`
 ...
@@ -8,12 +11,13 @@ LL | fn want_foo_for_any_tcx<F>(f: &F)
    |    --------------------
 LL |     where F : for<'tcx> Foo<'tcx>
    |               ------------------- required by this bound in `want_foo_for_any_tcx`
-   |
-   = help: consider adding a `where for<'tcx> F: Foo<'tcx>` bound
 
 error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied
   --> $DIR/hrtb-higher-ranker-supertraits.rs:35:26
    |
+LL |     where B : Bar<'x>
+   |                      - help: consider further restricting type parameter `B`: `, for<'ccx> B: Bar<'ccx>`
+...
 LL |     want_bar_for_any_ccx(b);
    |                          ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B`
 ...
@@ -21,8 +25,6 @@ LL | fn want_bar_for_any_ccx<B>(b: &B)
    |    --------------------
 LL |     where B : for<'ccx> Bar<'ccx>
    |               ------------------- required by this bound in `want_bar_for_any_ccx`
-   |
-   = help: consider adding a `where for<'ccx> B: Bar<'ccx>` bound
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/kindck/kindck-impl-type-params.stderr b/src/test/ui/kindck/kindck-impl-type-params.stderr
index e6f7088bd46..777a553c2a5 100644
--- a/src/test/ui/kindck/kindck-impl-type-params.stderr
+++ b/src/test/ui/kindck/kindck-impl-type-params.stderr
@@ -1,42 +1,50 @@
 error[E0277]: `T` cannot be sent between threads safely
   --> $DIR/kindck-impl-type-params.rs:18:13
    |
+LL | fn f<T>(val: T) {
+   |      - help: consider restricting this bound: `T: std::marker::Send`
+LL |     let t: S<T> = S(marker::PhantomData);
 LL |     let a = &t as &dyn Gettable<T>;
    |             ^^ `T` cannot be sent between threads safely
    |
    = help: the trait `std::marker::Send` is not implemented for `T`
-   = help: consider adding a `where T: std::marker::Send` bound
    = note: required because of the requirements on the impl of `Gettable<T>` for `S<T>`
    = note: required for the cast to the object type `dyn Gettable<T>`
 
 error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
   --> $DIR/kindck-impl-type-params.rs:18:13
    |
+LL | fn f<T>(val: T) {
+   |      - help: consider restricting this bound: `T: std::marker::Copy`
+LL |     let t: S<T> = S(marker::PhantomData);
 LL |     let a = &t as &dyn Gettable<T>;
    |             ^^ the trait `std::marker::Copy` is not implemented for `T`
    |
-   = help: consider adding a `where T: std::marker::Copy` bound
    = note: required because of the requirements on the impl of `Gettable<T>` for `S<T>`
    = note: required for the cast to the object type `dyn Gettable<T>`
 
 error[E0277]: `T` cannot be sent between threads safely
   --> $DIR/kindck-impl-type-params.rs:25:31
    |
+LL | fn g<T>(val: T) {
+   |      - help: consider restricting this bound: `T: std::marker::Send`
+LL |     let t: S<T> = S(marker::PhantomData);
 LL |     let a: &dyn Gettable<T> = &t;
    |                               ^^ `T` cannot be sent between threads safely
    |
    = help: the trait `std::marker::Send` is not implemented for `T`
-   = help: consider adding a `where T: std::marker::Send` bound
    = note: required because of the requirements on the impl of `Gettable<T>` for `S<T>`
    = note: required for the cast to the object type `dyn Gettable<T>`
 
 error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
   --> $DIR/kindck-impl-type-params.rs:25:31
    |
+LL | fn g<T>(val: T) {
+   |      - help: consider restricting this bound: `T: std::marker::Copy`
+LL |     let t: S<T> = S(marker::PhantomData);
 LL |     let a: &dyn Gettable<T> = &t;
    |                               ^^ the trait `std::marker::Copy` is not implemented for `T`
    |
-   = help: consider adding a `where T: std::marker::Copy` bound
    = note: required because of the requirements on the impl of `Gettable<T>` for `S<T>`
    = note: required for the cast to the object type `dyn Gettable<T>`
 
diff --git a/src/test/ui/phantom-oibit.stderr b/src/test/ui/phantom-oibit.stderr
index ac48ee0cb0f..4d9d06b8986 100644
--- a/src/test/ui/phantom-oibit.stderr
+++ b/src/test/ui/phantom-oibit.stderr
@@ -3,12 +3,13 @@ error[E0277]: `T` cannot be shared between threads safely
    |
 LL | fn is_zen<T: Zen>(_: T) {}
    |    ------    --- required by this bound in `is_zen`
-...
+LL | 
+LL | fn not_sync<T>(x: Guard<T>) {
+   |             - help: consider restricting this bound: `T: std::marker::Sync`
 LL |     is_zen(x)
    |            ^ `T` cannot be shared between threads safely
    |
    = help: the trait `std::marker::Sync` is not implemented for `T`
-   = help: consider adding a `where T: std::marker::Sync` bound
    = note: required because of the requirements on the impl of `Zen` for `&T`
    = note: required because it appears within the type `std::marker::PhantomData<&T>`
    = note: required because it appears within the type `Guard<'_, T>`
@@ -19,11 +20,12 @@ error[E0277]: `T` cannot be shared between threads safely
 LL | fn is_zen<T: Zen>(_: T) {}
    |    ------    --- required by this bound in `is_zen`
 ...
+LL | fn nested_not_sync<T>(x: Nested<Guard<T>>) {
+   |                    - help: consider restricting this bound: `T: std::marker::Sync`
 LL |     is_zen(x)
    |            ^ `T` cannot be shared between threads safely
    |
    = help: the trait `std::marker::Sync` is not implemented for `T`
-   = help: consider adding a `where T: std::marker::Sync` bound
    = note: required because of the requirements on the impl of `Zen` for `&T`
    = note: required because it appears within the type `std::marker::PhantomData<&T>`
    = note: required because it appears within the type `Guard<'_, T>`
diff --git a/src/test/ui/suggestions/restrict-type-argument.rs b/src/test/ui/suggestions/restrict-type-argument.rs
new file mode 100644
index 00000000000..c4ebfbe922c
--- /dev/null
+++ b/src/test/ui/suggestions/restrict-type-argument.rs
@@ -0,0 +1,31 @@
+fn is_send<T: Send>(val: T) {}
+
+fn use_impl_sync(val: impl Sync) {
+    is_send(val); //~ ERROR `impl Sync` cannot be sent between threads safely
+}
+
+fn use_where<S>(val: S) where S: Sync {
+    is_send(val); //~ ERROR `S` cannot be sent between threads safely
+}
+
+fn use_bound<S: Sync>(val: S) {
+    is_send(val); //~ ERROR `S` cannot be sent between threads safely
+}
+
+fn use_bound_2<
+    S // Make sure we can synthezise a correct suggestion span for this case
+    :
+    Sync
+>(val: S) {
+    is_send(val); //~ ERROR `S` cannot be sent between threads safely
+}
+
+fn use_bound_and_where<S: Sync>(val: S) where S: std::fmt::Debug {
+    is_send(val); //~ ERROR `S` cannot be sent between threads safely
+}
+
+fn use_unbound<S>(val: S) {
+    is_send(val); //~ ERROR `S` cannot be sent between threads safely
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/restrict-type-argument.stderr b/src/test/ui/suggestions/restrict-type-argument.stderr
new file mode 100644
index 00000000000..d6840ca4d72
--- /dev/null
+++ b/src/test/ui/suggestions/restrict-type-argument.stderr
@@ -0,0 +1,83 @@
+error[E0277]: `impl Sync` cannot be sent between threads safely
+  --> $DIR/restrict-type-argument.rs:4:13
+   |
+LL | fn is_send<T: Send>(val: T) {}
+   |    -------    ---- required by this bound in `is_send`
+LL | 
+LL | fn use_impl_sync(val: impl Sync) {
+   |                       --------- help: consider further restricting this bound: `impl Sync + std::marker::Send`
+LL |     is_send(val);
+   |             ^^^ `impl Sync` cannot be sent between threads safely
+   |
+   = help: the trait `std::marker::Send` is not implemented for `impl Sync`
+
+error[E0277]: `S` cannot be sent between threads safely
+  --> $DIR/restrict-type-argument.rs:8:13
+   |
+LL | fn is_send<T: Send>(val: T) {}
+   |    -------    ---- required by this bound in `is_send`
+...
+LL | fn use_where<S>(val: S) where S: Sync {
+   |                                      - help: consider further restricting type parameter `S`: `, S: std::marker::Send`
+LL |     is_send(val);
+   |             ^^^ `S` cannot be sent between threads safely
+   |
+   = help: the trait `std::marker::Send` is not implemented for `S`
+
+error[E0277]: `S` cannot be sent between threads safely
+  --> $DIR/restrict-type-argument.rs:12:13
+   |
+LL | fn is_send<T: Send>(val: T) {}
+   |    -------    ---- required by this bound in `is_send`
+...
+LL | fn use_bound<S: Sync>(val: S) {
+   |              -- help: consider further restricting this bound: `S: std::marker::Send +`
+LL |     is_send(val);
+   |             ^^^ `S` cannot be sent between threads safely
+   |
+   = help: the trait `std::marker::Send` is not implemented for `S`
+
+error[E0277]: `S` cannot be sent between threads safely
+  --> $DIR/restrict-type-argument.rs:20:13
+   |
+LL |   fn is_send<T: Send>(val: T) {}
+   |      -------    ---- required by this bound in `is_send`
+...
+LL | /     S // Make sure we can synthezise a correct suggestion span for this case
+LL | |     :
+   | |_____- help: consider further restricting this bound: `S: std::marker::Send +`
+...
+LL |       is_send(val);
+   |               ^^^ `S` cannot be sent between threads safely
+   |
+   = help: the trait `std::marker::Send` is not implemented for `S`
+
+error[E0277]: `S` cannot be sent between threads safely
+  --> $DIR/restrict-type-argument.rs:24:13
+   |
+LL | fn is_send<T: Send>(val: T) {}
+   |    -------    ---- required by this bound in `is_send`
+...
+LL | fn use_bound_and_where<S: Sync>(val: S) where S: std::fmt::Debug {
+   |                                                                 - help: consider further restricting type parameter `S`: `, S: std::marker::Send`
+LL |     is_send(val);
+   |             ^^^ `S` cannot be sent between threads safely
+   |
+   = help: the trait `std::marker::Send` is not implemented for `S`
+
+error[E0277]: `S` cannot be sent between threads safely
+  --> $DIR/restrict-type-argument.rs:28:13
+   |
+LL | fn is_send<T: Send>(val: T) {}
+   |    -------    ---- required by this bound in `is_send`
+...
+LL | fn use_unbound<S>(val: S) {
+   |                - help: consider restricting this bound: `S: std::marker::Send`
+LL |     is_send(val);
+   |             ^^^ `S` cannot be sent between threads safely
+   |
+   = help: the trait `std::marker::Send` is not implemented for `S`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/traits/trait-suggest-where-clause.stderr b/src/test/ui/traits/trait-suggest-where-clause.stderr
index d15edaa9c81..bc9948064a3 100644
--- a/src/test/ui/traits/trait-suggest-where-clause.stderr
+++ b/src/test/ui/traits/trait-suggest-where-clause.stderr
@@ -1,6 +1,9 @@
 error[E0277]: the size for values of type `U` cannot be known at compilation time
   --> $DIR/trait-suggest-where-clause.rs:9:20
    |
+LL | fn check<T: Iterator, U: ?Sized>() {
+   |                       -- help: consider further restricting this bound: `U: std::marker::Sized +`
+LL |     // suggest a where-clause, if needed
 LL |     mem::size_of::<U>();
    |                    ^ doesn't have a size known at compile-time
    | 
@@ -11,11 +14,13 @@ LL | pub const fn size_of<T>() -> usize {
    |
    = help: the trait `std::marker::Sized` is not implemented for `U`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where U: std::marker::Sized` bound
 
 error[E0277]: the size for values of type `U` cannot be known at compilation time
   --> $DIR/trait-suggest-where-clause.rs:12:5
    |
+LL | fn check<T: Iterator, U: ?Sized>() {
+   |                       -- help: consider further restricting this bound: `U: std::marker::Sized +`
+...
 LL |     mem::size_of::<Misc<U>>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    | 
@@ -26,7 +31,6 @@ LL | pub const fn size_of<T>() -> usize {
    |
    = help: within `Misc<U>`, the trait `std::marker::Sized` is not implemented for `U`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where U: std::marker::Sized` bound
    = note: required because it appears within the type `Misc<U>`
 
 error[E0277]: the trait bound `u64: std::convert::From<T>` is not satisfied
diff --git a/src/test/ui/traits/traits-repeated-supertrait-ambig.stderr b/src/test/ui/traits/traits-repeated-supertrait-ambig.stderr
index db77e82adbd..85c7a55c313 100644
--- a/src/test/ui/traits/traits-repeated-supertrait-ambig.stderr
+++ b/src/test/ui/traits/traits-repeated-supertrait-ambig.stderr
@@ -7,10 +7,10 @@ LL |     c.same_as(22)
 error[E0277]: the trait bound `C: CompareTo<i32>` is not satisfied
   --> $DIR/traits-repeated-supertrait-ambig.rs:30:7
    |
+LL | fn with_trait<C:CompareToInts>(c: &C) -> bool {
+   |               -- help: consider further restricting this bound: `C: CompareTo<i32> +`
 LL |     c.same_as(22)
    |       ^^^^^^^ the trait `CompareTo<i32>` is not implemented for `C`
-   |
-   = help: consider adding a `where C: CompareTo<i32>` bound
 
 error[E0277]: the trait bound `dyn CompareToInts: CompareTo<i32>` is not satisfied
   --> $DIR/traits-repeated-supertrait-ambig.rs:34:5
@@ -27,10 +27,10 @@ error[E0277]: the trait bound `C: CompareTo<i32>` is not satisfied
 LL |     fn same_as(&self, t: T) -> bool;
    |     -------------------------------- required by `CompareTo::same_as`
 ...
+LL | fn with_ufcs2<C:CompareToInts>(c: &C) -> bool {
+   |               -- help: consider further restricting this bound: `C: CompareTo<i32> +`
 LL |     CompareTo::same_as(c, 22)
    |     ^^^^^^^^^^^^^^^^^^ the trait `CompareTo<i32>` is not implemented for `C`
-   |
-   = help: consider adding a `where C: CompareTo<i32>` bound
 
 error[E0277]: the trait bound `i64: CompareTo<i32>` is not satisfied
   --> $DIR/traits-repeated-supertrait-ambig.rs:42:23
diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr b/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr
index dd90dd1b06f..63c07224353 100644
--- a/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr
@@ -9,8 +9,10 @@ error[E0277]: the trait bound `T: Trait` is not satisfied
    |
 LL | type Underconstrained<T: Trait> = impl 'static;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T`
+...
+LL | fn underconstrain<T>(_: T) -> Underconstrained<T> {
+   |                   - help: consider restricting this bound: `T: Trait`
    |
-   = help: consider adding a `where T: Trait` bound
    = note: the return type of a function must have a statically known size
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr
index 574432bdcf6..ba892f6ed7c 100644
--- a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr
@@ -15,9 +15,11 @@ error[E0277]: `U` doesn't implement `std::fmt::Debug`
    |
 LL | type Underconstrained<T: std::fmt::Debug> = impl 'static;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
+...
+LL | fn underconstrained<U>(_: U) -> Underconstrained<U> {
+   |                     - help: consider restricting this bound: `U: std::fmt::Debug`
    |
    = help: the trait `std::fmt::Debug` is not implemented for `U`
-   = help: consider adding a `where U: std::fmt::Debug` bound
    = note: the return type of a function must have a statically known size
 
 error[E0277]: `V` doesn't implement `std::fmt::Debug`
@@ -25,9 +27,11 @@ error[E0277]: `V` doesn't implement `std::fmt::Debug`
    |
 LL | type Underconstrained2<T: std::fmt::Debug> = impl 'static;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
+...
+LL | fn underconstrained2<U, V>(_: U, _: V) -> Underconstrained2<V> {
+   |                         - help: consider restricting this bound: `V: std::fmt::Debug`
    |
    = help: the trait `std::fmt::Debug` is not implemented for `V`
-   = help: consider adding a `where V: std::fmt::Debug` bound
    = note: the return type of a function must have a statically known size
 
 error: aborting due to 4 previous errors
diff --git a/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr b/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr
index b3139083b1a..a84aef5fdbd 100644
--- a/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr
+++ b/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr
@@ -1,6 +1,8 @@
 error[E0277]: `T` cannot be sent between threads safely
   --> $DIR/typeck-default-trait-impl-send-param.rs:5:15
    |
+LL | fn foo<T>() {
+   |        - help: consider restricting this bound: `T: std::marker::Send`
 LL |     is_send::<T>()
    |               ^ `T` cannot be sent between threads safely
 ...
@@ -8,7 +10,6 @@ LL | fn is_send<T:Send>() {
    |    -------   ---- required by this bound in `is_send`
    |
    = help: the trait `std::marker::Send` is not implemented for `T`
-   = help: consider adding a `where T: std::marker::Send` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unsized/unsized-bare-typaram.stderr b/src/test/ui/unsized/unsized-bare-typaram.stderr
index e56176690a1..bd97b0203b5 100644
--- a/src/test/ui/unsized/unsized-bare-typaram.stderr
+++ b/src/test/ui/unsized/unsized-bare-typaram.stderr
@@ -4,11 +4,12 @@ error[E0277]: the size for values of type `T` cannot be known at compilation tim
 LL | fn bar<T: Sized>() { }
    |    --- - required by this bound in `bar`
 LL | fn foo<T: ?Sized>() { bar::<T>() }
-   |                             ^ doesn't have a size known at compile-time
+   |        --                   ^ doesn't have a size known at compile-time
+   |        |
+   |        help: consider further restricting this bound: `T: std::marker::Sized +`
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where T: std::marker::Sized` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unsized/unsized-enum.stderr b/src/test/ui/unsized/unsized-enum.stderr
index dff934834ef..341d3e4cc2d 100644
--- a/src/test/ui/unsized/unsized-enum.stderr
+++ b/src/test/ui/unsized/unsized-enum.stderr
@@ -5,11 +5,12 @@ LL | enum Foo<U> { FooSome(U), FooNone }
    | ----------- required by `Foo`
 LL | fn foo1<T>() { not_sized::<Foo<T>>() } // Hunky dory.
 LL | fn foo2<T: ?Sized>() { not_sized::<Foo<T>>() }
-   |                                    ^^^^^^ doesn't have a size known at compile-time
+   |         --                         ^^^^^^ doesn't have a size known at compile-time
+   |         |
+   |         help: consider further restricting this bound: `T: std::marker::Sized +`
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where T: std::marker::Sized` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unsized/unsized-struct.stderr b/src/test/ui/unsized/unsized-struct.stderr
index 0d4776ff6c2..2894d5d5671 100644
--- a/src/test/ui/unsized/unsized-struct.stderr
+++ b/src/test/ui/unsized/unsized-struct.stderr
@@ -5,11 +5,12 @@ LL | struct Foo<T> { data: T }
    | ------------- required by `Foo`
 LL | fn foo1<T>() { not_sized::<Foo<T>>() } // Hunky dory.
 LL | fn foo2<T: ?Sized>() { not_sized::<Foo<T>>() }
-   |                                    ^^^^^^ doesn't have a size known at compile-time
+   |         --                         ^^^^^^ doesn't have a size known at compile-time
+   |         |
+   |         help: consider further restricting this bound: `T: std::marker::Sized +`
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where T: std::marker::Sized` bound
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
   --> $DIR/unsized-struct.rs:13:24
@@ -18,11 +19,12 @@ LL | fn is_sized<T:Sized>() { }
    |    -------- - required by this bound in `is_sized`
 ...
 LL | fn bar2<T: ?Sized>() { is_sized::<Bar<T>>() }
-   |                        ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |         --             ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |         |
+   |         help: consider further restricting this bound: `T: std::marker::Sized +`
    |
    = help: within `Bar<T>`, the trait `std::marker::Sized` is not implemented for `T`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where T: std::marker::Sized` bound
    = note: required because it appears within the type `Bar<T>`
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/unsized3.stderr b/src/test/ui/unsized3.stderr
index c821a08f6b5..232296ad091 100644
--- a/src/test/ui/unsized3.stderr
+++ b/src/test/ui/unsized3.stderr
@@ -1,6 +1,8 @@
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized3.rs:7:13
    |
+LL | fn f1<X: ?Sized>(x: &X) {
+   |       -- help: consider further restricting this bound: `X: std::marker::Sized +`
 LL |     f2::<X>(x);
    |             ^ doesn't have a size known at compile-time
 ...
@@ -9,11 +11,12 @@ LL | fn f2<X>(x: &X) {
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized3.rs:18:13
    |
+LL | fn f3<X: ?Sized + T>(x: &X) {
+   |       -- help: consider further restricting this bound: `X: std::marker::Sized +`
 LL |     f4::<X>(x);
    |             ^ doesn't have a size known at compile-time
 ...
@@ -22,7 +25,6 @@ LL | fn f4<X: T>(x: &X) {
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized3.rs:33:8
@@ -30,35 +32,38 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim
 LL | fn f5<Y>(x: &Y) {}
    |    -- - required by this bound in `f5`
 ...
+LL | fn f8<X: ?Sized>(x1: &S<X>, x2: &S<X>) {
+   |       -- help: consider further restricting this bound: `X: std::marker::Sized +`
 LL |     f5(x1);
    |        ^^ doesn't have a size known at compile-time
    |
    = help: within `S<X>`, the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: required because it appears within the type `S<X>`
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized3.rs:40:8
    |
+LL | fn f9<X: ?Sized>(x1: Box<S<X>>) {
+   |       -- help: consider further restricting this bound: `X: std::marker::Sized +`
 LL |     f5(&(*x1, 34));
    |        ^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: within `S<X>`, the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: required because it appears within the type `S<X>`
    = note: only the last element of a tuple may have a dynamically sized type
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized3.rs:45:9
    |
+LL | fn f10<X: ?Sized>(x1: Box<S<X>>) {
+   |        -- help: consider further restricting this bound: `X: std::marker::Sized +`
 LL |     f5(&(32, *x1));
    |         ^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: within `({integer}, S<X>)`, the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: required because it appears within the type `S<X>`
    = note: required because it appears within the type `({integer}, S<X>)`
    = note: tuples must have a statically known size to be initialized
@@ -69,12 +74,13 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim
 LL | fn f5<Y>(x: &Y) {}
    |    -- - required by this bound in `f5`
 ...
+LL | fn f10<X: ?Sized>(x1: Box<S<X>>) {
+   |        -- help: consider further restricting this bound: `X: std::marker::Sized +`
 LL |     f5(&(32, *x1));
    |        ^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: within `({integer}, S<X>)`, the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: required because it appears within the type `S<X>`
    = note: required because it appears within the type `({integer}, S<X>)`
 
diff --git a/src/test/ui/unsized6.stderr b/src/test/ui/unsized6.stderr
index a6a26573e7c..95acd987a5a 100644
--- a/src/test/ui/unsized6.stderr
+++ b/src/test/ui/unsized6.stderr
@@ -1,129 +1,148 @@
 error[E0277]: the size for values of type `Y` cannot be known at compilation time
   --> $DIR/unsized6.rs:9:9
    |
+LL | fn f1<W: ?Sized, X: ?Sized, Y: ?Sized, Z: ?Sized>(x: &X) {
+   |                             -- help: consider further restricting this bound: `Y: std::marker::Sized +`
+...
 LL |     let y: Y;
    |         ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `Y`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where Y: std::marker::Sized` bound
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:7:12
    |
+LL | fn f1<W: ?Sized, X: ?Sized, Y: ?Sized, Z: ?Sized>(x: &X) {
+   |                  -- help: consider further restricting this bound: `X: std::marker::Sized +`
+LL |     let _: W; // <-- this is OK, no bindings created, no initializer.
 LL |     let _: (isize, (X, isize));
    |            ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: only the last element of a tuple may have a dynamically sized type
 
 error[E0277]: the size for values of type `Z` cannot be known at compilation time
   --> $DIR/unsized6.rs:11:12
    |
+LL | fn f1<W: ?Sized, X: ?Sized, Y: ?Sized, Z: ?Sized>(x: &X) {
+   |                                        -- help: consider further restricting this bound: `Z: std::marker::Sized +`
+...
 LL |     let y: (isize, (Z, usize));
    |            ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `Z`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where Z: std::marker::Sized` bound
    = note: only the last element of a tuple may have a dynamically sized type
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:15:9
    |
+LL | fn f2<X: ?Sized, Y: ?Sized>(x: &X) {
+   |       -- help: consider further restricting this bound: `X: std::marker::Sized +`
 LL |     let y: X;
    |         ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
 error[E0277]: the size for values of type `Y` cannot be known at compilation time
   --> $DIR/unsized6.rs:17:12
    |
+LL | fn f2<X: ?Sized, Y: ?Sized>(x: &X) {
+   |                  -- help: consider further restricting this bound: `Y: std::marker::Sized +`
+...
 LL |     let y: (isize, (Y, isize));
    |            ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `Y`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where Y: std::marker::Sized` bound
    = note: only the last element of a tuple may have a dynamically sized type
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:22:9
    |
+LL | fn f3<X: ?Sized>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
+   |       -- help: consider further restricting this bound: `X: std::marker::Sized +`
 LL |     let y: X = *x1;
    |         ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:24:9
    |
+LL | fn f3<X: ?Sized>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
+   |       -- help: consider further restricting this bound: `X: std::marker::Sized +`
+...
 LL |     let y = *x2;
    |         ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:26:10
    |
+LL | fn f3<X: ?Sized>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
+   |       -- help: consider further restricting this bound: `X: std::marker::Sized +`
+...
 LL |     let (y, z) = (*x3, 4);
    |          ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:30:9
    |
+LL | fn f4<X: ?Sized + T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
+   |       -- help: consider further restricting this bound: `X: std::marker::Sized +`
 LL |     let y: X = *x1;
    |         ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:32:9
    |
+LL | fn f4<X: ?Sized + T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
+   |       -- help: consider further restricting this bound: `X: std::marker::Sized +`
+...
 LL |     let y = *x2;
    |         ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:34:10
    |
+LL | fn f4<X: ?Sized + T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
+   |       -- help: consider further restricting this bound: `X: std::marker::Sized +`
+...
 LL |     let (y, z) = (*x3, 4);
    |          ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -131,11 +150,12 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim
   --> $DIR/unsized6.rs:38:18
    |
 LL | fn g1<X: ?Sized>(x: X) {}
-   |                  ^ doesn't have a size known at compile-time
+   |       --         ^ doesn't have a size known at compile-time
+   |       |
+   |       help: consider further restricting this bound: `X: std::marker::Sized +`
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -143,11 +163,12 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim
   --> $DIR/unsized6.rs:40:22
    |
 LL | fn g2<X: ?Sized + T>(x: X) {}
-   |                      ^ doesn't have a size known at compile-time
+   |       --             ^ doesn't have a size known at compile-time
+   |       |
+   |       help: consider further restricting this bound: `X: std::marker::Sized +`
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
diff --git a/src/test/ui/wf/wf-impl-associated-type-trait.stderr b/src/test/ui/wf/wf-impl-associated-type-trait.stderr
index ceafb4f6157..6d71670e6a8 100644
--- a/src/test/ui/wf/wf-impl-associated-type-trait.stderr
+++ b/src/test/ui/wf/wf-impl-associated-type-trait.stderr
@@ -4,10 +4,10 @@ error[E0277]: the trait bound `T: MyHash` is not satisfied
 LL | pub struct MySet<T:MyHash> {
    | -------------------------- required by `MySet`
 ...
+LL | impl<T> Foo for T {
+   |      - help: consider restricting this bound: `T: MyHash`
 LL |     type Bar = MySet<T>;
    |     ^^^^^^^^^^^^^^^^^^^^ the trait `MyHash` is not implemented for `T`
-   |
-   = help: consider adding a `where T: MyHash` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr b/src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr
index 1e258864d03..21f825ac9ef 100644
--- a/src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr
+++ b/src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr
@@ -4,11 +4,11 @@ error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied
 LL |   trait ExtraCopy<T:Copy> { }
    |   ----------------------- required by `ExtraCopy`
 ...
+LL |   impl<T,U> Foo<T,U> {
+   |          - help: consider restricting this bound: `U: std::marker::Copy`
 LL | /     fn foo(self) where T: ExtraCopy<U>
 LL | |     {}
    | |______^ the trait `std::marker::Copy` is not implemented for `U`
-   |
-   = help: consider adding a `where U: std::marker::Copy` bound
 
 error: aborting due to previous error