about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs23
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs10
-rw-r--r--compiler/rustc_hir/src/hir.rs2
-rw-r--r--compiler/rustc_hir/src/intravisit.rs1
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs3
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs112
-rw-r--r--compiler/rustc_save_analysis/src/dump_visitor.rs1
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs3
-rw-r--r--compiler/rustc_typeck/src/collect.rs7
-rw-r--r--src/librustdoc/clean/mod.rs9
-rw-r--r--src/test/ui/const-generics/const-argument-if-length.full.stderr9
-rw-r--r--src/test/ui/const-generics/const-argument-if-length.min.stderr4
-rw-r--r--src/test/ui/dst/dst-object-from-unsized-type.stderr8
-rw-r--r--src/test/ui/packed/issue-27060-2.stderr4
-rw-r--r--src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr4
-rw-r--r--src/test/ui/trait-bounds/unsized-bound.rs32
-rw-r--r--src/test/ui/trait-bounds/unsized-bound.stderr234
-rw-r--r--src/test/ui/traits/suggest-where-clause.stderr9
-rw-r--r--src/test/ui/union/union-sized-field.stderr12
-rw-r--r--src/test/ui/unsized/unsized-bare-typaram.stderr5
-rw-r--r--src/test/ui/unsized/unsized-enum.stderr4
-rw-r--r--src/test/ui/unsized/unsized-enum2.stderr16
-rw-r--r--src/test/ui/unsized/unsized-fn-arg.fixed2
-rw-r--r--src/test/ui/unsized/unsized-fn-arg.stderr4
-rw-r--r--src/test/ui/unsized/unsized-inherent-impl-self-type.stderr4
-rw-r--r--src/test/ui/unsized/unsized-struct.stderr8
-rw-r--r--src/test/ui/unsized/unsized-trait-impl-self-type.stderr4
-rw-r--r--src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr4
-rw-r--r--src/test/ui/unsized/unsized3.stderr24
-rw-r--r--src/test/ui/unsized/unsized5.stderr16
-rw-r--r--src/test/ui/unsized/unsized6.stderr52
-rw-r--r--src/test/ui/unsized/unsized7.stderr4
32 files changed, 615 insertions, 19 deletions
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 0fddb0ee4cc..3acf69ec2b7 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1443,16 +1443,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
                             ImplTraitContext::disallowed(),
                         ),
                         bounded_ty: this.lower_ty(bounded_ty, ImplTraitContext::disallowed()),
-                        bounds: this.arena.alloc_from_iter(bounds.iter().filter_map(|bound| {
-                            match *bound {
-                                // Ignore `?Trait` bounds.
-                                // They were copied into type parameters already.
-                                GenericBound::Trait(_, TraitBoundModifier::Maybe) => None,
-                                _ => Some(
-                                    this.lower_param_bound(bound, ImplTraitContext::disallowed()),
-                                ),
-                            }
-                        })),
+                        bounds: this.arena.alloc_from_iter(bounds.iter().map(
+                            |bound| match bound {
+                                // We used to ignore `?Trait` bounds, as they were copied into type
+                                // parameters already, but we need to keep them around only for
+                                // diagnostics when we suggest removal of `?Sized` bounds. See
+                                // `suggest_constraining_type_param`. This will need to change if
+                                // we ever allow something *other* than `?Sized`.
+                                GenericBound::Trait(p, TraitBoundModifier::Maybe) => {
+                                    hir::GenericBound::Unsized(p.span)
+                                }
+                                _ => this.lower_param_bound(bound, ImplTraitContext::disallowed()),
+                            },
+                        )),
                         span,
                     })
                 })
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 3bd42ba6090..581f177ad14 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -2160,12 +2160,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         tpb: &GenericBound,
         itctx: ImplTraitContext<'_, 'hir>,
     ) -> hir::GenericBound<'hir> {
-        match *tpb {
-            GenericBound::Trait(ref ty, modifier) => hir::GenericBound::Trait(
-                self.lower_poly_trait_ref(ty, itctx),
-                self.lower_trait_bound_modifier(modifier),
+        match tpb {
+            GenericBound::Trait(p, modifier) => hir::GenericBound::Trait(
+                self.lower_poly_trait_ref(p, itctx),
+                self.lower_trait_bound_modifier(*modifier),
             ),
-            GenericBound::Outlives(ref lifetime) => {
+            GenericBound::Outlives(lifetime) => {
                 hir::GenericBound::Outlives(self.lower_lifetime(lifetime))
             }
         }
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index db7fe6cb12f..aac5d296f17 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -442,6 +442,7 @@ pub enum GenericBound<'hir> {
     Trait(PolyTraitRef<'hir>, TraitBoundModifier),
     // FIXME(davidtwco): Introduce `PolyTraitRef::LangItem`
     LangItemTrait(LangItem, Span, HirId, &'hir GenericArgs<'hir>),
+    Unsized(Span),
     Outlives(Lifetime),
 }
 
@@ -458,6 +459,7 @@ impl GenericBound<'_> {
             GenericBound::Trait(t, ..) => t.span,
             GenericBound::LangItemTrait(_, span, ..) => *span,
             GenericBound::Outlives(l) => l.span,
+            GenericBound::Unsized(span) => *span,
         }
     }
 }
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 17835493cda..ae186d66004 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -889,6 +889,7 @@ pub fn walk_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v GenericB
             visitor.visit_generic_args(span, args);
         }
         GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime),
+        GenericBound::Unsized(_) => {}
     }
 }
 
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 90ceb1d5c91..2b372392575 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -2230,6 +2230,9 @@ impl<'a> State<'a> {
                 GenericBound::Outlives(lt) => {
                     self.print_lifetime(lt);
                 }
+                GenericBound::Unsized(_) => {
+                    self.s.word("?Sized");
+                }
             }
         }
     }
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index bfb4c0cb538..4cfb104bee3 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -2,6 +2,7 @@
 
 use crate::ty::TyKind::*;
 use crate::ty::{InferTy, TyCtxt, TyS};
+use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
@@ -105,6 +106,116 @@ pub fn suggest_arbitrary_trait_bound(
     true
 }
 
+fn suggest_removing_unsized_bound(
+    generics: &hir::Generics<'_>,
+    err: &mut DiagnosticBuilder<'_>,
+    param_name: &str,
+    param: &hir::GenericParam<'_>,
+    def_id: Option<DefId>,
+) {
+    // See if there's a `?Sized` bound that can be removed to suggest that.
+    // First look at the `where` clause because we can have `where T: ?Sized`, but that
+    // `?Sized` bound is *also* included in the `GenericParam` as a bound, which breaks
+    // the spans. Hence the somewhat involved logic that follows.
+    let mut where_unsized_bounds = FxHashSet::default();
+    for (where_pos, predicate) in generics.where_clause.predicates.iter().enumerate() {
+        match predicate {
+            WherePredicate::BoundPredicate(WhereBoundPredicate {
+                bounded_ty:
+                    hir::Ty {
+                        kind:
+                            hir::TyKind::Path(hir::QPath::Resolved(
+                                None,
+                                hir::Path {
+                                    segments: [segment],
+                                    res: hir::def::Res::Def(hir::def::DefKind::TyParam, _),
+                                    ..
+                                },
+                            )),
+                        ..
+                    },
+                bounds,
+                span,
+                ..
+            }) if segment.ident.as_str() == param_name => {
+                for (pos, bound) in bounds.iter().enumerate() {
+                    match bound {
+                        hir::GenericBound::Unsized(_) => {}
+                        hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe)
+                            if poly.trait_ref.trait_def_id() == def_id => {}
+                        _ => continue,
+                    }
+                    let sp = match (
+                        bounds.len(),
+                        pos,
+                        generics.where_clause.predicates.len(),
+                        where_pos,
+                    ) {
+                        // where T: ?Sized
+                        // ^^^^^^^^^^^^^^^
+                        (1, _, 1, _) => generics.where_clause.span,
+                        // where Foo: Bar, T: ?Sized,
+                        //               ^^^^^^^^^^^
+                        (1, _, len, pos) if pos == len - 1 => generics.where_clause.predicates
+                            [pos - 1]
+                            .span()
+                            .shrink_to_hi()
+                            .to(*span),
+                        // where T: ?Sized, Foo: Bar,
+                        //       ^^^^^^^^^^^
+                        (1, _, _, pos) => {
+                            span.until(generics.where_clause.predicates[pos + 1].span())
+                        }
+                        // where T: ?Sized + Bar, Foo: Bar,
+                        //          ^^^^^^^^^
+                        (_, 0, _, _) => bound.span().to(bounds[1].span().shrink_to_lo()),
+                        // where T: Bar + ?Sized, Foo: Bar,
+                        //             ^^^^^^^^^
+                        (_, pos, _, _) => bounds[pos - 1].span().shrink_to_hi().to(bound.span()),
+                    };
+                    where_unsized_bounds.insert(bound.span());
+                    err.span_suggestion_verbose(
+                        sp,
+                        "consider removing the `?Sized` bound to make the \
+                            type parameter `Sized`",
+                        String::new(),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            }
+            _ => {}
+        }
+    }
+    for (pos, bound) in param.bounds.iter().enumerate() {
+        match bound {
+            hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe)
+                if poly.trait_ref.trait_def_id() == def_id
+                    && !where_unsized_bounds.contains(&bound.span()) =>
+            {
+                let sp = match (param.bounds.len(), pos) {
+                    // T: ?Sized,
+                    //  ^^^^^^^^
+                    (1, _) => param.span.shrink_to_hi().to(bound.span()),
+                    // T: ?Sized + Bar,
+                    //    ^^^^^^^^^
+                    (_, 0) => bound.span().to(param.bounds[1].span().shrink_to_lo()),
+                    // T: Bar + ?Sized,
+                    //       ^^^^^^^^^
+                    (_, pos) => param.bounds[pos - 1].span().shrink_to_hi().to(bound.span()),
+                };
+                err.span_suggestion_verbose(
+                    sp,
+                    "consider removing the `?Sized` bound to make the type parameter \
+                        `Sized`",
+                    String::new(),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            _ => {}
+        }
+    }
+}
+
 /// Suggest restricting a type param with a new bound.
 pub fn suggest_constraining_type_param(
     tcx: TyCtxt<'_>,
@@ -130,6 +241,7 @@ pub fn suggest_constraining_type_param(
     if def_id == tcx.lang_items().sized_trait() {
         // Type parameters are already `Sized` by default.
         err.span_label(param.span, &format!("this type parameter needs to be `{}`", constraint));
+        suggest_removing_unsized_bound(generics, err, param_name, param, def_id);
         return true;
     }
     let mut suggest_restrict = |span| {
diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs
index 4f8dc7d16d4..34302c3fb42 100644
--- a/compiler/rustc_save_analysis/src/dump_visitor.rs
+++ b/compiler/rustc_save_analysis/src/dump_visitor.rs
@@ -689,6 +689,7 @@ impl<'tcx> DumpVisitor<'tcx> {
                     (Some(self.tcx.require_lang_item(lang_item, Some(span))), span)
                 }
                 hir::GenericBound::Outlives(..) => continue,
+                hir::GenericBound::Unsized(_) => continue,
             };
 
             if let Some(id) = def_id {
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 9871b14754e..92583f2b0ea 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -943,7 +943,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                         false,
                     );
                 }
-                hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {}
+                hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe)
+                | hir::GenericBound::Unsized(_) => {}
                 hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => self
                     .instantiate_lang_item_trait_ref(
                         lang_item, span, hir_id, args, param_ty, bounds,
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index 997fdcefe03..ce74d6fec9e 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -2230,7 +2230,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
                             let constness = match modifier {
                                 hir::TraitBoundModifier::MaybeConst => hir::Constness::NotConst,
                                 hir::TraitBoundModifier::None => constness,
-                                hir::TraitBoundModifier::Maybe => bug!("this wasn't handled"),
+                                // We ignore `where T: ?Sized`, it is already part of
+                                // type parameter `T`.
+                                hir::TraitBoundModifier::Maybe => continue,
                             };
 
                             let mut bounds = Bounds::default();
@@ -2260,6 +2262,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
                             predicates.extend(bounds.predicates(tcx, ty));
                         }
 
+                        hir::GenericBound::Unsized(_) => {}
+
                         hir::GenericBound::Outlives(lifetime) => {
                             let region =
                                 <dyn AstConv<'_>>::ast_region_to_region(&icx, lifetime, None);
@@ -2521,6 +2525,7 @@ fn predicates_from_bound<'tcx>(
             );
             bounds.predicates(astconv.tcx(), param_ty)
         }
+        hir::GenericBound::Unsized(_) => vec![],
         hir::GenericBound::Outlives(ref lifetime) => {
             let region = astconv.ast_region_to_region(lifetime, None);
             let pred = ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(param_ty, region))
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index fd79292477c..75ea30bb565 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -128,6 +128,7 @@ impl Clean<GenericBound> for hir::GenericBound<'_> {
     fn clean(&self, cx: &mut DocContext<'_>) -> GenericBound {
         match *self {
             hir::GenericBound::Outlives(lt) => GenericBound::Outlives(lt.clean(cx)),
+            hir::GenericBound::Unsized(_) => GenericBound::maybe_sized(cx),
             hir::GenericBound::LangItemTrait(lang_item, span, _, generic_args) => {
                 let def_id = cx.tcx.require_lang_item(lang_item, Some(span));
 
@@ -562,13 +563,19 @@ impl Clean<Generics> for hir::Generics<'_> {
                 WherePredicate::BoundPredicate {
                     ty: Generic(ref name), ref mut bounds, ..
                 } => {
-                    if bounds.is_empty() {
+                    if let [] | [GenericBound::TraitBound(_, hir::TraitBoundModifier::Maybe)] =
+                        &bounds[..]
+                    {
                         for param in &mut generics.params {
                             match param.kind {
                                 GenericParamDefKind::Lifetime => {}
                                 GenericParamDefKind::Type { bounds: ref mut ty_bounds, .. } => {
                                     if &param.name == name {
                                         mem::swap(bounds, ty_bounds);
+                                        // We now keep track of `?Sized` obligations in the HIR.
+                                        // If we don't clear `ty_bounds` we end up with
+                                        // `fn foo<X: ?Sized>(_: X) where X: ?Sized`.
+                                        ty_bounds.clear();
                                         break;
                                     }
                                 }
diff --git a/src/test/ui/const-generics/const-argument-if-length.full.stderr b/src/test/ui/const-generics/const-argument-if-length.full.stderr
index c6088e665a2..a9f1d0eb657 100644
--- a/src/test/ui/const-generics/const-argument-if-length.full.stderr
+++ b/src/test/ui/const-generics/const-argument-if-length.full.stderr
@@ -10,6 +10,11 @@ LL |     if std::mem::size_of::<T>() == 0 {
    |
 LL | pub const fn size_of<T>() -> usize {
    |                      - required by this bound in `std::mem::size_of`
+   |
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | pub const fn is_zst<T>() -> usize {
+   |                     --
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
   --> $DIR/const-argument-if-length.rs:16:12
@@ -21,6 +26,10 @@ LL |     value: T,
    |
    = note: only the last field of a struct may have a dynamically sized type
    = help: change the field's type to have a statically known size
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | pub struct AtLeastByte<T> {
+   |                        --
 help: borrowed types always have a statically known size
    |
 LL |     value: &T,
diff --git a/src/test/ui/const-generics/const-argument-if-length.min.stderr b/src/test/ui/const-generics/const-argument-if-length.min.stderr
index bc06e8d7fb1..173a1471663 100644
--- a/src/test/ui/const-generics/const-argument-if-length.min.stderr
+++ b/src/test/ui/const-generics/const-argument-if-length.min.stderr
@@ -17,6 +17,10 @@ LL |     value: T,
    |
    = note: only the last field of a struct may have a dynamically sized type
    = help: change the field's type to have a statically known size
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | pub struct AtLeastByte<T> {
+   |                        --
 help: borrowed types always have a statically known size
    |
 LL |     value: &T,
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 2d12265df98..6c57dd9316f 100644
--- a/src/test/ui/dst/dst-object-from-unsized-type.stderr
+++ b/src/test/ui/dst/dst-object-from-unsized-type.stderr
@@ -7,6 +7,10 @@ LL |     let u: &dyn Foo = t;
    |                       ^ doesn't have a size known at compile-time
    |
    = note: required for the cast to the object type `dyn Foo`
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | fn test1<T: Foo>(t: &T) {
+   |            --
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
   --> $DIR/dst-object-from-unsized-type.rs:13:23
@@ -17,6 +21,10 @@ LL |     let v: &dyn Foo = t as &dyn Foo;
    |                       ^ doesn't have a size known at compile-time
    |
    = note: required for the cast to the object type `dyn Foo`
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | fn test2<T: Foo>(t: &T) {
+   |            --
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
   --> $DIR/dst-object-from-unsized-type.rs:18:28
diff --git a/src/test/ui/packed/issue-27060-2.stderr b/src/test/ui/packed/issue-27060-2.stderr
index 5dbcc96e874..64e061a89b4 100644
--- a/src/test/ui/packed/issue-27060-2.stderr
+++ b/src/test/ui/packed/issue-27060-2.stderr
@@ -8,6 +8,10 @@ LL |     data: T,
    |
    = note: the last field of a packed struct may only have a dynamically sized type if it does not need drop to be run
    = help: change the field's type to have a statically known size
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | pub struct Bad<T> {
+   |                --
 help: borrowed types always have a statically known size
    |
 LL |     data: &T,
diff --git a/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr
index 18ba7254446..ac3902dc6de 100644
--- a/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr
+++ b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr
@@ -91,6 +91,10 @@ LL | struct X<T>(T);
    |          ^  - ...if indirection were used here: `Box<T>`
    |          |
    |          this could be changed to `T: ?Sized`...
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | struct Struct5<T>{
+   |                --
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/trait-bounds/unsized-bound.rs b/src/test/ui/trait-bounds/unsized-bound.rs
new file mode 100644
index 00000000000..035b8ef1bde
--- /dev/null
+++ b/src/test/ui/trait-bounds/unsized-bound.rs
@@ -0,0 +1,32 @@
+trait Trait<A> {}
+impl<A, B> Trait<(A, B)> for (A, B) where A: ?Sized, B: ?Sized, {}
+//~^ ERROR E0277
+//~| ERROR E0277
+impl<A, B: ?Sized, C: ?Sized> Trait<(A, B, C)> for (A, B, C) where A: ?Sized, {}
+//~^ ERROR E0277
+//~| ERROR E0277
+//~| ERROR E0277
+trait Trait2<A> {}
+impl<A: ?Sized, B: ?Sized> Trait2<(A, B)> for (A, B) {}
+//~^ ERROR E0277
+//~| ERROR E0277
+trait Trait3<A> {}
+impl<A> Trait3<A> for A where A: ?Sized {}
+//~^ ERROR E0277
+trait Trait4<A> {}
+impl<A: ?Sized> Trait4<A> for A {}
+//~^ ERROR E0277
+trait Trait5<A, B> {}
+impl<X, Y> Trait5<X, Y> for X where X: ?Sized {}
+//~^ ERROR E0277
+trait Trait6<A, B> {}
+impl<X: ?Sized, Y> Trait6<X, Y> for X {}
+//~^ ERROR E0277
+trait Trait7<A, B> {}
+impl<X, Y> Trait7<X, Y> for X where Y: ?Sized {}
+//~^ ERROR E0277
+trait Trait8<A, B> {}
+impl<X, Y: ?Sized> Trait8<X, Y> for X {}
+//~^ ERROR E0277
+
+fn main() {}
diff --git a/src/test/ui/trait-bounds/unsized-bound.stderr b/src/test/ui/trait-bounds/unsized-bound.stderr
new file mode 100644
index 00000000000..30163ab7978
--- /dev/null
+++ b/src/test/ui/trait-bounds/unsized-bound.stderr
@@ -0,0 +1,234 @@
+error[E0277]: the size for values of type `B` cannot be known at compilation time
+  --> $DIR/unsized-bound.rs:2:12
+   |
+LL | trait Trait<A> {}
+   |             - required by this bound in `Trait`
+LL | impl<A, B> Trait<(A, B)> for (A, B) where A: ?Sized, B: ?Sized, {}
+   |         -  ^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |         |
+   |         this type parameter needs to be `std::marker::Sized`
+   |
+   = note: required because it appears within the type `(A, B)`
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | impl<A, B> Trait<(A, B)> for (A, B) where A: ?Sized, {}
+   |                                                   --
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | trait Trait<A: ?Sized> {}
+   |              ^^^^^^^^
+
+error[E0277]: the size for values of type `A` cannot be known at compilation time
+  --> $DIR/unsized-bound.rs:2:30
+   |
+LL | impl<A, B> Trait<(A, B)> for (A, B) where A: ?Sized, B: ?Sized, {}
+   |      -                       ^^^^^^ doesn't have a size known at compile-time
+   |      |
+   |      this type parameter needs to be `std::marker::Sized`
+   |
+   = note: only the last element of a tuple may have a dynamically sized type
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | impl<A, B> Trait<(A, B)> for (A, B) where B: ?Sized, {}
+   |                                          --
+
+error[E0277]: the size for values of type `C` cannot be known at compilation time
+  --> $DIR/unsized-bound.rs:5:31
+   |
+LL | trait Trait<A> {}
+   |             - required by this bound in `Trait`
+...
+LL | impl<A, B: ?Sized, C: ?Sized> Trait<(A, B, C)> for (A, B, C) where A: ?Sized, {}
+   |                    -          ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |                    |
+   |                    this type parameter needs to be `std::marker::Sized`
+   |
+   = note: required because it appears within the type `(A, B, C)`
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | impl<A, B: ?Sized, C> Trait<(A, B, C)> for (A, B, C) where A: ?Sized, {}
+   |                    --
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | trait Trait<A: ?Sized> {}
+   |              ^^^^^^^^
+
+error[E0277]: the size for values of type `A` cannot be known at compilation time
+  --> $DIR/unsized-bound.rs:5:52
+   |
+LL | impl<A, B: ?Sized, C: ?Sized> Trait<(A, B, C)> for (A, B, C) where A: ?Sized, {}
+   |      -                                             ^^^^^^^^^ doesn't have a size known at compile-time
+   |      |
+   |      this type parameter needs to be `std::marker::Sized`
+   |
+   = note: only the last element of a tuple may have a dynamically sized type
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | impl<A, B: ?Sized, C: ?Sized> Trait<(A, B, C)> for (A, B, C)  {}
+   |                                                             --
+
+error[E0277]: the size for values of type `B` cannot be known at compilation time
+  --> $DIR/unsized-bound.rs:5:52
+   |
+LL | impl<A, B: ?Sized, C: ?Sized> Trait<(A, B, C)> for (A, B, C) where A: ?Sized, {}
+   |         -                                          ^^^^^^^^^ doesn't have a size known at compile-time
+   |         |
+   |         this type parameter needs to be `std::marker::Sized`
+   |
+   = note: only the last element of a tuple may have a dynamically sized type
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | impl<A, B, C: ?Sized> Trait<(A, B, C)> for (A, B, C) where A: ?Sized, {}
+   |         --
+
+error[E0277]: the size for values of type `B` cannot be known at compilation time
+  --> $DIR/unsized-bound.rs:10:28
+   |
+LL | trait Trait2<A> {}
+   |              - required by this bound in `Trait2`
+LL | impl<A: ?Sized, B: ?Sized> Trait2<(A, B)> for (A, B) {}
+   |                 -          ^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |                 |
+   |                 this type parameter needs to be `std::marker::Sized`
+   |
+   = note: required because it appears within the type `(A, B)`
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | impl<A: ?Sized, B> Trait2<(A, B)> for (A, B) {}
+   |                 --
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | trait Trait2<A: ?Sized> {}
+   |               ^^^^^^^^
+
+error[E0277]: the size for values of type `A` cannot be known at compilation time
+  --> $DIR/unsized-bound.rs:10:47
+   |
+LL | impl<A: ?Sized, B: ?Sized> Trait2<(A, B)> for (A, B) {}
+   |      -                                        ^^^^^^ doesn't have a size known at compile-time
+   |      |
+   |      this type parameter needs to be `std::marker::Sized`
+   |
+   = note: only the last element of a tuple may have a dynamically sized type
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | impl<A, B: ?Sized> Trait2<(A, B)> for (A, B) {}
+   |      --
+
+error[E0277]: the size for values of type `A` cannot be known at compilation time
+  --> $DIR/unsized-bound.rs:14:9
+   |
+LL | trait Trait3<A> {}
+   |              - required by this bound in `Trait3`
+LL | impl<A> Trait3<A> for A where A: ?Sized {}
+   |      -  ^^^^^^^^^ doesn't have a size known at compile-time
+   |      |
+   |      this type parameter needs to be `std::marker::Sized`
+   |
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | impl<A> Trait3<A> for A  {}
+   |                        --
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | trait Trait3<A: ?Sized> {}
+   |               ^^^^^^^^
+
+error[E0277]: the size for values of type `A` cannot be known at compilation time
+  --> $DIR/unsized-bound.rs:17:17
+   |
+LL | trait Trait4<A> {}
+   |              - required by this bound in `Trait4`
+LL | impl<A: ?Sized> Trait4<A> for A {}
+   |      -          ^^^^^^^^^ doesn't have a size known at compile-time
+   |      |
+   |      this type parameter needs to be `std::marker::Sized`
+   |
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | impl<A> Trait4<A> for A {}
+   |      --
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | trait Trait4<A: ?Sized> {}
+   |               ^^^^^^^^
+
+error[E0277]: the size for values of type `X` cannot be known at compilation time
+  --> $DIR/unsized-bound.rs:20:12
+   |
+LL | trait Trait5<A, B> {}
+   |              - required by this bound in `Trait5`
+LL | impl<X, Y> Trait5<X, Y> for X where X: ?Sized {}
+   |      -     ^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |      |
+   |      this type parameter needs to be `std::marker::Sized`
+   |
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | impl<X, Y> Trait5<X, Y> for X  {}
+   |                              --
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | trait Trait5<A: ?Sized, B> {}
+   |               ^^^^^^^^
+
+error[E0277]: the size for values of type `X` cannot be known at compilation time
+  --> $DIR/unsized-bound.rs:23:20
+   |
+LL | trait Trait6<A, B> {}
+   |              - required by this bound in `Trait6`
+LL | impl<X: ?Sized, Y> Trait6<X, Y> for X {}
+   |      -             ^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |      |
+   |      this type parameter needs to be `std::marker::Sized`
+   |
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | impl<X, Y> Trait6<X, Y> for X {}
+   |      --
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | trait Trait6<A: ?Sized, B> {}
+   |               ^^^^^^^^
+
+error[E0277]: the size for values of type `Y` cannot be known at compilation time
+  --> $DIR/unsized-bound.rs:26:12
+   |
+LL | trait Trait7<A, B> {}
+   |                 - required by this bound in `Trait7`
+LL | impl<X, Y> Trait7<X, Y> for X where Y: ?Sized {}
+   |         -  ^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |         |
+   |         this type parameter needs to be `std::marker::Sized`
+   |
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | impl<X, Y> Trait7<X, Y> for X  {}
+   |                              --
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | trait Trait7<A, B: ?Sized> {}
+   |                  ^^^^^^^^
+
+error[E0277]: the size for values of type `Y` cannot be known at compilation time
+  --> $DIR/unsized-bound.rs:29:20
+   |
+LL | trait Trait8<A, B> {}
+   |                 - required by this bound in `Trait8`
+LL | impl<X, Y: ?Sized> Trait8<X, Y> for X {}
+   |         -          ^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |         |
+   |         this type parameter needs to be `std::marker::Sized`
+   |
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | impl<X, Y> Trait8<X, Y> for X {}
+   |         --
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | trait Trait8<A, B: ?Sized> {}
+   |                  ^^^^^^^^
+
+error: aborting due to 13 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/traits/suggest-where-clause.stderr b/src/test/ui/traits/suggest-where-clause.stderr
index f15e7e35839..47f287807d4 100644
--- a/src/test/ui/traits/suggest-where-clause.stderr
+++ b/src/test/ui/traits/suggest-where-clause.stderr
@@ -11,6 +11,11 @@ LL |     mem::size_of::<U>();
    |
 LL | pub const fn size_of<T>() -> usize {
    |                      - required by this bound in `std::mem::size_of`
+   |
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | fn check<T: Iterator, U>() {
+   |                       --
 
 error[E0277]: the size for values of type `U` cannot be known at compilation time
   --> $DIR/suggest-where-clause.rs:10:5
@@ -31,6 +36,10 @@ note: required because it appears within the type `Misc<U>`
    |
 LL | struct Misc<T:?Sized>(T);
    |        ^^^^
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | fn check<T: Iterator, U>() {
+   |                       --
 
 error[E0277]: the trait bound `u64: From<T>` is not satisfied
   --> $DIR/suggest-where-clause.rs:15:5
diff --git a/src/test/ui/union/union-sized-field.stderr b/src/test/ui/union/union-sized-field.stderr
index b916bbe8ad1..ef86c624e9b 100644
--- a/src/test/ui/union/union-sized-field.stderr
+++ b/src/test/ui/union/union-sized-field.stderr
@@ -8,6 +8,10 @@ LL |     value: T,
    |
    = note: no field of a union may have a dynamically sized type
    = help: change the field's type to have a statically known size
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | union Foo<T> {
+   |           --
 help: borrowed types always have a statically known size
    |
 LL |     value: &T,
@@ -27,6 +31,10 @@ LL |     value: T,
    |
    = note: only the last field of a struct may have a dynamically sized type
    = help: change the field's type to have a statically known size
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | struct Foo2<T> {
+   |             --
 help: borrowed types always have a statically known size
    |
 LL |     value: &T,
@@ -46,6 +54,10 @@ LL |     Value(T),
    |
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | enum Foo3<T> {
+   |           --
 help: borrowed types always have a statically known size
    |
 LL |     Value(&T),
diff --git a/src/test/ui/unsized/unsized-bare-typaram.stderr b/src/test/ui/unsized/unsized-bare-typaram.stderr
index 19978ae24ca..35bba1c103a 100644
--- a/src/test/ui/unsized/unsized-bare-typaram.stderr
+++ b/src/test/ui/unsized/unsized-bare-typaram.stderr
@@ -7,6 +7,11 @@ LL | fn foo<T: ?Sized>() { bar::<T>() }
    |        -                    ^ doesn't have a size known at compile-time
    |        |
    |        this type parameter needs to be `std::marker::Sized`
+   |
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | fn foo<T>() { bar::<T>() }
+   |        --
 
 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 601db7d1cd9..f66ce2af304 100644
--- a/src/test/ui/unsized/unsized-enum.stderr
+++ b/src/test/ui/unsized/unsized-enum.stderr
@@ -16,6 +16,10 @@ LL | enum Foo<U> { FooSome(U), FooNone }
    |          ^            - ...if indirection were used here: `Box<U>`
    |          |
    |          this could be changed to `U: ?Sized`...
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | fn foo2<T>() { not_sized::<Foo<T>>() }
+   |         --
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unsized/unsized-enum2.stderr b/src/test/ui/unsized/unsized-enum2.stderr
index 1b6c8585815..b9a03d904af 100644
--- a/src/test/ui/unsized/unsized-enum2.stderr
+++ b/src/test/ui/unsized/unsized-enum2.stderr
@@ -9,6 +9,10 @@ LL |     VA(W),
    |
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | enum E<W, X: ?Sized, Y: ?Sized, Z: ?Sized> {
+   |        --
 help: borrowed types always have a statically known size
    |
 LL |     VA(&W),
@@ -29,6 +33,10 @@ LL |     VB{x: X},
    |
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | enum E<W: ?Sized, X, Y: ?Sized, Z: ?Sized> {
+   |                   --
 help: borrowed types always have a statically known size
    |
 LL |     VB{x: &X},
@@ -49,6 +57,10 @@ LL |     VC(isize, Y),
    |
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | enum E<W: ?Sized, X: ?Sized, Y, Z: ?Sized> {
+   |                              --
 help: borrowed types always have a statically known size
    |
 LL |     VC(isize, &Y),
@@ -69,6 +81,10 @@ LL |     VD{u: isize, x: Z},
    |
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | enum E<W: ?Sized, X: ?Sized, Y: ?Sized, Z> {
+   |                                         --
 help: borrowed types always have a statically known size
    |
 LL |     VD{u: isize, x: &Z},
diff --git a/src/test/ui/unsized/unsized-fn-arg.fixed b/src/test/ui/unsized/unsized-fn-arg.fixed
index 2c686c6c2b2..fd9b159a481 100644
--- a/src/test/ui/unsized/unsized-fn-arg.fixed
+++ b/src/test/ui/unsized/unsized-fn-arg.fixed
@@ -2,5 +2,5 @@
 #![crate_type="lib"]
 #![allow(unused)]
 
-fn f<T: ?Sized>(t: &T) {}
+fn f<T>(t: &T) {}
 //~^ ERROR the size for values of type `T` cannot be known at compilation time
diff --git a/src/test/ui/unsized/unsized-fn-arg.stderr b/src/test/ui/unsized/unsized-fn-arg.stderr
index 6b802ddf542..acb8a598d2c 100644
--- a/src/test/ui/unsized/unsized-fn-arg.stderr
+++ b/src/test/ui/unsized/unsized-fn-arg.stderr
@@ -7,6 +7,10 @@ LL | fn f<T: ?Sized>(t: T) {}
    |      this type parameter needs to be `std::marker::Sized`
    |
    = help: unsized fn params are gated as an unstable feature
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | fn f<T>(t: T) {}
+   |      --
 help: function arguments must have a statically known size, borrowed types always have a known size
    |
 LL | fn f<T: ?Sized>(t: &T) {}
diff --git a/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr b/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr
index 9d072eda4e8..99f75d8c5b3 100644
--- a/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr
+++ b/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr
@@ -16,6 +16,10 @@ LL | struct S5<Y>(Y);
    |           ^  - ...if indirection were used here: `Box<Y>`
    |           |
    |           this could be changed to `Y: ?Sized`...
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | impl<X> S5<X> {
+   |      --
 
 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 e38375bff46..71693b8130d 100644
--- a/src/test/ui/unsized/unsized-struct.stderr
+++ b/src/test/ui/unsized/unsized-struct.stderr
@@ -16,6 +16,10 @@ LL | struct Foo<T> { data: T }
    |            ^          - ...if indirection were used here: `Box<T>`
    |            |
    |            this could be changed to `T: ?Sized`...
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | fn foo2<T>() { not_sized::<Foo<T>>() }
+   |         --
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
   --> $DIR/unsized-struct.rs:13:24
@@ -33,6 +37,10 @@ note: required because it appears within the type `Bar<T>`
    |
 LL | struct Bar<T: ?Sized> { data: T }
    |        ^^^
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | fn bar2<T>() { is_sized::<Bar<T>>() }
+   |         --
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/unsized/unsized-trait-impl-self-type.stderr b/src/test/ui/unsized/unsized-trait-impl-self-type.stderr
index aef0d0cbb83..201dbf85d20 100644
--- a/src/test/ui/unsized/unsized-trait-impl-self-type.stderr
+++ b/src/test/ui/unsized/unsized-trait-impl-self-type.stderr
@@ -16,6 +16,10 @@ LL | struct S5<Y>(Y);
    |           ^  - ...if indirection were used here: `Box<Y>`
    |           |
    |           this could be changed to `Y: ?Sized`...
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | impl<X> T3<X> for S5<X> {
+   |      --
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr b/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr
index f48d4ef9f14..f8f8aa8e3e9 100644
--- a/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr
+++ b/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr
@@ -9,6 +9,10 @@ LL | impl<X: ?Sized> T2<X> for S4<X> {
    |      |
    |      this type parameter needs to be `std::marker::Sized`
    |
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | impl<X> T2<X> for S4<X> {
+   |      --
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | trait T2<Z: ?Sized> {
diff --git a/src/test/ui/unsized/unsized3.stderr b/src/test/ui/unsized/unsized3.stderr
index bd36008aca0..10ddfe34eac 100644
--- a/src/test/ui/unsized/unsized3.stderr
+++ b/src/test/ui/unsized/unsized3.stderr
@@ -9,6 +9,10 @@ LL |     f2::<X>(x);
 LL | fn f2<X>(x: &X) {
    |       - required by this bound in `f2`
    |
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | fn f1<X>(x: &X) {
+   |       --
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | fn f2<X: ?Sized>(x: &X) {
@@ -25,6 +29,10 @@ LL |     f4::<X>(x);
 LL | fn f4<X: T>(x: &X) {
    |       - required by this bound in `f4`
    |
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | fn f3<X: T>(x: &X) {
+   |         --
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | fn f4<X: T + ?Sized>(x: &X) {
@@ -46,6 +54,10 @@ note: required because it appears within the type `S<X>`
    |
 LL | struct S<X: ?Sized> {
    |        ^
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | fn f8<X>(x1: &S<X>, x2: &S<X>) {
+   |       --
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | fn f5<Y: ?Sized>(x: &Y) {}
@@ -65,6 +77,10 @@ note: required because it appears within the type `S<X>`
 LL | struct S<X: ?Sized> {
    |        ^
    = note: only the last element of a tuple may have a dynamically sized type
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | fn f9<X>(x1: Box<S<X>>) {
+   |       --
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized3.rs:45:9
@@ -81,6 +97,10 @@ LL | struct S<X: ?Sized> {
    |        ^
    = note: required because it appears within the type `({integer}, S<X>)`
    = note: tuples must have a statically known size to be initialized
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | fn f10<X>(x1: Box<S<X>>) {
+   |        --
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized3.rs:45:8
@@ -99,6 +119,10 @@ note: required because it appears within the type `S<X>`
 LL | struct S<X: ?Sized> {
    |        ^
    = note: required because it appears within the type `({integer}, S<X>)`
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | fn f10<X>(x1: Box<S<X>>) {
+   |        --
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | fn f5<Y: ?Sized>(x: &Y) {}
diff --git a/src/test/ui/unsized/unsized5.stderr b/src/test/ui/unsized/unsized5.stderr
index 0bfd4565529..6e5b3556429 100644
--- a/src/test/ui/unsized/unsized5.stderr
+++ b/src/test/ui/unsized/unsized5.stderr
@@ -8,6 +8,10 @@ LL |     f1: X,
    |
    = note: only the last field of a struct may have a dynamically sized type
    = help: change the field's type to have a statically known size
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | struct S1<X> {
+   |           --
 help: borrowed types always have a statically known size
    |
 LL |     f1: &X,
@@ -28,6 +32,10 @@ LL |     g: X,
    |
    = note: only the last field of a struct may have a dynamically sized type
    = help: change the field's type to have a statically known size
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | struct S2<X> {
+   |           --
 help: borrowed types always have a statically known size
    |
 LL |     g: &X,
@@ -83,6 +91,10 @@ LL |     V1(X, isize),
    |
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | enum E<X> {
+   |        --
 help: borrowed types always have a statically known size
    |
 LL |     V1(&X, isize),
@@ -102,6 +114,10 @@ LL |     V2{f1: X, f: isize},
    |
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | enum F<X> {
+   |        --
 help: borrowed types always have a statically known size
    |
 LL |     V2{f1: &X, f: isize},
diff --git a/src/test/ui/unsized/unsized6.stderr b/src/test/ui/unsized/unsized6.stderr
index 8e5734dffb1..5eff89d971f 100644
--- a/src/test/ui/unsized/unsized6.stderr
+++ b/src/test/ui/unsized/unsized6.stderr
@@ -9,6 +9,10 @@ LL |     let y: Y;
    |
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | fn f1<W: ?Sized, X: ?Sized, Y, Z: ?Sized>(x: &X) {
+   |                             --
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:7:12
@@ -20,6 +24,10 @@ LL |     let _: (isize, (X, isize));
    |            ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = note: only the last element of a tuple may have a dynamically sized type
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | fn f1<W: ?Sized, X, Y: ?Sized, Z: ?Sized>(x: &X) {
+   |                  --
 
 error[E0277]: the size for values of type `Z` cannot be known at compilation time
   --> $DIR/unsized6.rs:11:12
@@ -31,6 +39,10 @@ LL |     let y: (isize, (Z, usize));
    |            ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = note: only the last element of a tuple may have a dynamically sized type
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | fn f1<W: ?Sized, X: ?Sized, Y: ?Sized, Z>(x: &X) {
+   |                                        --
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:15:9
@@ -42,6 +54,10 @@ LL |     let y: X;
    |
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | fn f2<X, Y: ?Sized>(x: &X) {
+   |       --
 
 error[E0277]: the size for values of type `Y` cannot be known at compilation time
   --> $DIR/unsized6.rs:17:12
@@ -53,6 +69,10 @@ LL |     let y: (isize, (Y, isize));
    |            ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = note: only the last element of a tuple may have a dynamically sized type
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | fn f2<X: ?Sized, Y>(x: &X) {
+   |                  --
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:22:9
@@ -64,6 +84,10 @@ LL |     let y: X = *x1;
    |
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | fn f3<X>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
+   |       --
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:24:9
@@ -76,6 +100,10 @@ LL |     let y = *x2;
    |
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | fn f3<X>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
+   |       --
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:26:10
@@ -88,6 +116,10 @@ LL |     let (y, z) = (*x3, 4);
    |
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | fn f3<X>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
+   |       --
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:30:9
@@ -99,6 +131,10 @@ LL |     let y: X = *x1;
    |
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | fn f4<X: T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
+   |         --
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:32:9
@@ -111,6 +147,10 @@ LL |     let y = *x2;
    |
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | fn f4<X: T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
+   |         --
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:34:10
@@ -123,6 +163,10 @@ LL |     let (y, z) = (*x3, 4);
    |
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | fn f4<X: T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
+   |         --
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:38:18
@@ -133,6 +177,10 @@ LL | fn g1<X: ?Sized>(x: X) {}
    |       this type parameter needs to be `std::marker::Sized`
    |
    = help: unsized fn params are gated as an unstable feature
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | fn g1<X>(x: X) {}
+   |       --
 help: function arguments must have a statically known size, borrowed types always have a known size
    |
 LL | fn g1<X: ?Sized>(x: &X) {}
@@ -147,6 +195,10 @@ LL | fn g2<X: ?Sized + T>(x: X) {}
    |       this type parameter needs to be `std::marker::Sized`
    |
    = help: unsized fn params are gated as an unstable feature
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | fn g2<X: T>(x: X) {}
+   |         --
 help: function arguments must have a statically known size, borrowed types always have a known size
    |
 LL | fn g2<X: ?Sized + T>(x: &X) {}
diff --git a/src/test/ui/unsized/unsized7.stderr b/src/test/ui/unsized/unsized7.stderr
index 7dbddd4ed24..e0d95e21296 100644
--- a/src/test/ui/unsized/unsized7.stderr
+++ b/src/test/ui/unsized/unsized7.stderr
@@ -9,6 +9,10 @@ LL | impl<X: ?Sized + T> T1<X> for S3<X> {
    |      |
    |      this type parameter needs to be `std::marker::Sized`
    |
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL | impl<X: T> T1<X> for S3<X> {
+   |        --
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | trait T1<Z: T + ?Sized> {