about summary refs log tree commit diff
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2020-06-19 09:15:06 -0700
committerGitHub <noreply@github.com>2020-06-19 09:15:06 -0700
commit4910206b4a5b36ce0d82e08f1e33e72875fd28df (patch)
treed8e7dbb9c3f5a5a5159a47c8543ba9f225550a27
parent17064dae1a91fb7a96f68508a052826d0f4e1d8a (diff)
parent40b27ff5f3828abd8d1ab951853bf70b5fbf6ed5 (diff)
downloadrust-4910206b4a5b36ce0d82e08f1e33e72875fd28df.tar.gz
rust-4910206b4a5b36ce0d82e08f1e33e72875fd28df.zip
Rollup merge of #73261 - estebank:generics-sized, r=nikomatsakis
Suggest `?Sized` when applicable for ADTs

Address #71790, fix #27964.
-rw-r--r--src/librustc_hir/hir.rs10
-rw-r--r--src/librustc_trait_selection/traits/error_reporting/mod.rs156
-rw-r--r--src/test/ui/dst/dst-sized-trait-param.stderr4
-rw-r--r--src/test/ui/extern/extern-types-unsized.stderr12
-rw-r--r--src/test/ui/issues/issue-10412.stderr4
-rw-r--r--src/test/ui/issues/issue-18919.stderr7
-rw-r--r--src/test/ui/issues/issue-23281.stderr7
-rw-r--r--src/test/ui/suggestions/adt-param-with-implicit-sized-bound.rs28
-rw-r--r--src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr107
-rw-r--r--src/test/ui/unsized/unsized-enum.stderr7
-rw-r--r--src/test/ui/unsized/unsized-inherent-impl-self-type.stderr7
-rw-r--r--src/test/ui/unsized/unsized-struct.stderr7
-rw-r--r--src/test/ui/unsized/unsized-trait-impl-self-type.stderr7
-rw-r--r--src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr4
-rw-r--r--src/test/ui/unsized3.stderr8
-rw-r--r--src/test/ui/unsized7.stderr4
-rw-r--r--src/test/ui/wf/wf-fn-where-clause.stderr7
17 files changed, 352 insertions, 34 deletions
diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs
index bed2044c708..e7d63c138f3 100644
--- a/src/librustc_hir/hir.rs
+++ b/src/librustc_hir/hir.rs
@@ -2741,14 +2741,8 @@ impl Node<'_> {
     pub fn generics(&self) -> Option<&Generics<'_>> {
         match self {
             Node::TraitItem(TraitItem { generics, .. })
-            | Node::ImplItem(ImplItem { generics, .. })
-            | Node::Item(Item {
-                kind:
-                    ItemKind::Trait(_, _, generics, ..)
-                    | ItemKind::Impl { generics, .. }
-                    | ItemKind::Fn(_, generics, _),
-                ..
-            }) => Some(generics),
+            | Node::ImplItem(ImplItem { generics, .. }) => Some(generics),
+            Node::Item(item) => item.kind.generics(),
             _ => None,
         }
     }
diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs
index e5a6c9a2e39..060877f80ad 100644
--- a/src/librustc_trait_selection/traits/error_reporting/mod.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs
@@ -15,6 +15,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::intravisit::Visitor;
 use rustc_hir::Node;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::error::ExpectedFound;
@@ -25,7 +26,7 @@ use rustc_middle::ty::{
     TypeFoldable, WithConstness,
 };
 use rustc_session::DiagnosticMessageId;
-use rustc_span::{ExpnKind, Span, DUMMY_SP};
+use rustc_span::{ExpnKind, MultiSpan, Span, DUMMY_SP};
 use std::fmt;
 
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
@@ -1695,36 +1696,95 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
         err: &mut DiagnosticBuilder<'tcx>,
         obligation: &PredicateObligation<'tcx>,
     ) {
-        if let (
-            ty::PredicateKind::Trait(pred, _),
-            ObligationCauseCode::BindingObligation(item_def_id, span),
-        ) = (obligation.predicate.kind(), &obligation.cause.code)
-        {
-            if let (Some(generics), true) = (
-                self.tcx.hir().get_if_local(*item_def_id).as_ref().and_then(|n| n.generics()),
-                Some(pred.def_id()) == self.tcx.lang_items().sized_trait(),
-            ) {
-                for param in generics.params {
-                    if param.span == *span
-                        && !param.bounds.iter().any(|bound| {
-                            bound.trait_ref().and_then(|trait_ref| trait_ref.trait_def_id())
-                                == self.tcx.lang_items().sized_trait()
-                        })
-                    {
-                        let (span, separator) = match param.bounds {
-                            [] => (span.shrink_to_hi(), ":"),
-                            [.., bound] => (bound.span().shrink_to_hi(), " +"),
-                        };
-                        err.span_suggestion_verbose(
-                            span,
-                            "consider relaxing the implicit `Sized` restriction",
-                            format!("{} ?Sized", separator),
-                            Applicability::MachineApplicable,
+        let (pred, item_def_id, span) =
+            match (obligation.predicate.kind(), &obligation.cause.code.peel_derives()) {
+                (
+                    ty::PredicateKind::Trait(pred, _),
+                    ObligationCauseCode::BindingObligation(item_def_id, span),
+                ) => (pred, item_def_id, span),
+                _ => return,
+            };
+
+        let node = match (
+            self.tcx.hir().get_if_local(*item_def_id),
+            Some(pred.def_id()) == self.tcx.lang_items().sized_trait(),
+        ) {
+            (Some(node), true) => node,
+            _ => return,
+        };
+        let generics = match node.generics() {
+            Some(generics) => generics,
+            None => return,
+        };
+        for param in generics.params {
+            if param.span != *span
+                || param.bounds.iter().any(|bound| {
+                    bound.trait_ref().and_then(|trait_ref| trait_ref.trait_def_id())
+                        == self.tcx.lang_items().sized_trait()
+                })
+            {
+                continue;
+            }
+            match node {
+                hir::Node::Item(
+                    item
+                    @
+                    hir::Item {
+                        kind:
+                            hir::ItemKind::Enum(..)
+                            | hir::ItemKind::Struct(..)
+                            | hir::ItemKind::Union(..),
+                        ..
+                    },
+                ) => {
+                    // Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a
+                    // borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);`
+                    // is not.
+                    let mut visitor = FindTypeParam {
+                        param: param.name.ident().name,
+                        invalid_spans: vec![],
+                        nested: false,
+                    };
+                    visitor.visit_item(item);
+                    if !visitor.invalid_spans.is_empty() {
+                        let mut multispan: MultiSpan = param.span.into();
+                        multispan.push_span_label(
+                            param.span,
+                            format!("this could be changed to `{}: ?Sized`...", param.name.ident()),
+                        );
+                        for sp in visitor.invalid_spans {
+                            multispan.push_span_label(
+                                sp,
+                                format!(
+                                    "...if indirection was used here: `Box<{}>`",
+                                    param.name.ident(),
+                                ),
+                            );
+                        }
+                        err.span_help(
+                            multispan,
+                            &format!(
+                                "you could relax the implicit `Sized` bound on `{T}` if it were \
+                                 used through indirection like `&{T}` or `Box<{T}>`",
+                                T = param.name.ident(),
+                            ),
                         );
                         return;
                     }
                 }
+                _ => {}
             }
+            let (span, separator) = match param.bounds {
+                [] => (span.shrink_to_hi(), ":"),
+                [.., bound] => (bound.span().shrink_to_hi(), " +"),
+            };
+            err.span_suggestion_verbose(
+                span,
+                "consider relaxing the implicit `Sized` restriction",
+                format!("{} ?Sized", separator),
+                Applicability::MachineApplicable,
+            );
+            return;
         }
     }
 
@@ -1744,6 +1804,50 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
     }
 }
 
+/// Look for type `param` in an ADT being used only through a reference to confirm that suggesting
+/// `param: ?Sized` would be a valid constraint.
+struct FindTypeParam {
+    param: rustc_span::Symbol,
+    invalid_spans: Vec<Span>,
+    nested: bool,
+}
+
+impl<'v> Visitor<'v> for FindTypeParam {
+    type Map = rustc_hir::intravisit::ErasedMap<'v>;
+
+    fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
+        hir::intravisit::NestedVisitorMap::None
+    }
+
+    fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
+        // We collect the spans of all uses of the "bare" type param, like in `field: T` or
+        // `field: (T, T)` where we could make `T: ?Sized` while skipping cases that are known to be
+        // valid like `field: &'a T` or `field: *mut T` and cases that *might* have further `Sized`
+        // obligations like `Box<T>` and `Vec<T>`, but we perform no extra analysis for those cases
+        // and suggest `T: ?Sized` regardless of their obligations. This is fine because the errors
+        // in that case should make what happened clear enough.
+        match ty.kind {
+            hir::TyKind::Ptr(_) | hir::TyKind::Rptr(..) | hir::TyKind::TraitObject(..) => {}
+            hir::TyKind::Path(hir::QPath::Resolved(None, path))
+                if path.segments.len() == 1 && path.segments[0].ident.name == self.param =>
+            {
+                if !self.nested {
+                    self.invalid_spans.push(ty.span);
+                }
+            }
+            hir::TyKind::Path(_) => {
+                let prev = self.nested;
+                self.nested = true;
+                hir::intravisit::walk_ty(self, ty);
+                self.nested = prev;
+            }
+            _ => {
+                hir::intravisit::walk_ty(self, ty);
+            }
+        }
+    }
+}
+
 pub fn recursive_type_with_infinite_size_error(
     tcx: TyCtxt<'tcx>,
     type_def_id: DefId,
diff --git a/src/test/ui/dst/dst-sized-trait-param.stderr b/src/test/ui/dst/dst-sized-trait-param.stderr
index 749d569b9ae..006a334021b 100644
--- a/src/test/ui/dst/dst-sized-trait-param.stderr
+++ b/src/test/ui/dst/dst-sized-trait-param.stderr
@@ -9,6 +9,10 @@ LL | impl Foo<[isize]> for usize { }
    |
    = help: the trait `std::marker::Sized` is not implemented for `[isize]`
    = 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 relaxing the implicit `Sized` restriction
+   |
+LL | trait Foo<T: ?Sized> : Sized { fn take(self, x: &T) { } } // Note: T is sized
+   |            ^^^^^^^^
 
 error[E0277]: the size for values of type `[usize]` cannot be known at compilation time
   --> $DIR/dst-sized-trait-param.rs:10:6
diff --git a/src/test/ui/extern/extern-types-unsized.stderr b/src/test/ui/extern/extern-types-unsized.stderr
index 9ed52511fa3..0c7995fde32 100644
--- a/src/test/ui/extern/extern-types-unsized.stderr
+++ b/src/test/ui/extern/extern-types-unsized.stderr
@@ -26,6 +26,10 @@ LL |     assert_sized::<Foo>();
    = help: within `Foo`, the trait `std::marker::Sized` is not implemented for `A`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Foo`
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | fn assert_sized<T: ?Sized>() { }
+   |                  ^^^^^^^^
 
 error[E0277]: the size for values of type `A` cannot be known at compilation time
   --> $DIR/extern-types-unsized.rs:28:5
@@ -39,6 +43,10 @@ LL |     assert_sized::<Bar<A>>();
    = help: within `Bar<A>`, the trait `std::marker::Sized` is not implemented for `A`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Bar<A>`
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | fn assert_sized<T: ?Sized>() { }
+   |                  ^^^^^^^^
 
 error[E0277]: the size for values of type `A` cannot be known at compilation time
   --> $DIR/extern-types-unsized.rs:31:5
@@ -53,6 +61,10 @@ LL |     assert_sized::<Bar<Bar<A>>>();
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Bar<A>`
    = note: required because it appears within the type `Bar<Bar<A>>`
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | fn assert_sized<T: ?Sized>() { }
+   |                  ^^^^^^^^
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/issues/issue-10412.stderr b/src/test/ui/issues/issue-10412.stderr
index 888576c4336..d7a4bf4f21f 100644
--- a/src/test/ui/issues/issue-10412.stderr
+++ b/src/test/ui/issues/issue-10412.stderr
@@ -57,6 +57,10 @@ LL | impl<'self> Serializable<str> for &'self str {
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
    = 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 relaxing the implicit `Sized` restriction
+   |
+LL | trait Serializable<'self, T: ?Sized> {
+   |                            ^^^^^^^^
 
 error: aborting due to 9 previous errors
 
diff --git a/src/test/ui/issues/issue-18919.stderr b/src/test/ui/issues/issue-18919.stderr
index 1ea40d0728e..383cdd4979a 100644
--- a/src/test/ui/issues/issue-18919.stderr
+++ b/src/test/ui/issues/issue-18919.stderr
@@ -9,6 +9,13 @@ LL | enum Option<T> {
    |
    = help: the trait `std::marker::Sized` is not implemented for `dyn for<'r> std::ops::Fn(&'r isize) -> isize`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/issue-18919.rs:7:13
+   |
+LL | enum Option<T> {
+   |             ^ this could be changed to `T: ?Sized`...
+LL |     Some(T),
+   |          - ...if indirection was used here: `Box<T>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-23281.stderr b/src/test/ui/issues/issue-23281.stderr
index 3b4b8997a70..cffa5236169 100644
--- a/src/test/ui/issues/issue-23281.stderr
+++ b/src/test/ui/issues/issue-23281.stderr
@@ -9,6 +9,13 @@ LL | struct Vec<T> {
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::Fn() + 'static)`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/issue-23281.rs:8:12
+   |
+LL | struct Vec<T> {
+   |            ^ this could be changed to `T: ?Sized`...
+LL |     t: T,
+   |        - ...if indirection was used here: `Box<T>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.rs b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.rs
new file mode 100644
index 00000000000..ef64d799b65
--- /dev/null
+++ b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.rs
@@ -0,0 +1,28 @@
+trait Trait {
+    fn func1() -> Struct1<Self>; //~ ERROR E0277
+    fn func2<'a>() -> Struct2<'a, Self>; //~ ERROR E0277
+    fn func3() -> Struct3<Self>; //~ ERROR E0277
+    fn func4() -> Struct4<Self>; //~ ERROR E0277
+}
+
+struct Struct1<T>{
+    _t: std::marker::PhantomData<*const T>,
+}
+struct Struct2<'a, T>{
+    _t: &'a T,
+}
+struct Struct3<T>{
+    _t: T,
+}
+
+struct X<T>(T);
+
+struct Struct4<T>{
+    _t: X<T>,
+}
+
+struct Struct5<T: ?Sized>{
+    _t: X<T>, //~ ERROR E0277
+}
+
+fn main() {}
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
new file mode 100644
index 00000000000..ee08f51f802
--- /dev/null
+++ b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr
@@ -0,0 +1,107 @@
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> $DIR/adt-param-with-implicit-sized-bound.rs:25:5
+   |
+LL | struct X<T>(T);
+   |          - required by this bound in `X`
+...
+LL | struct Struct5<T: ?Sized>{
+   |                - this type parameter needs to be `std::marker::Sized`
+LL |     _t: X<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: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/adt-param-with-implicit-sized-bound.rs:18:10
+   |
+LL | struct X<T>(T);
+   |          ^  - ...if indirection was used here: `Box<T>`
+   |          |
+   |          this could be changed to `T: ?Sized`...
+
+error[E0277]: the size for values of type `Self` cannot be known at compilation time
+  --> $DIR/adt-param-with-implicit-sized-bound.rs:2:19
+   |
+LL |     fn func1() -> Struct1<Self>;
+   |                   ^^^^^^^^^^^^^ doesn't have a size known at compile-time
+...
+LL | struct Struct1<T>{
+   |                - required by this bound in `Struct1`
+   |
+   = help: the trait `std::marker::Sized` is not implemented for `Self`
+   = 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 further restricting `Self`
+   |
+LL |     fn func1() -> Struct1<Self> where Self: std::marker::Sized;
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | struct Struct1<T: ?Sized>{
+   |                 ^^^^^^^^
+
+error[E0277]: the size for values of type `Self` cannot be known at compilation time
+  --> $DIR/adt-param-with-implicit-sized-bound.rs:3:23
+   |
+LL |     fn func2<'a>() -> Struct2<'a, Self>;
+   |                       ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+...
+LL | struct Struct2<'a, T>{
+   |                    - required by this bound in `Struct2`
+   |
+   = help: the trait `std::marker::Sized` is not implemented for `Self`
+   = 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 further restricting `Self`
+   |
+LL |     fn func2<'a>() -> Struct2<'a, Self> where Self: std::marker::Sized;
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | struct Struct2<'a, T: ?Sized>{
+   |                     ^^^^^^^^
+
+error[E0277]: the size for values of type `Self` cannot be known at compilation time
+  --> $DIR/adt-param-with-implicit-sized-bound.rs:4:19
+   |
+LL |     fn func3() -> Struct3<Self>;
+   |                   ^^^^^^^^^^^^^ doesn't have a size known at compile-time
+...
+LL | struct Struct3<T>{
+   |                - required by this bound in `Struct3`
+   |
+   = help: the trait `std::marker::Sized` is not implemented for `Self`
+   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/adt-param-with-implicit-sized-bound.rs:14:16
+   |
+LL | struct Struct3<T>{
+   |                ^ this could be changed to `T: ?Sized`...
+LL |     _t: T,
+   |         - ...if indirection was used here: `Box<T>`
+help: consider further restricting `Self`
+   |
+LL |     fn func3() -> Struct3<Self> where Self: std::marker::Sized;
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: the size for values of type `Self` cannot be known at compilation time
+  --> $DIR/adt-param-with-implicit-sized-bound.rs:5:19
+   |
+LL |     fn func4() -> Struct4<Self>;
+   |                   ^^^^^^^^^^^^^ doesn't have a size known at compile-time
+...
+LL | struct Struct4<T>{
+   |                - required by this bound in `Struct4`
+   |
+   = help: the trait `std::marker::Sized` is not implemented for `Self`
+   = 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 further restricting `Self`
+   |
+LL |     fn func4() -> Struct4<Self> where Self: std::marker::Sized;
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | struct Struct4<T: ?Sized>{
+   |                 ^^^^^^^^
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/unsized/unsized-enum.stderr b/src/test/ui/unsized/unsized-enum.stderr
index f43d00f9739..1908aee25ea 100644
--- a/src/test/ui/unsized/unsized-enum.stderr
+++ b/src/test/ui/unsized/unsized-enum.stderr
@@ -11,6 +11,13 @@ LL | fn foo2<T: ?Sized>() { not_sized::<Foo<T>>() }
    |
    = 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: you could relax the implicit `Sized` bound on `U` if it were used through indirection like `&U` or `Box<U>`
+  --> $DIR/unsized-enum.rs:4:10
+   |
+LL | enum Foo<U> { FooSome(U), FooNone }
+   |          ^            - ...if indirection was used here: `Box<U>`
+   |          |
+   |          this could be changed to `U: ?Sized`...
 
 error: aborting due to previous error
 
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 808c9c583d4..e0f077d66f9 100644
--- a/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr
+++ b/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr
@@ -11,6 +11,13 @@ LL | impl<X: ?Sized> S5<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: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box<Y>`
+  --> $DIR/unsized-inherent-impl-self-type.rs:5:11
+   |
+LL | struct S5<Y>(Y);
+   |           ^  - ...if indirection was used here: `Box<Y>`
+   |           |
+   |           this could be changed to `Y: ?Sized`...
 
 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 42fc5569ece..d92d1d9113e 100644
--- a/src/test/ui/unsized/unsized-struct.stderr
+++ b/src/test/ui/unsized/unsized-struct.stderr
@@ -11,6 +11,13 @@ LL | fn foo2<T: ?Sized>() { not_sized::<Foo<T>>() }
    |
    = 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: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/unsized-struct.rs:4:12
+   |
+LL | struct Foo<T> { data: T }
+   |            ^          - ...if indirection was used here: `Box<T>`
+   |            |
+   |            this could be changed to `T: ?Sized`...
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
   --> $DIR/unsized-struct.rs:13:24
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 c2b2fe40ce6..73c5439da53 100644
--- a/src/test/ui/unsized/unsized-trait-impl-self-type.stderr
+++ b/src/test/ui/unsized/unsized-trait-impl-self-type.stderr
@@ -11,6 +11,13 @@ LL | impl<X: ?Sized> T3<X> for S5<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: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box<Y>`
+  --> $DIR/unsized-trait-impl-self-type.rs:8:11
+   |
+LL | struct S5<Y>(Y);
+   |           ^  - ...if indirection was used here: `Box<Y>`
+   |           |
+   |           this could be changed to `Y: ?Sized`...
 
 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 4cf054d177f..e423a9bdeab 100644
--- a/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr
+++ b/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr
@@ -11,6 +11,10 @@ LL | impl<X: ?Sized> T2<X> for S4<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 relaxing the implicit `Sized` restriction
+   |
+LL | trait T2<Z: ?Sized> {
+   |           ^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unsized3.stderr b/src/test/ui/unsized3.stderr
index 828e8bc9f4a..e0a0389dc46 100644
--- a/src/test/ui/unsized3.stderr
+++ b/src/test/ui/unsized3.stderr
@@ -48,6 +48,10 @@ LL |     f5(x1);
    = 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>
    = note: required because it appears within the type `S<X>`
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | fn f5<Y: ?Sized>(x: &Y) {}
+   |        ^^^^^^^^
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized3.rs:40:8
@@ -91,6 +95,10 @@ LL |     f5(&(32, *x1));
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `S<X>`
    = note: required because it appears within the type `({integer}, S<X>)`
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | fn f5<Y: ?Sized>(x: &Y) {}
+   |        ^^^^^^^^
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/unsized7.stderr b/src/test/ui/unsized7.stderr
index d18644f005a..e616a5cf0f9 100644
--- a/src/test/ui/unsized7.stderr
+++ b/src/test/ui/unsized7.stderr
@@ -11,6 +11,10 @@ LL | impl<X: ?Sized + T> T1<X> for S3<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 relaxing the implicit `Sized` restriction
+   |
+LL | trait T1<Z: T + ?Sized> {
+   |               ^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-fn-where-clause.stderr b/src/test/ui/wf/wf-fn-where-clause.stderr
index 59a4f9bad9d..731d31ac34f 100644
--- a/src/test/ui/wf/wf-fn-where-clause.stderr
+++ b/src/test/ui/wf/wf-fn-where-clause.stderr
@@ -23,6 +23,13 @@ LL | struct Vec<T> {
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn std::marker::Copy + 'static)`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/wf-fn-where-clause.rs:16:12
+   |
+LL | struct Vec<T> {
+   |            ^ this could be changed to `T: ?Sized`...
+LL |     t: T,
+   |        - ...if indirection was used here: `Box<T>`
 
 error[E0038]: the trait `std::marker::Copy` cannot be made into an object
   --> $DIR/wf-fn-where-clause.rs:12:16