about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2024-04-18 22:18:19 +0000
committerEsteban Küber <esteban@kuber.com.ar>2024-04-24 22:21:15 +0000
commitd68f2a6b71df3a4524c390f683dbd7a925ed207f (patch)
tree5ed4e87d077e098de7c22dab9161e0355d5bc2be
parent4aba2c55e6bbe6c09132ff19360d302269dca775 (diff)
downloadrust-d68f2a6b71df3a4524c390f683dbd7a925ed207f.tar.gz
rust-d68f2a6b71df3a4524c390f683dbd7a925ed207f.zip
Mention when type parameter could be `Clone`
```
error[E0382]: use of moved value: `t`
  --> $DIR/use_of_moved_value_copy_suggestions.rs:7:9
   |
LL | fn duplicate_t<T>(t: T) -> (T, T) {
   |                   - move occurs because `t` has type `T`, which does not implement the `Copy` trait
...
LL |     (t, t)
   |      -  ^ value used here after move
   |      |
   |      value moved here
   |
help: if `T` implemented `Clone`, you could clone the value
  --> $DIR/use_of_moved_value_copy_suggestions.rs:4:16
   |
LL | fn duplicate_t<T>(t: T) -> (T, T) {
   |                ^ consider constraining this type parameter with `Clone`
...
LL |     (t, t)
   |      - you could clone this value
help: consider restricting type parameter `T`
   |
LL | fn duplicate_t<T: Copy>(t: T) -> (T, T) {
   |                 ++++++
```

The `help` is new. On ADTs, we also extend the output with span labels:

```
error[E0507]: cannot move out of static item `FOO`
  --> $DIR/issue-17718-static-move.rs:6:14
   |
LL |     let _a = FOO;
   |              ^^^ move occurs because `FOO` has type `Foo`, which does not implement the `Copy` trait
   |
note: if `Foo` implemented `Clone`, you could clone the value
  --> $DIR/issue-17718-static-move.rs:1:1
   |
LL | struct Foo;
   | ^^^^^^^^^^ consider implementing `Clone` for this type
...
LL |     let _a = FOO;
   |              --- you could clone this value
help: consider borrowing here
   |
LL |     let _a = &FOO;
   |              +
```
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs47
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs12
-rw-r--r--tests/ui/associated-types/issue-25700.stderr5
-rw-r--r--tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr7
-rw-r--r--tests/ui/binop/binop-consume-args.stderr140
-rw-r--r--tests/ui/binop/binop-move-semantics.stderr41
-rw-r--r--tests/ui/borrowck/borrowck-move-out-of-static-item.stderr5
-rw-r--r--tests/ui/borrowck/borrowck-move-subcomponent.stderr5
-rw-r--r--tests/ui/borrowck/borrowck-overloaded-call.stderr5
-rw-r--r--tests/ui/borrowck/clone-on-ref.stderr12
-rw-r--r--tests/ui/borrowck/issue-101119.stderr5
-rw-r--r--tests/ui/borrowck/issue-103624.stderr5
-rw-r--r--tests/ui/borrowck/issue-119915-bad-clone-suggestion.stderr5
-rw-r--r--tests/ui/borrowck/issue-17718-static-move.stderr5
-rw-r--r--tests/ui/borrowck/issue-20801.stderr20
-rw-r--r--tests/ui/borrowck/move-error-in-promoted-2.stderr5
-rw-r--r--tests/ui/borrowck/move-error-snippets.stderr7
-rw-r--r--tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr10
-rw-r--r--tests/ui/box/leak-alloc.stderr5
-rw-r--r--tests/ui/derives/deriving-with-repr-packed.stderr5
-rw-r--r--tests/ui/error-codes/E0504.stderr5
-rw-r--r--tests/ui/error-codes/E0505.stderr5
-rw-r--r--tests/ui/error-codes/E0507.stderr5
-rw-r--r--tests/ui/error-codes/E0508-fail.stderr5
-rw-r--r--tests/ui/error-codes/E0508.stderr5
-rw-r--r--tests/ui/error-codes/E0509.stderr5
-rw-r--r--tests/ui/issues/issue-17385.stderr10
-rw-r--r--tests/ui/issues/issue-24357.rs2
-rw-r--r--tests/ui/issues/issue-24357.stderr7
-rw-r--r--tests/ui/issues/issue-4335.stderr8
-rw-r--r--tests/ui/mir/issue-102389.stderr5
-rw-r--r--tests/ui/moves/borrow-closures-instead-of-move.rs4
-rw-r--r--tests/ui/moves/borrow-closures-instead-of-move.stderr16
-rw-r--r--tests/ui/moves/issue-72649-uninit-in-loop.rs8
-rw-r--r--tests/ui/moves/issue-72649-uninit-in-loop.stderr34
-rw-r--r--tests/ui/moves/issue-75904-move-closure-loop.stderr5
-rw-r--r--tests/ui/moves/move-fn-self-receiver.stderr10
-rw-r--r--tests/ui/moves/move-out-of-array-1.stderr5
-rw-r--r--tests/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr7
-rw-r--r--tests/ui/moves/use_of_moved_value_copy_suggestions.fixed4
-rw-r--r--tests/ui/moves/use_of_moved_value_copy_suggestions.rs4
-rw-r--r--tests/ui/moves/use_of_moved_value_copy_suggestions.stderr50
-rw-r--r--tests/ui/nll/issue-21232-partial-init-and-use.stderr10
-rw-r--r--tests/ui/nll/move-errors.stderr30
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr10
-rw-r--r--tests/ui/suggestions/option-content-move3.rs17
-rw-r--r--tests/ui/suggestions/option-content-move3.stderr35
-rw-r--r--tests/ui/union/union-borrow-move-parent-sibling.stderr5
-rw-r--r--tests/ui/union/union-move.stderr10
-rw-r--r--tests/ui/unop-move-semantics.stderr34
-rw-r--r--tests/ui/variance/variance-issue-20533.stderr15
51 files changed, 640 insertions, 86 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index ed8c9bd51cf..8215dc68c08 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -347,7 +347,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         mpi: MovePathIndex,
         err: &mut Diag<'tcx>,
         in_pattern: &mut bool,
-        move_spans: UseSpans<'_>,
+        move_spans: UseSpans<'tcx>,
     ) {
         let move_span = match move_spans {
             UseSpans::ClosureUse { capture_kind_span, .. } => capture_kind_span,
@@ -491,11 +491,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     ..
                 } = move_spans
                 {
-                    self.suggest_cloning(err, ty, expr, None);
+                    self.suggest_cloning(err, ty, expr, None, Some(move_spans));
                 } else if self.suggest_hoisting_call_outside_loop(err, expr) {
                     // The place where the the type moves would be misleading to suggest clone.
                     // #121466
-                    self.suggest_cloning(err, ty, expr, None);
+                    self.suggest_cloning(err, ty, expr, None, Some(move_spans));
                 }
             }
             if let Some(pat) = finder.pat {
@@ -1085,6 +1085,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         ty: Ty<'tcx>,
         mut expr: &'cx hir::Expr<'cx>,
         mut other_expr: Option<&'cx hir::Expr<'cx>>,
+        use_spans: Option<UseSpans<'tcx>>,
     ) {
         if let hir::ExprKind::Struct(_, _, Some(_)) = expr.kind {
             // We have `S { foo: val, ..base }`. In `check_aggregate_rvalue` we have a single
@@ -1197,8 +1198,44 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     .all(|field| self.implements_clone(field.ty(self.infcx.tcx, args)))
             })
         {
+            let ty_span = self.infcx.tcx.def_span(def.did());
+            let mut span: MultiSpan = ty_span.into();
+            span.push_span_label(ty_span, "consider implementing `Clone` for this type");
+            span.push_span_label(expr.span, "you could clone this value");
             err.span_note(
-                self.infcx.tcx.def_span(def.did()),
+                span,
+                format!("if `{ty}` implemented `Clone`, you could clone the value"),
+            );
+        } else if let ty::Param(param) = ty.kind()
+            && let Some(_clone_trait_def) = self.infcx.tcx.lang_items().clone_trait()
+            && let generics = self.infcx.tcx.generics_of(self.mir_def_id())
+            && let generic_param = generics.type_param(*param, self.infcx.tcx)
+            && let param_span = self.infcx.tcx.def_span(generic_param.def_id)
+            && if let Some(UseSpans::FnSelfUse { kind, .. }) = use_spans
+                && let CallKind::FnCall { fn_trait_id, self_ty } = kind
+                && let ty::Param(_) = self_ty.kind()
+                && ty == self_ty
+                && [
+                    self.infcx.tcx.lang_items().fn_once_trait(),
+                    self.infcx.tcx.lang_items().fn_mut_trait(),
+                    self.infcx.tcx.lang_items().fn_trait(),
+                ]
+                .contains(&Some(fn_trait_id))
+            {
+                // Do not suggest `F: FnOnce() + Clone`.
+                false
+            } else {
+                true
+            }
+        {
+            let mut span: MultiSpan = param_span.into();
+            span.push_span_label(
+                param_span,
+                "consider constraining this type parameter with `Clone`",
+            );
+            span.push_span_label(expr.span, "you could clone this value");
+            err.span_help(
+                span,
                 format!("if `{ty}` implemented `Clone`, you could clone the value"),
             );
         }
@@ -1403,7 +1440,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         if let Some(expr) = self.find_expr(borrow_span)
             && let Some(ty) = typeck_results.node_type_opt(expr.hir_id)
         {
-            self.suggest_cloning(&mut err, ty, expr, self.find_expr(span));
+            self.suggest_cloning(&mut err, ty, expr, self.find_expr(span), Some(move_spans));
         }
         self.buffer_error(err);
     }
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index bc02c5be93d..1bbf36355cb 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -447,7 +447,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     };
 
                     if let Some(expr) = self.find_expr(span) {
-                        self.suggest_cloning(err, place_ty, expr, self.find_expr(other_span));
+                        self.suggest_cloning(err, place_ty, expr, self.find_expr(other_span), None);
                     }
 
                     err.subdiagnostic(
@@ -482,7 +482,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 };
 
                 if let Some(expr) = self.find_expr(use_span) {
-                    self.suggest_cloning(err, place_ty, expr, self.find_expr(span));
+                    self.suggest_cloning(
+                        err,
+                        place_ty,
+                        expr,
+                        self.find_expr(span),
+                        Some(use_spans),
+                    );
                 }
 
                 err.subdiagnostic(
@@ -595,7 +601,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 let place_desc = &format!("`{}`", self.local_names[*local].unwrap());
 
                 if let Some(expr) = self.find_expr(binding_span) {
-                    self.suggest_cloning(err, bind_to.ty, expr, None);
+                    self.suggest_cloning(err, bind_to.ty, expr, None, None);
                 }
 
                 err.subdiagnostic(
diff --git a/tests/ui/associated-types/issue-25700.stderr b/tests/ui/associated-types/issue-25700.stderr
index fb0e63c207a..8d40e6905e0 100644
--- a/tests/ui/associated-types/issue-25700.stderr
+++ b/tests/ui/associated-types/issue-25700.stderr
@@ -12,7 +12,10 @@ note: if `S<()>` implemented `Clone`, you could clone the value
   --> $DIR/issue-25700.rs:1:1
    |
 LL | struct S<T: 'static>(#[allow(dead_code)] Option<&'static T>);
-   | ^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     drop(t);
+   |          - you could clone this value
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr b/tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr
index dcf1c02bcee..4c1de72798c 100644
--- a/tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr
+++ b/tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr
@@ -23,6 +23,13 @@ LL | fn copy<T: Magic>(x: T) -> (T, T) { (x, x) }
    |                   |                  value moved here
    |                   move occurs because `x` has type `T`, which does not implement the `Copy` trait
    |
+help: if `T` implemented `Clone`, you could clone the value
+  --> $DIR/typeck-auto-trait-no-supertraits-2.rs:8:9
+   |
+LL | fn copy<T: Magic>(x: T) -> (T, T) { (x, x) }
+   |         ^                            - you could clone this value
+   |         |
+   |         consider constraining this type parameter with `Clone`
 help: consider further restricting this bound
    |
 LL | fn copy<T: Magic + Copy>(x: T) -> (T, T) { (x, x) }
diff --git a/tests/ui/binop/binop-consume-args.stderr b/tests/ui/binop/binop-consume-args.stderr
index 6fbbb55437e..1b59216b3c7 100644
--- a/tests/ui/binop/binop-consume-args.stderr
+++ b/tests/ui/binop/binop-consume-args.stderr
@@ -8,6 +8,13 @@ LL |     lhs + rhs;
 LL |     drop(lhs);
    |          ^^^ value used here after move
    |
+help: if `A` implemented `Clone`, you could clone the value
+  --> $DIR/binop-consume-args.rs:5:8
+   |
+LL | fn add<A: Add<B, Output=()>, B>(lhs: A, rhs: B) {
+   |        ^ consider constraining this type parameter with `Clone`
+LL |     lhs + rhs;
+   |     --- you could clone this value
 note: calling this operator moves the left-hand side
   --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
 help: consider further restricting this bound
@@ -26,6 +33,13 @@ LL |     drop(lhs);
 LL |     drop(rhs);
    |          ^^^ value used here after move
    |
+help: if `B` implemented `Clone`, you could clone the value
+  --> $DIR/binop-consume-args.rs:5:30
+   |
+LL | fn add<A: Add<B, Output=()>, B>(lhs: A, rhs: B) {
+   |                              ^ consider constraining this type parameter with `Clone`
+LL |     lhs + rhs;
+   |           --- you could clone this value
 help: consider restricting type parameter `B`
    |
 LL | fn add<A: Add<B, Output=()>, B: Copy>(lhs: A, rhs: B) {
@@ -41,6 +55,13 @@ LL |     lhs - rhs;
 LL |     drop(lhs);
    |          ^^^ value used here after move
    |
+help: if `A` implemented `Clone`, you could clone the value
+  --> $DIR/binop-consume-args.rs:11:8
+   |
+LL | fn sub<A: Sub<B, Output=()>, B>(lhs: A, rhs: B) {
+   |        ^ consider constraining this type parameter with `Clone`
+LL |     lhs - rhs;
+   |     --- you could clone this value
 note: calling this operator moves the left-hand side
   --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
 help: consider further restricting this bound
@@ -59,6 +80,13 @@ LL |     drop(lhs);
 LL |     drop(rhs);
    |          ^^^ value used here after move
    |
+help: if `B` implemented `Clone`, you could clone the value
+  --> $DIR/binop-consume-args.rs:11:30
+   |
+LL | fn sub<A: Sub<B, Output=()>, B>(lhs: A, rhs: B) {
+   |                              ^ consider constraining this type parameter with `Clone`
+LL |     lhs - rhs;
+   |           --- you could clone this value
 help: consider restricting type parameter `B`
    |
 LL | fn sub<A: Sub<B, Output=()>, B: Copy>(lhs: A, rhs: B) {
@@ -74,6 +102,13 @@ LL |     lhs * rhs;
 LL |     drop(lhs);
    |          ^^^ value used here after move
    |
+help: if `A` implemented `Clone`, you could clone the value
+  --> $DIR/binop-consume-args.rs:17:8
+   |
+LL | fn mul<A: Mul<B, Output=()>, B>(lhs: A, rhs: B) {
+   |        ^ consider constraining this type parameter with `Clone`
+LL |     lhs * rhs;
+   |     --- you could clone this value
 note: calling this operator moves the left-hand side
   --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
 help: consider further restricting this bound
@@ -92,6 +127,13 @@ LL |     drop(lhs);
 LL |     drop(rhs);
    |          ^^^ value used here after move
    |
+help: if `B` implemented `Clone`, you could clone the value
+  --> $DIR/binop-consume-args.rs:17:30
+   |
+LL | fn mul<A: Mul<B, Output=()>, B>(lhs: A, rhs: B) {
+   |                              ^ consider constraining this type parameter with `Clone`
+LL |     lhs * rhs;
+   |           --- you could clone this value
 help: consider restricting type parameter `B`
    |
 LL | fn mul<A: Mul<B, Output=()>, B: Copy>(lhs: A, rhs: B) {
@@ -107,6 +149,13 @@ LL |     lhs / rhs;
 LL |     drop(lhs);
    |          ^^^ value used here after move
    |
+help: if `A` implemented `Clone`, you could clone the value
+  --> $DIR/binop-consume-args.rs:23:8
+   |
+LL | fn div<A: Div<B, Output=()>, B>(lhs: A, rhs: B) {
+   |        ^ consider constraining this type parameter with `Clone`
+LL |     lhs / rhs;
+   |     --- you could clone this value
 note: calling this operator moves the left-hand side
   --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
 help: consider further restricting this bound
@@ -125,6 +174,13 @@ LL |     drop(lhs);
 LL |     drop(rhs);
    |          ^^^ value used here after move
    |
+help: if `B` implemented `Clone`, you could clone the value
+  --> $DIR/binop-consume-args.rs:23:30
+   |
+LL | fn div<A: Div<B, Output=()>, B>(lhs: A, rhs: B) {
+   |                              ^ consider constraining this type parameter with `Clone`
+LL |     lhs / rhs;
+   |           --- you could clone this value
 help: consider restricting type parameter `B`
    |
 LL | fn div<A: Div<B, Output=()>, B: Copy>(lhs: A, rhs: B) {
@@ -140,6 +196,13 @@ LL |     lhs % rhs;
 LL |     drop(lhs);
    |          ^^^ value used here after move
    |
+help: if `A` implemented `Clone`, you could clone the value
+  --> $DIR/binop-consume-args.rs:29:8
+   |
+LL | fn rem<A: Rem<B, Output=()>, B>(lhs: A, rhs: B) {
+   |        ^ consider constraining this type parameter with `Clone`
+LL |     lhs % rhs;
+   |     --- you could clone this value
 note: calling this operator moves the left-hand side
   --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
 help: consider further restricting this bound
@@ -158,6 +221,13 @@ LL |     drop(lhs);
 LL |     drop(rhs);
    |          ^^^ value used here after move
    |
+help: if `B` implemented `Clone`, you could clone the value
+  --> $DIR/binop-consume-args.rs:29:30
+   |
+LL | fn rem<A: Rem<B, Output=()>, B>(lhs: A, rhs: B) {
+   |                              ^ consider constraining this type parameter with `Clone`
+LL |     lhs % rhs;
+   |           --- you could clone this value
 help: consider restricting type parameter `B`
    |
 LL | fn rem<A: Rem<B, Output=()>, B: Copy>(lhs: A, rhs: B) {
@@ -173,6 +243,13 @@ LL |     lhs & rhs;
 LL |     drop(lhs);
    |          ^^^ value used here after move
    |
+help: if `A` implemented `Clone`, you could clone the value
+  --> $DIR/binop-consume-args.rs:35:11
+   |
+LL | fn bitand<A: BitAnd<B, Output=()>, B>(lhs: A, rhs: B) {
+   |           ^ consider constraining this type parameter with `Clone`
+LL |     lhs & rhs;
+   |     --- you could clone this value
 note: calling this operator moves the left-hand side
   --> $SRC_DIR/core/src/ops/bit.rs:LL:COL
 help: consider further restricting this bound
@@ -191,6 +268,13 @@ LL |     drop(lhs);
 LL |     drop(rhs);
    |          ^^^ value used here after move
    |
+help: if `B` implemented `Clone`, you could clone the value
+  --> $DIR/binop-consume-args.rs:35:36
+   |
+LL | fn bitand<A: BitAnd<B, Output=()>, B>(lhs: A, rhs: B) {
+   |                                    ^ consider constraining this type parameter with `Clone`
+LL |     lhs & rhs;
+   |           --- you could clone this value
 help: consider restricting type parameter `B`
    |
 LL | fn bitand<A: BitAnd<B, Output=()>, B: Copy>(lhs: A, rhs: B) {
@@ -206,6 +290,13 @@ LL |     lhs | rhs;
 LL |     drop(lhs);
    |          ^^^ value used here after move
    |
+help: if `A` implemented `Clone`, you could clone the value
+  --> $DIR/binop-consume-args.rs:41:10
+   |
+LL | fn bitor<A: BitOr<B, Output=()>, B>(lhs: A, rhs: B) {
+   |          ^ consider constraining this type parameter with `Clone`
+LL |     lhs | rhs;
+   |     --- you could clone this value
 note: calling this operator moves the left-hand side
   --> $SRC_DIR/core/src/ops/bit.rs:LL:COL
 help: consider further restricting this bound
@@ -224,6 +315,13 @@ LL |     drop(lhs);
 LL |     drop(rhs);
    |          ^^^ value used here after move
    |
+help: if `B` implemented `Clone`, you could clone the value
+  --> $DIR/binop-consume-args.rs:41:34
+   |
+LL | fn bitor<A: BitOr<B, Output=()>, B>(lhs: A, rhs: B) {
+   |                                  ^ consider constraining this type parameter with `Clone`
+LL |     lhs | rhs;
+   |           --- you could clone this value
 help: consider restricting type parameter `B`
    |
 LL | fn bitor<A: BitOr<B, Output=()>, B: Copy>(lhs: A, rhs: B) {
@@ -239,6 +337,13 @@ LL |     lhs ^ rhs;
 LL |     drop(lhs);
    |          ^^^ value used here after move
    |
+help: if `A` implemented `Clone`, you could clone the value
+  --> $DIR/binop-consume-args.rs:47:11
+   |
+LL | fn bitxor<A: BitXor<B, Output=()>, B>(lhs: A, rhs: B) {
+   |           ^ consider constraining this type parameter with `Clone`
+LL |     lhs ^ rhs;
+   |     --- you could clone this value
 note: calling this operator moves the left-hand side
   --> $SRC_DIR/core/src/ops/bit.rs:LL:COL
 help: consider further restricting this bound
@@ -257,6 +362,13 @@ LL |     drop(lhs);
 LL |     drop(rhs);
    |          ^^^ value used here after move
    |
+help: if `B` implemented `Clone`, you could clone the value
+  --> $DIR/binop-consume-args.rs:47:36
+   |
+LL | fn bitxor<A: BitXor<B, Output=()>, B>(lhs: A, rhs: B) {
+   |                                    ^ consider constraining this type parameter with `Clone`
+LL |     lhs ^ rhs;
+   |           --- you could clone this value
 help: consider restricting type parameter `B`
    |
 LL | fn bitxor<A: BitXor<B, Output=()>, B: Copy>(lhs: A, rhs: B) {
@@ -272,6 +384,13 @@ LL |     lhs << rhs;
 LL |     drop(lhs);
    |          ^^^ value used here after move
    |
+help: if `A` implemented `Clone`, you could clone the value
+  --> $DIR/binop-consume-args.rs:53:8
+   |
+LL | fn shl<A: Shl<B, Output=()>, B>(lhs: A, rhs: B) {
+   |        ^ consider constraining this type parameter with `Clone`
+LL |     lhs << rhs;
+   |     --- you could clone this value
 note: calling this operator moves the left-hand side
   --> $SRC_DIR/core/src/ops/bit.rs:LL:COL
 help: consider further restricting this bound
@@ -290,6 +409,13 @@ LL |     drop(lhs);
 LL |     drop(rhs);
    |          ^^^ value used here after move
    |
+help: if `B` implemented `Clone`, you could clone the value
+  --> $DIR/binop-consume-args.rs:53:30
+   |
+LL | fn shl<A: Shl<B, Output=()>, B>(lhs: A, rhs: B) {
+   |                              ^ consider constraining this type parameter with `Clone`
+LL |     lhs << rhs;
+   |            --- you could clone this value
 help: consider restricting type parameter `B`
    |
 LL | fn shl<A: Shl<B, Output=()>, B: Copy>(lhs: A, rhs: B) {
@@ -305,6 +431,13 @@ LL |     lhs >> rhs;
 LL |     drop(lhs);
    |          ^^^ value used here after move
    |
+help: if `A` implemented `Clone`, you could clone the value
+  --> $DIR/binop-consume-args.rs:59:8
+   |
+LL | fn shr<A: Shr<B, Output=()>, B>(lhs: A, rhs: B) {
+   |        ^ consider constraining this type parameter with `Clone`
+LL |     lhs >> rhs;
+   |     --- you could clone this value
 note: calling this operator moves the left-hand side
   --> $SRC_DIR/core/src/ops/bit.rs:LL:COL
 help: consider further restricting this bound
@@ -323,6 +456,13 @@ LL |     drop(lhs);
 LL |     drop(rhs);
    |          ^^^ value used here after move
    |
+help: if `B` implemented `Clone`, you could clone the value
+  --> $DIR/binop-consume-args.rs:59:30
+   |
+LL | fn shr<A: Shr<B, Output=()>, B>(lhs: A, rhs: B) {
+   |                              ^ consider constraining this type parameter with `Clone`
+LL |     lhs >> rhs;
+   |            --- you could clone this value
 help: consider restricting type parameter `B`
    |
 LL | fn shr<A: Shr<B, Output=()>, B: Copy>(lhs: A, rhs: B) {
diff --git a/tests/ui/binop/binop-move-semantics.stderr b/tests/ui/binop/binop-move-semantics.stderr
index 1dd8c9a87d4..83c27590e90 100644
--- a/tests/ui/binop/binop-move-semantics.stderr
+++ b/tests/ui/binop/binop-move-semantics.stderr
@@ -11,6 +11,13 @@ LL | |     x;
    | |_____value used here after move
    |       `x` moved due to usage in operator
    |
+help: if `T` implemented `Clone`, you could clone the value
+  --> $DIR/binop-move-semantics.rs:5:16
+   |
+LL | fn double_move<T: Add<Output=()>>(x: T) {
+   |                ^ consider constraining this type parameter with `Clone`
+LL |     x
+   |     - you could clone this value
 note: calling this operator moves the left-hand side
   --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
 help: consider further restricting this bound
@@ -51,6 +58,14 @@ LL |     x
 ...
 LL |     use_mut(n); use_imm(m);
    |                         - borrow later used here
+   |
+help: if `T` implemented `Clone`, you could clone the value
+  --> $DIR/binop-move-semantics.rs:17:18
+   |
+LL | fn move_borrowed<T: Add<Output=()>>(x: T, mut y: T) {
+   |                  ^ consider constraining this type parameter with `Clone`
+LL |     let m = &x;
+   |             -- you could clone this value
 
 error[E0505]: cannot move out of `y` because it is borrowed
   --> $DIR/binop-move-semantics.rs:23:5
@@ -65,6 +80,15 @@ LL |     y;
    |     ^ move out of `y` occurs here
 LL |     use_mut(n); use_imm(m);
    |             - borrow later used here
+   |
+help: if `T` implemented `Clone`, you could clone the value
+  --> $DIR/binop-move-semantics.rs:17:18
+   |
+LL | fn move_borrowed<T: Add<Output=()>>(x: T, mut y: T) {
+   |                  ^ consider constraining this type parameter with `Clone`
+LL |     let m = &x;
+LL |     let n = &mut y;
+   |             ------ you could clone this value
 
 error[E0507]: cannot move out of `*m` which is behind a mutable reference
   --> $DIR/binop-move-semantics.rs:30:5
@@ -80,12 +104,29 @@ LL | |     *n;
    |
 note: calling this operator moves the left-hand side
   --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
+help: if `T` implemented `Clone`, you could clone the value
+  --> $DIR/binop-move-semantics.rs:26:24
+   |
+LL | fn illegal_dereference<T: Add<Output=()>>(mut x: T, y: T) {
+   |                        ^ consider constraining this type parameter with `Clone`
+...
+LL |     *m
+   |     -- you could clone this value
 
 error[E0507]: cannot move out of `*n` which is behind a shared reference
   --> $DIR/binop-move-semantics.rs:32:5
    |
 LL |     *n;
    |     ^^ move occurs because `*n` has type `T`, which does not implement the `Copy` trait
+   |
+help: if `T` implemented `Clone`, you could clone the value
+  --> $DIR/binop-move-semantics.rs:26:24
+   |
+LL | fn illegal_dereference<T: Add<Output=()>>(mut x: T, y: T) {
+   |                        ^ consider constraining this type parameter with `Clone`
+...
+LL |     *n;
+   |     -- you could clone this value
 
 error[E0502]: cannot borrow `f` as immutable because it is also borrowed as mutable
   --> $DIR/binop-move-semantics.rs:54:5
diff --git a/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr b/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr
index 86bddacbdc7..b4b60d40d91 100644
--- a/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr
+++ b/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr
@@ -8,7 +8,10 @@ note: if `Foo` implemented `Clone`, you could clone the value
   --> $DIR/borrowck-move-out-of-static-item.rs:3:1
    |
 LL | struct Foo {
-   | ^^^^^^^^^^
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     test(BAR);
+   |          --- you could clone this value
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-move-subcomponent.stderr b/tests/ui/borrowck/borrowck-move-subcomponent.stderr
index 4d9477f8581..cc6c3bdeb10 100644
--- a/tests/ui/borrowck/borrowck-move-subcomponent.stderr
+++ b/tests/ui/borrowck/borrowck-move-subcomponent.stderr
@@ -14,7 +14,10 @@ note: if `S` implemented `Clone`, you could clone the value
   --> $DIR/borrowck-move-subcomponent.rs:6:1
    |
 LL | struct S {
-   | ^^^^^^^^
+   | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |   let pb = &a;
+   |            -- you could clone this value
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-overloaded-call.stderr b/tests/ui/borrowck/borrowck-overloaded-call.stderr
index 1602058c183..c3b7b0b6080 100644
--- a/tests/ui/borrowck/borrowck-overloaded-call.stderr
+++ b/tests/ui/borrowck/borrowck-overloaded-call.stderr
@@ -34,7 +34,10 @@ note: if `SFnOnce` implemented `Clone`, you could clone the value
   --> $DIR/borrowck-overloaded-call.rs:41:1
    |
 LL | struct SFnOnce {
-   | ^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     s(" world".to_string());
+   |     - you could clone this value
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/borrowck/clone-on-ref.stderr b/tests/ui/borrowck/clone-on-ref.stderr
index f0eaf4bac7d..19f040556f8 100644
--- a/tests/ui/borrowck/clone-on-ref.stderr
+++ b/tests/ui/borrowck/clone-on-ref.stderr
@@ -32,6 +32,13 @@ LL |
 LL |     println!("{b}");
    |               --- borrow later used here
    |
+help: if `T` implemented `Clone`, you could clone the value
+  --> $DIR/clone-on-ref.rs:11:8
+   |
+LL | fn bar<T: std::fmt::Display>(x: T) {
+   |        ^ consider constraining this type parameter with `Clone`
+LL |     let a = &x;
+   |             -- you could clone this value
 help: consider further restricting this bound
    |
 LL | fn bar<T: std::fmt::Display + Clone>(x: T) {
@@ -56,7 +63,10 @@ note: if `A` implemented `Clone`, you could clone the value
   --> $DIR/clone-on-ref.rs:19:1
    |
 LL | struct A;
-   | ^^^^^^^^
+   | ^^^^^^^^ consider implementing `Clone` for this type
+LL | fn qux(x: A) {
+LL |     let a = &x;
+   |             -- you could clone this value
 help: consider annotating `A` with `#[derive(Clone)]`
    |
 LL + #[derive(Clone)]
diff --git a/tests/ui/borrowck/issue-101119.stderr b/tests/ui/borrowck/issue-101119.stderr
index b4775496f4f..a894fa63ace 100644
--- a/tests/ui/borrowck/issue-101119.stderr
+++ b/tests/ui/borrowck/issue-101119.stderr
@@ -22,7 +22,10 @@ note: if `State` implemented `Clone`, you could clone the value
   --> $DIR/issue-101119.rs:1:1
    |
 LL | struct State;
-   | ^^^^^^^^^^^^
+   | ^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |             fill_segment(state);
+   |                          ----- you could clone this value
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/issue-103624.stderr b/tests/ui/borrowck/issue-103624.stderr
index 94421c35c65..603055beadc 100644
--- a/tests/ui/borrowck/issue-103624.stderr
+++ b/tests/ui/borrowck/issue-103624.stderr
@@ -13,8 +13,11 @@ LL |             self.b;
 note: if `StructB` implemented `Clone`, you could clone the value
   --> $DIR/issue-103624.rs:23:1
    |
+LL |             self.b;
+   |             ------ you could clone this value
+...
 LL | struct StructB {}
-   | ^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type
 
 error[E0521]: borrowed data escapes outside of method
   --> $DIR/issue-103624.rs:14:9
diff --git a/tests/ui/borrowck/issue-119915-bad-clone-suggestion.stderr b/tests/ui/borrowck/issue-119915-bad-clone-suggestion.stderr
index 701f00d079d..dde17d1f652 100644
--- a/tests/ui/borrowck/issue-119915-bad-clone-suggestion.stderr
+++ b/tests/ui/borrowck/issue-119915-bad-clone-suggestion.stderr
@@ -15,7 +15,10 @@ note: if `Example<E, NoLifetime>` implemented `Clone`, you could clone the value
   --> $DIR/issue-119915-bad-clone-suggestion.rs:3:1
    |
 LL | struct Example<E, FakeParam>(PhantomData<(fn(E), fn(FakeParam))>);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |         unsafe { self.change() }
+   |                  ---- you could clone this value
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/issue-17718-static-move.stderr b/tests/ui/borrowck/issue-17718-static-move.stderr
index e2c3a9d5a26..057ac6d7e3d 100644
--- a/tests/ui/borrowck/issue-17718-static-move.stderr
+++ b/tests/ui/borrowck/issue-17718-static-move.stderr
@@ -8,7 +8,10 @@ note: if `Foo` implemented `Clone`, you could clone the value
   --> $DIR/issue-17718-static-move.rs:1:1
    |
 LL | struct Foo;
-   | ^^^^^^^^^^
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let _a = FOO;
+   |              --- you could clone this value
 help: consider borrowing here
    |
 LL |     let _a = &FOO;
diff --git a/tests/ui/borrowck/issue-20801.stderr b/tests/ui/borrowck/issue-20801.stderr
index 1da6f0bef02..20a4bd4e423 100644
--- a/tests/ui/borrowck/issue-20801.stderr
+++ b/tests/ui/borrowck/issue-20801.stderr
@@ -23,7 +23,10 @@ note: if `T` implemented `Clone`, you could clone the value
   --> $DIR/issue-20801.rs:3:1
    |
 LL | struct T(u8);
-   | ^^^^^^^^
+   | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let a = unsafe { *mut_ref() };
+   |                      ---------- you could clone this value
 help: consider removing the dereference here
    |
 LL -     let a = unsafe { *mut_ref() };
@@ -40,7 +43,10 @@ note: if `T` implemented `Clone`, you could clone the value
   --> $DIR/issue-20801.rs:3:1
    |
 LL | struct T(u8);
-   | ^^^^^^^^
+   | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let b = unsafe { *imm_ref() };
+   |                      ---------- you could clone this value
 help: consider removing the dereference here
    |
 LL -     let b = unsafe { *imm_ref() };
@@ -57,7 +63,10 @@ note: if `T` implemented `Clone`, you could clone the value
   --> $DIR/issue-20801.rs:3:1
    |
 LL | struct T(u8);
-   | ^^^^^^^^
+   | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let c = unsafe { *mut_ptr() };
+   |                      ---------- you could clone this value
 help: consider removing the dereference here
    |
 LL -     let c = unsafe { *mut_ptr() };
@@ -74,7 +83,10 @@ note: if `T` implemented `Clone`, you could clone the value
   --> $DIR/issue-20801.rs:3:1
    |
 LL | struct T(u8);
-   | ^^^^^^^^
+   | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let d = unsafe { *const_ptr() };
+   |                      ------------ you could clone this value
 help: consider removing the dereference here
    |
 LL -     let d = unsafe { *const_ptr() };
diff --git a/tests/ui/borrowck/move-error-in-promoted-2.stderr b/tests/ui/borrowck/move-error-in-promoted-2.stderr
index 43f4e820857..1e9b1d5209c 100644
--- a/tests/ui/borrowck/move-error-in-promoted-2.stderr
+++ b/tests/ui/borrowck/move-error-in-promoted-2.stderr
@@ -11,7 +11,10 @@ note: if `S` implemented `Clone`, you could clone the value
   --> $DIR/move-error-in-promoted-2.rs:3:1
    |
 LL | struct S;
-   | ^^^^^^^^
+   | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     &([S][0],);
+   |       ------ you could clone this value
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/move-error-snippets.stderr b/tests/ui/borrowck/move-error-snippets.stderr
index 40b64398aef..97d14051518 100644
--- a/tests/ui/borrowck/move-error-snippets.stderr
+++ b/tests/ui/borrowck/move-error-snippets.stderr
@@ -13,7 +13,12 @@ note: if `A` implemented `Clone`, you could clone the value
   --> $DIR/move-error-snippets.rs:9:1
    |
 LL | struct A;
-   | ^^^^^^^^
+   | ^^^^^^^^ consider implementing `Clone` for this type
+   |
+  ::: $DIR/move-error-snippets-ext.rs:5:17
+   |
+LL |         let a = $c;
+   |                 -- you could clone this value
    = note: this error originates in the macro `aaa` which comes from the expansion of the macro `sss` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider borrowing here
    |
diff --git a/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr b/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr
index a4e70b50646..009e85a8031 100644
--- a/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr
+++ b/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr
@@ -8,7 +8,10 @@ note: if `Foo` implemented `Clone`, you could clone the value
   --> $DIR/move-in-static-initializer-issue-38520.rs:5:1
    |
 LL | struct Foo(usize);
-   | ^^^^^^^^^^
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | static Y: usize = get(*&X);
+   |                       --- you could clone this value
 
 error[E0507]: cannot move out of a shared reference
   --> $DIR/move-in-static-initializer-issue-38520.rs:13:22
@@ -20,7 +23,10 @@ note: if `Foo` implemented `Clone`, you could clone the value
   --> $DIR/move-in-static-initializer-issue-38520.rs:5:1
    |
 LL | struct Foo(usize);
-   | ^^^^^^^^^^
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | const Z: usize = get(*&X);
+   |                      --- you could clone this value
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/box/leak-alloc.stderr b/tests/ui/box/leak-alloc.stderr
index 53ff5f0107d..bdaa9449f91 100644
--- a/tests/ui/box/leak-alloc.stderr
+++ b/tests/ui/box/leak-alloc.stderr
@@ -16,7 +16,10 @@ note: if `Alloc` implemented `Clone`, you could clone the value
   --> $DIR/leak-alloc.rs:8:1
    |
 LL | struct Alloc {}
-   | ^^^^^^^^^^^^
+   | ^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let boxed = Box::new_in(10, alloc.by_ref());
+   |                                 ----- you could clone this value
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/derives/deriving-with-repr-packed.stderr b/tests/ui/derives/deriving-with-repr-packed.stderr
index 26ac532263f..a8523d25cab 100644
--- a/tests/ui/derives/deriving-with-repr-packed.stderr
+++ b/tests/ui/derives/deriving-with-repr-packed.stderr
@@ -40,7 +40,10 @@ note: if `Y` implemented `Clone`, you could clone the value
   --> $DIR/deriving-with-repr-packed.rs:16:1
    |
 LL | struct Y(usize);
-   | ^^^^^^^^
+   | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | struct X(Y);
+   |          - you could clone this value
    = note: `#[derive(Debug)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour
    = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/tests/ui/error-codes/E0504.stderr b/tests/ui/error-codes/E0504.stderr
index 900cb706bd9..343bca9a72e 100644
--- a/tests/ui/error-codes/E0504.stderr
+++ b/tests/ui/error-codes/E0504.stderr
@@ -18,7 +18,10 @@ note: if `FancyNum` implemented `Clone`, you could clone the value
   --> $DIR/E0504.rs:1:1
    |
 LL | struct FancyNum {
-   | ^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let fancy_ref = &fancy_num;
+   |                     ---------- you could clone this value
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/error-codes/E0505.stderr b/tests/ui/error-codes/E0505.stderr
index ce01298a70d..266df9ea32a 100644
--- a/tests/ui/error-codes/E0505.stderr
+++ b/tests/ui/error-codes/E0505.stderr
@@ -15,7 +15,10 @@ note: if `Value` implemented `Clone`, you could clone the value
   --> $DIR/E0505.rs:1:1
    |
 LL | struct Value {}
-   | ^^^^^^^^^^^^
+   | ^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |         let _ref_to_val: &Value = &x;
+   |                                   -- you could clone this value
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/error-codes/E0507.stderr b/tests/ui/error-codes/E0507.stderr
index 60a4daa9d38..70d99ea2cce 100644
--- a/tests/ui/error-codes/E0507.stderr
+++ b/tests/ui/error-codes/E0507.stderr
@@ -15,7 +15,10 @@ note: if `TheDarkKnight` implemented `Clone`, you could clone the value
   --> $DIR/E0507.rs:3:1
    |
 LL | struct TheDarkKnight;
-   | ^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     x.borrow().nothing_is_true();
+   |     ---------- you could clone this value
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/error-codes/E0508-fail.stderr b/tests/ui/error-codes/E0508-fail.stderr
index 96d3bcb67a5..fcfac399e0d 100644
--- a/tests/ui/error-codes/E0508-fail.stderr
+++ b/tests/ui/error-codes/E0508-fail.stderr
@@ -11,7 +11,10 @@ note: if `NonCopy` implemented `Clone`, you could clone the value
   --> $DIR/E0508-fail.rs:1:1
    |
 LL | struct NonCopy;
-   | ^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let _value = array[0];
+   |                  -------- you could clone this value
 help: consider borrowing here
    |
 LL |     let _value = &array[0];
diff --git a/tests/ui/error-codes/E0508.stderr b/tests/ui/error-codes/E0508.stderr
index c1b622e2432..b9fa0f4d17a 100644
--- a/tests/ui/error-codes/E0508.stderr
+++ b/tests/ui/error-codes/E0508.stderr
@@ -11,7 +11,10 @@ note: if `NonCopy` implemented `Clone`, you could clone the value
   --> $DIR/E0508.rs:1:1
    |
 LL | struct NonCopy;
-   | ^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let _value = array[0];
+   |                  -------- you could clone this value
 help: consider borrowing here
    |
 LL |     let _value = &array[0];
diff --git a/tests/ui/error-codes/E0509.stderr b/tests/ui/error-codes/E0509.stderr
index 75c372d0440..628a253e085 100644
--- a/tests/ui/error-codes/E0509.stderr
+++ b/tests/ui/error-codes/E0509.stderr
@@ -11,7 +11,10 @@ note: if `FancyNum` implemented `Clone`, you could clone the value
   --> $DIR/E0509.rs:1:1
    |
 LL | struct FancyNum {
-   | ^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let fancy_field = drop_struct.fancy;
+   |                       ----------------- you could clone this value
 help: consider borrowing here
    |
 LL |     let fancy_field = &drop_struct.fancy;
diff --git a/tests/ui/issues/issue-17385.stderr b/tests/ui/issues/issue-17385.stderr
index 988db0fb1fc..3c451a859e9 100644
--- a/tests/ui/issues/issue-17385.stderr
+++ b/tests/ui/issues/issue-17385.stderr
@@ -12,7 +12,10 @@ note: if `X` implemented `Clone`, you could clone the value
   --> $DIR/issue-17385.rs:1:1
    |
 LL | struct X(isize);
-   | ^^^^^^^^
+   | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     drop(foo);
+   |          --- you could clone this value
 
 error[E0382]: use of moved value: `e`
   --> $DIR/issue-17385.rs:25:11
@@ -28,7 +31,10 @@ note: if `Enum` implemented `Clone`, you could clone the value
   --> $DIR/issue-17385.rs:3:1
    |
 LL | enum Enum {
-   | ^^^^^^^^^
+   | ^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     drop(e);
+   |          - you could clone this value
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/issues/issue-24357.rs b/tests/ui/issues/issue-24357.rs
index d1a9e37251e..63c061594d8 100644
--- a/tests/ui/issues/issue-24357.rs
+++ b/tests/ui/issues/issue-24357.rs
@@ -1,10 +1,12 @@
 struct NoCopy; //~ NOTE if `NoCopy` implemented `Clone`, you could clone the value
+//~^ NOTE consider implementing `Clone` for this type
 fn main() {
    let x = NoCopy;
    //~^ NOTE move occurs because `x` has type `NoCopy`
    let f = move || { let y = x; };
    //~^ NOTE value moved into closure here
    //~| NOTE variable moved due to use in closure
+   //~| NOTE you could clone this value
    let z = x;
    //~^ ERROR use of moved value: `x`
    //~| NOTE value used here after move
diff --git a/tests/ui/issues/issue-24357.stderr b/tests/ui/issues/issue-24357.stderr
index 6d50eea7e21..2d85077fe4c 100644
--- a/tests/ui/issues/issue-24357.stderr
+++ b/tests/ui/issues/issue-24357.stderr
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `x`
-  --> $DIR/issue-24357.rs:8:12
+  --> $DIR/issue-24357.rs:10:12
    |
 LL |    let x = NoCopy;
    |        - move occurs because `x` has type `NoCopy`, which does not implement the `Copy` trait
@@ -16,7 +16,10 @@ note: if `NoCopy` implemented `Clone`, you could clone the value
   --> $DIR/issue-24357.rs:1:1
    |
 LL | struct NoCopy;
-   | ^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |    let f = move || { let y = x; };
+   |                              - you could clone this value
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-4335.stderr b/tests/ui/issues/issue-4335.stderr
index 8b4aff54dc3..14b5cfa9f9a 100644
--- a/tests/ui/issues/issue-4335.stderr
+++ b/tests/ui/issues/issue-4335.stderr
@@ -7,6 +7,14 @@ LL |     id(Box::new(|| *v))
    |                 -- ^^ move occurs because `*v` has type `T`, which does not implement the `Copy` trait
    |                 |
    |                 captured by this `FnMut` closure
+   |
+help: if `T` implemented `Clone`, you could clone the value
+  --> $DIR/issue-4335.rs:5:10
+   |
+LL | fn f<'r, T>(v: &'r T) -> Box<dyn FnMut() -> T + 'r> {
+   |          ^ consider constraining this type parameter with `Clone`
+LL |     id(Box::new(|| *v))
+   |                    -- you could clone this value
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/mir/issue-102389.stderr b/tests/ui/mir/issue-102389.stderr
index 838eaffb5a0..162d7ac031a 100644
--- a/tests/ui/mir/issue-102389.stderr
+++ b/tests/ui/mir/issue-102389.stderr
@@ -8,7 +8,10 @@ note: if `Enum` implemented `Clone`, you could clone the value
   --> $DIR/issue-102389.rs:1:1
    |
 LL | enum Enum { A, B, C }
-   | ^^^^^^^^^
+   | ^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     array[*inbounds as usize]
+   |           --------- you could clone this value
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/moves/borrow-closures-instead-of-move.rs b/tests/ui/moves/borrow-closures-instead-of-move.rs
index 51771ced7f2..e4bca54e995 100644
--- a/tests/ui/moves/borrow-closures-instead-of-move.rs
+++ b/tests/ui/moves/borrow-closures-instead-of-move.rs
@@ -1,4 +1,4 @@
-fn takes_fn(f: impl Fn()) {
+fn takes_fn(f: impl Fn()) { //~ HELP if `impl Fn()` implemented `Clone`
     loop {
         takes_fnonce(f);
         //~^ ERROR use of moved value
@@ -6,7 +6,7 @@ fn takes_fn(f: impl Fn()) {
     }
 }
 
-fn takes_fn_mut(m: impl FnMut()) {
+fn takes_fn_mut(m: impl FnMut()) { //~ HELP if `impl FnMut()` implemented `Clone`
     if maybe() {
         takes_fnonce(m);
         //~^ HELP consider mutably borrowing
diff --git a/tests/ui/moves/borrow-closures-instead-of-move.stderr b/tests/ui/moves/borrow-closures-instead-of-move.stderr
index 9a84ddef7e6..ab6ff417efb 100644
--- a/tests/ui/moves/borrow-closures-instead-of-move.stderr
+++ b/tests/ui/moves/borrow-closures-instead-of-move.stderr
@@ -15,6 +15,14 @@ LL | fn takes_fnonce(_: impl FnOnce()) {}
    |    ------------    ^^^^^^^^^^^^^ this parameter takes ownership of the value
    |    |
    |    in this function
+help: if `impl Fn()` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-closures-instead-of-move.rs:1:16
+   |
+LL | fn takes_fn(f: impl Fn()) {
+   |                ^^^^^^^^^ consider constraining this type parameter with `Clone`
+LL |     loop {
+LL |         takes_fnonce(f);
+   |                      - you could clone this value
 help: consider borrowing `f`
    |
 LL |         takes_fnonce(&f);
@@ -39,6 +47,14 @@ LL | fn takes_fnonce(_: impl FnOnce()) {}
    |    ------------    ^^^^^^^^^^^^^ this parameter takes ownership of the value
    |    |
    |    in this function
+help: if `impl FnMut()` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-closures-instead-of-move.rs:9:20
+   |
+LL | fn takes_fn_mut(m: impl FnMut()) {
+   |                    ^^^^^^^^^^^^ consider constraining this type parameter with `Clone`
+LL |     if maybe() {
+LL |         takes_fnonce(m);
+   |                      - you could clone this value
 help: consider mutably borrowing `m`
    |
 LL |         takes_fnonce(&mut m);
diff --git a/tests/ui/moves/issue-72649-uninit-in-loop.rs b/tests/ui/moves/issue-72649-uninit-in-loop.rs
index 86f389cb3af..8f2e01bdf1a 100644
--- a/tests/ui/moves/issue-72649-uninit-in-loop.rs
+++ b/tests/ui/moves/issue-72649-uninit-in-loop.rs
@@ -7,6 +7,10 @@ struct NonCopy;
 //~| NOTE if `NonCopy` implemented `Clone`
 //~| NOTE if `NonCopy` implemented `Clone`
 //~| NOTE if `NonCopy` implemented `Clone`
+//~| NOTE consider implementing `Clone` for this type
+//~| NOTE consider implementing `Clone` for this type
+//~| NOTE consider implementing `Clone` for this type
+//~| NOTE consider implementing `Clone` for this type
 
 fn good() {
     loop {
@@ -21,6 +25,7 @@ fn moved_here_1() {
         //~^ NOTE move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
         let _used = value;
         //~^ NOTE value moved here
+        //~| NOTE you could clone this value
         let _used2 = value; //~ ERROR use of moved value: `value`
         //~^ NOTE value used here after move
     }
@@ -32,6 +37,7 @@ fn moved_here_2() {
     loop { //~ NOTE inside of this loop
         let _used = value;
         //~^ NOTE value moved here
+        //~| NOTE you could clone this value
         loop {
             let _used2 = value; //~ ERROR use of moved value: `value`
             //~^ NOTE value used here after move
@@ -45,6 +51,7 @@ fn moved_loop_1() {
     loop { //~ NOTE inside of this loop
         let _used = value; //~ ERROR use of moved value: `value`
         //~^ NOTE value moved here, in previous iteration of loop
+        //~| NOTE you could clone this value
     }
 }
 
@@ -56,6 +63,7 @@ fn moved_loop_2() {
     loop { //~ NOTE inside of this loop
         let _used2 = value; //~ ERROR use of moved value: `value`
         //~^ NOTE value moved here, in previous iteration of loop
+        //~| NOTE you could clone this value
     }
 }
 
diff --git a/tests/ui/moves/issue-72649-uninit-in-loop.stderr b/tests/ui/moves/issue-72649-uninit-in-loop.stderr
index a613f35a35e..3a93769ac45 100644
--- a/tests/ui/moves/issue-72649-uninit-in-loop.stderr
+++ b/tests/ui/moves/issue-72649-uninit-in-loop.stderr
@@ -1,12 +1,12 @@
 error[E0382]: use of moved value: `value`
-  --> $DIR/issue-72649-uninit-in-loop.rs:24:22
+  --> $DIR/issue-72649-uninit-in-loop.rs:29:22
    |
 LL |         let value = NonCopy{};
    |             ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
 LL |
 LL |         let _used = value;
    |                     ----- value moved here
-LL |
+...
 LL |         let _used2 = value;
    |                      ^^^^^ value used here after move
    |
@@ -14,10 +14,13 @@ note: if `NonCopy` implemented `Clone`, you could clone the value
   --> $DIR/issue-72649-uninit-in-loop.rs:5:1
    |
 LL | struct NonCopy;
-   | ^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |         let _used = value;
+   |                     ----- you could clone this value
 
 error[E0382]: use of moved value: `value`
-  --> $DIR/issue-72649-uninit-in-loop.rs:36:26
+  --> $DIR/issue-72649-uninit-in-loop.rs:42:26
    |
 LL |     let value = NonCopy{};
    |         ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
@@ -34,10 +37,13 @@ note: if `NonCopy` implemented `Clone`, you could clone the value
   --> $DIR/issue-72649-uninit-in-loop.rs:5:1
    |
 LL | struct NonCopy;
-   | ^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |         let _used = value;
+   |                     ----- you could clone this value
 
 error[E0382]: use of moved value: `value`
-  --> $DIR/issue-72649-uninit-in-loop.rs:46:21
+  --> $DIR/issue-72649-uninit-in-loop.rs:52:21
    |
 LL |     let value = NonCopy{};
    |         ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
@@ -51,10 +57,13 @@ note: if `NonCopy` implemented `Clone`, you could clone the value
   --> $DIR/issue-72649-uninit-in-loop.rs:5:1
    |
 LL | struct NonCopy;
-   | ^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |         let _used = value;
+   |                     ----- you could clone this value
 
 error[E0382]: use of moved value: `value`
-  --> $DIR/issue-72649-uninit-in-loop.rs:57:22
+  --> $DIR/issue-72649-uninit-in-loop.rs:64:22
    |
 LL |     let mut value = NonCopy{};
    |         --------- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
@@ -68,10 +77,13 @@ note: if `NonCopy` implemented `Clone`, you could clone the value
   --> $DIR/issue-72649-uninit-in-loop.rs:5:1
    |
 LL | struct NonCopy;
-   | ^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |         let _used2 = value;
+   |                      ----- you could clone this value
 
 error[E0381]: used binding `value` isn't initialized
-  --> $DIR/issue-72649-uninit-in-loop.rs:65:21
+  --> $DIR/issue-72649-uninit-in-loop.rs:73:21
    |
 LL |         let value: NonCopy;
    |             ----- binding declared here but left uninitialized
@@ -84,7 +96,7 @@ LL |         let value: NonCopy = /* value */;
    |                            +++++++++++++
 
 error[E0381]: used binding `value` isn't initialized
-  --> $DIR/issue-72649-uninit-in-loop.rs:73:21
+  --> $DIR/issue-72649-uninit-in-loop.rs:81:21
    |
 LL |     let mut value: NonCopy;
    |         --------- binding declared here but left uninitialized
diff --git a/tests/ui/moves/issue-75904-move-closure-loop.stderr b/tests/ui/moves/issue-75904-move-closure-loop.stderr
index b6ad906bbdb..815e91b0f4d 100644
--- a/tests/ui/moves/issue-75904-move-closure-loop.stderr
+++ b/tests/ui/moves/issue-75904-move-closure-loop.stderr
@@ -15,7 +15,10 @@ note: if `NotCopy` implemented `Clone`, you could clone the value
   --> $DIR/issue-75904-move-closure-loop.rs:5:1
    |
 LL | struct NotCopy;
-   | ^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |             a;
+   |             - you could clone this value
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/moves/move-fn-self-receiver.stderr b/tests/ui/moves/move-fn-self-receiver.stderr
index e6bf52276ac..f2c6008d27e 100644
--- a/tests/ui/moves/move-fn-self-receiver.stderr
+++ b/tests/ui/moves/move-fn-self-receiver.stderr
@@ -106,7 +106,10 @@ note: if `Foo` implemented `Clone`, you could clone the value
   --> $DIR/move-fn-self-receiver.rs:5:1
    |
 LL | struct Foo;
-   | ^^^^^^^^^^
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let ret = mut_foo.use_mut_self();
+   |               ------- you could clone this value
 
 error[E0382]: use of moved value: `rc_foo`
   --> $DIR/move-fn-self-receiver.rs:55:5
@@ -142,7 +145,10 @@ note: if `Foo` implemented `Clone`, you could clone the value
   --> $DIR/move-fn-self-receiver.rs:5:1
    |
 LL | struct Foo;
-   | ^^^^^^^^^^
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     foo_add + Foo;
+   |     ------- you could clone this value
 note: calling this operator moves the left-hand side
   --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
 
diff --git a/tests/ui/moves/move-out-of-array-1.stderr b/tests/ui/moves/move-out-of-array-1.stderr
index 9e4a08e0cef..8a030f02192 100644
--- a/tests/ui/moves/move-out-of-array-1.stderr
+++ b/tests/ui/moves/move-out-of-array-1.stderr
@@ -11,7 +11,10 @@ note: if `D` implemented `Clone`, you could clone the value
   --> $DIR/move-out-of-array-1.rs:5:1
    |
 LL | struct D { _x: u8 }
-   | ^^^^^^^^
+   | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     a[i]
+   |     ---- you could clone this value
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr b/tests/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr
index 4759b45892c..a8473bb8198 100644
--- a/tests/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr
+++ b/tests/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr
@@ -17,6 +17,13 @@ LL |     let mut r = R {c: Box::new(f)};
 LL |     f(&mut r, false)
    |     ^ value borrowed here after move
    |
+help: if `F` implemented `Clone`, you could clone the value
+  --> $DIR/moves-based-on-type-no-recursive-stack-closure.rs:30:16
+   |
+LL | fn conspirator<F>(mut f: F) where F: FnMut(&mut R, bool) {
+   |                ^ consider constraining this type parameter with `Clone`
+LL |     let mut r = R {c: Box::new(f)};
+   |                                - you could clone this value
 help: consider mutably borrowing `f`
    |
 LL |     let mut r = R {c: Box::new(&mut f)};
diff --git a/tests/ui/moves/use_of_moved_value_copy_suggestions.fixed b/tests/ui/moves/use_of_moved_value_copy_suggestions.fixed
index e726c8145c3..bfb855c7fb1 100644
--- a/tests/ui/moves/use_of_moved_value_copy_suggestions.fixed
+++ b/tests/ui/moves/use_of_moved_value_copy_suggestions.fixed
@@ -3,6 +3,7 @@
 
 fn duplicate_t<T: Copy>(t: T) -> (T, T) {
     //~^ HELP consider restricting type parameter `T`
+    //~| HELP if `T` implemented `Clone`, you could clone the value
     (t, t) //~ use of moved value: `t`
 }
 
@@ -72,10 +73,11 @@ where
 #[rustfmt::skip]
 fn existing_colon<T: Copy>(t: T) {
     //~^ HELP consider restricting type parameter `T`
+    //~| HELP if `T` implemented `Clone`, you could clone the value
     [t, t]; //~ use of moved value: `t`
 }
 
-fn existing_colon_in_where<T>(t: T)
+fn existing_colon_in_where<T>(t: T) //~ HELP if `T` implemented `Clone`, you could clone the value
 where
     T:, T: Copy
     //~^ HELP consider further restricting type parameter `T`
diff --git a/tests/ui/moves/use_of_moved_value_copy_suggestions.rs b/tests/ui/moves/use_of_moved_value_copy_suggestions.rs
index ee08ce0fa5b..fbe5a1d74c3 100644
--- a/tests/ui/moves/use_of_moved_value_copy_suggestions.rs
+++ b/tests/ui/moves/use_of_moved_value_copy_suggestions.rs
@@ -3,6 +3,7 @@
 
 fn duplicate_t<T>(t: T) -> (T, T) {
     //~^ HELP consider restricting type parameter `T`
+    //~| HELP if `T` implemented `Clone`, you could clone the value
     (t, t) //~ use of moved value: `t`
 }
 
@@ -72,10 +73,11 @@ where
 #[rustfmt::skip]
 fn existing_colon<T:>(t: T) {
     //~^ HELP consider restricting type parameter `T`
+    //~| HELP if `T` implemented `Clone`, you could clone the value
     [t, t]; //~ use of moved value: `t`
 }
 
-fn existing_colon_in_where<T>(t: T)
+fn existing_colon_in_where<T>(t: T) //~ HELP if `T` implemented `Clone`, you could clone the value
 where
     T:,
     //~^ HELP consider further restricting type parameter `T`
diff --git a/tests/ui/moves/use_of_moved_value_copy_suggestions.stderr b/tests/ui/moves/use_of_moved_value_copy_suggestions.stderr
index 3e37fcb2141..c03204c7b9f 100644
--- a/tests/ui/moves/use_of_moved_value_copy_suggestions.stderr
+++ b/tests/ui/moves/use_of_moved_value_copy_suggestions.stderr
@@ -1,21 +1,29 @@
 error[E0382]: use of moved value: `t`
-  --> $DIR/use_of_moved_value_copy_suggestions.rs:6:9
+  --> $DIR/use_of_moved_value_copy_suggestions.rs:7:9
    |
 LL | fn duplicate_t<T>(t: T) -> (T, T) {
    |                   - move occurs because `t` has type `T`, which does not implement the `Copy` trait
-LL |
+...
 LL |     (t, t)
    |      -  ^ value used here after move
    |      |
    |      value moved here
    |
+help: if `T` implemented `Clone`, you could clone the value
+  --> $DIR/use_of_moved_value_copy_suggestions.rs:4:16
+   |
+LL | fn duplicate_t<T>(t: T) -> (T, T) {
+   |                ^ consider constraining this type parameter with `Clone`
+...
+LL |     (t, t)
+   |      - you could clone this value
 help: consider restricting type parameter `T`
    |
 LL | fn duplicate_t<T: Copy>(t: T) -> (T, T) {
    |                 ++++++
 
 error[E0382]: use of moved value: `t`
-  --> $DIR/use_of_moved_value_copy_suggestions.rs:11:9
+  --> $DIR/use_of_moved_value_copy_suggestions.rs:12:9
    |
 LL | fn duplicate_opt<T>(t: Option<T>) -> (Option<T>, Option<T>) {
    |                     - move occurs because `t` has type `Option<T>`, which does not implement the `Copy` trait
@@ -31,7 +39,7 @@ LL | fn duplicate_opt<T: Copy>(t: Option<T>) -> (Option<T>, Option<T>) {
    |                   ++++++
 
 error[E0382]: use of moved value: `t`
-  --> $DIR/use_of_moved_value_copy_suggestions.rs:16:9
+  --> $DIR/use_of_moved_value_copy_suggestions.rs:17:9
    |
 LL | fn duplicate_tup1<T>(t: (T,)) -> ((T,), (T,)) {
    |                      - move occurs because `t` has type `(T,)`, which does not implement the `Copy` trait
@@ -47,7 +55,7 @@ LL | fn duplicate_tup1<T: Copy>(t: (T,)) -> ((T,), (T,)) {
    |                    ++++++
 
 error[E0382]: use of moved value: `t`
-  --> $DIR/use_of_moved_value_copy_suggestions.rs:21:9
+  --> $DIR/use_of_moved_value_copy_suggestions.rs:22:9
    |
 LL | fn duplicate_tup2<A, B>(t: (A, B)) -> ((A, B), (A, B)) {
    |                         - move occurs because `t` has type `(A, B)`, which does not implement the `Copy` trait
@@ -63,7 +71,7 @@ LL | fn duplicate_tup2<A: Copy, B: Copy>(t: (A, B)) -> ((A, B), (A, B)) {
    |                    ++++++   ++++++
 
 error[E0382]: use of moved value: `t`
-  --> $DIR/use_of_moved_value_copy_suggestions.rs:26:9
+  --> $DIR/use_of_moved_value_copy_suggestions.rs:27:9
    |
 LL | fn duplicate_custom<T>(t: S<T>) -> (S<T>, S<T>) {
    |                        - move occurs because `t` has type `S<T>`, which does not implement the `Copy` trait
@@ -79,7 +87,7 @@ LL | fn duplicate_custom<T: Copy + Trait>(t: S<T>) -> (S<T>, S<T>) {
    |                      ++++++++++++++
 
 error[E0382]: use of moved value: `t`
-  --> $DIR/use_of_moved_value_copy_suggestions.rs:44:9
+  --> $DIR/use_of_moved_value_copy_suggestions.rs:45:9
    |
 LL | fn duplicate_custom_1<T>(t: S<T>) -> (S<T>, S<T>) where {
    |                          - move occurs because `t` has type `S<T>`, which does not implement the `Copy` trait
@@ -95,7 +103,7 @@ LL | fn duplicate_custom_1<T: Copy + Trait>(t: S<T>) -> (S<T>, S<T>) where {
    |                        ++++++++++++++
 
 error[E0382]: use of moved value: `t`
-  --> $DIR/use_of_moved_value_copy_suggestions.rs:52:9
+  --> $DIR/use_of_moved_value_copy_suggestions.rs:53:9
    |
 LL | fn duplicate_custom_2<T>(t: S<T>) -> (S<T>, S<T>)
    |                          - move occurs because `t` has type `S<T>`, which does not implement the `Copy` trait
@@ -111,7 +119,7 @@ LL |     T: A + Copy + Trait,
    |          ++++++++++++++
 
 error[E0382]: use of moved value: `t`
-  --> $DIR/use_of_moved_value_copy_suggestions.rs:61:9
+  --> $DIR/use_of_moved_value_copy_suggestions.rs:62:9
    |
 LL | fn duplicate_custom_3<T>(t: S<T>) -> (S<T>, S<T>)
    |                          - move occurs because `t` has type `S<T>`, which does not implement the `Copy` trait
@@ -127,7 +135,7 @@ LL |     T: A + Copy + Trait,
    |          ++++++++++++++
 
 error[E0382]: use of moved value: `t`
-  --> $DIR/use_of_moved_value_copy_suggestions.rs:69:9
+  --> $DIR/use_of_moved_value_copy_suggestions.rs:70:9
    |
 LL | fn duplicate_custom_4<T: A>(t: S<T>) -> (S<T>, S<T>)
    |                             - move occurs because `t` has type `S<T>`, which does not implement the `Copy` trait
@@ -143,23 +151,31 @@ LL | fn duplicate_custom_4<T: A + Copy + Trait>(t: S<T>) -> (S<T>, S<T>)
    |                            ++++++++++++++
 
 error[E0382]: use of moved value: `t`
-  --> $DIR/use_of_moved_value_copy_suggestions.rs:75:9
+  --> $DIR/use_of_moved_value_copy_suggestions.rs:77:9
    |
 LL | fn existing_colon<T:>(t: T) {
    |                       - move occurs because `t` has type `T`, which does not implement the `Copy` trait
-LL |
+...
 LL |     [t, t];
    |      -  ^ value used here after move
    |      |
    |      value moved here
    |
+help: if `T` implemented `Clone`, you could clone the value
+  --> $DIR/use_of_moved_value_copy_suggestions.rs:74:19
+   |
+LL | fn existing_colon<T:>(t: T) {
+   |                   ^ consider constraining this type parameter with `Clone`
+...
+LL |     [t, t];
+   |      - you could clone this value
 help: consider restricting type parameter `T`
    |
 LL | fn existing_colon<T: Copy>(t: T) {
    |                      ++++
 
 error[E0382]: use of moved value: `t`
-  --> $DIR/use_of_moved_value_copy_suggestions.rs:83:9
+  --> $DIR/use_of_moved_value_copy_suggestions.rs:85:9
    |
 LL | fn existing_colon_in_where<T>(t: T)
    |                               - move occurs because `t` has type `T`, which does not implement the `Copy` trait
@@ -169,6 +185,14 @@ LL |     [t, t];
    |      |
    |      value moved here
    |
+help: if `T` implemented `Clone`, you could clone the value
+  --> $DIR/use_of_moved_value_copy_suggestions.rs:80:28
+   |
+LL | fn existing_colon_in_where<T>(t: T)
+   |                            ^ consider constraining this type parameter with `Clone`
+...
+LL |     [t, t];
+   |      - you could clone this value
 help: consider further restricting type parameter `T`
    |
 LL |     T:, T: Copy
diff --git a/tests/ui/nll/issue-21232-partial-init-and-use.stderr b/tests/ui/nll/issue-21232-partial-init-and-use.stderr
index 2aff375f0a7..496a298a36c 100644
--- a/tests/ui/nll/issue-21232-partial-init-and-use.stderr
+++ b/tests/ui/nll/issue-21232-partial-init-and-use.stderr
@@ -32,7 +32,10 @@ note: if `S<Box<u32>>` implemented `Clone`, you could clone the value
   --> $DIR/issue-21232-partial-init-and-use.rs:15:1
    |
 LL | struct S<Y> {
-   | ^^^^^^^^^^^
+   | ^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let mut s: S<B> = S::new(); drop(s);
+   |                                      - you could clone this value
 
 error[E0382]: assign to part of moved value: `t`
   --> $DIR/issue-21232-partial-init-and-use.rs:116:5
@@ -83,7 +86,10 @@ note: if `S<Box<u32>>` implemented `Clone`, you could clone the value
   --> $DIR/issue-21232-partial-init-and-use.rs:15:1
    |
 LL | struct S<Y> {
-   | ^^^^^^^^^^^
+   | ^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let mut s: S<B> = S::new(); drop(s);
+   |                                      - you could clone this value
 
 error[E0382]: assign to part of moved value: `t`
   --> $DIR/issue-21232-partial-init-and-use.rs:142:5
diff --git a/tests/ui/nll/move-errors.stderr b/tests/ui/nll/move-errors.stderr
index 842ecaf524b..d1384121379 100644
--- a/tests/ui/nll/move-errors.stderr
+++ b/tests/ui/nll/move-errors.stderr
@@ -8,7 +8,10 @@ note: if `A` implemented `Clone`, you could clone the value
   --> $DIR/move-errors.rs:1:1
    |
 LL | struct A(String);
-   | ^^^^^^^^
+   | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let b = *a;
+   |             -- you could clone this value
 help: consider removing the dereference here
    |
 LL -     let b = *a;
@@ -28,7 +31,10 @@ note: if `A` implemented `Clone`, you could clone the value
   --> $DIR/move-errors.rs:1:1
    |
 LL | struct A(String);
-   | ^^^^^^^^
+   | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let b = a[0];
+   |             ---- you could clone this value
 help: consider borrowing here
    |
 LL |     let b = &a[0];
@@ -44,7 +50,10 @@ note: if `A` implemented `Clone`, you could clone the value
   --> $DIR/move-errors.rs:1:1
    |
 LL | struct A(String);
-   | ^^^^^^^^
+   | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let s = **r;
+   |             --- you could clone this value
 help: consider removing the dereference here
    |
 LL -     let s = **r;
@@ -61,7 +70,10 @@ note: if `A` implemented `Clone`, you could clone the value
   --> $DIR/move-errors.rs:1:1
    |
 LL | struct A(String);
-   | ^^^^^^^^
+   | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let s = *r;
+   |             -- you could clone this value
 help: consider removing the dereference here
    |
 LL -     let s = *r;
@@ -81,7 +93,10 @@ note: if `A` implemented `Clone`, you could clone the value
   --> $DIR/move-errors.rs:1:1
    |
 LL | struct A(String);
-   | ^^^^^^^^
+   | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let a = [A("".to_string())][0];
+   |             ---------------------- you could clone this value
 help: consider borrowing here
    |
 LL |     let a = &[A("".to_string())][0];
@@ -126,7 +141,10 @@ note: if `A` implemented `Clone`, you could clone the value
   --> $DIR/move-errors.rs:1:1
    |
 LL | struct A(String);
-   | ^^^^^^^^
+   | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     b = *a;
+   |         -- you could clone this value
 
 error[E0508]: cannot move out of type `[B; 1]`, a non-copy array
   --> $DIR/move-errors.rs:74:11
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
index 00964cb8336..e925fe78f33 100644
--- a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
@@ -337,7 +337,10 @@ note: if `U` implemented `Clone`, you could clone the value
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:17:5
    |
 LL |     struct U;
-   |     ^^^^^^^^
+   |     ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
+   |                                                                  - you could clone this value
 
 error[E0507]: cannot move out of `b` in pattern guard
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:66
@@ -350,7 +353,10 @@ note: if `U` implemented `Clone`, you could clone the value
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:17:5
    |
 LL |     struct U;
-   |     ^^^^^^^^
+   |     ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
+   |                                                                  - you could clone this value
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0507]: cannot move out of `a` in pattern guard
diff --git a/tests/ui/suggestions/option-content-move3.rs b/tests/ui/suggestions/option-content-move3.rs
new file mode 100644
index 00000000000..afd8fd0c3a2
--- /dev/null
+++ b/tests/ui/suggestions/option-content-move3.rs
@@ -0,0 +1,17 @@
+#[derive(Debug, Clone)]
+struct NotCopyable;
+
+fn func<F: FnMut() -> H, H: FnMut()>(_: F) {}
+
+fn parse() {
+    let mut var = NotCopyable;
+    func(|| {
+        // Shouldn't suggest `move ||.as_ref()` here
+        move || { //~ ERROR cannot move out of `var`
+            let x = var; //~ ERROR cannot move out of `var`
+            println!("{x:?}");
+        }
+    });
+}
+
+fn main() {}
diff --git a/tests/ui/suggestions/option-content-move3.stderr b/tests/ui/suggestions/option-content-move3.stderr
new file mode 100644
index 00000000000..2d28d9b5ea7
--- /dev/null
+++ b/tests/ui/suggestions/option-content-move3.stderr
@@ -0,0 +1,35 @@
+error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure
+  --> $DIR/option-content-move3.rs:11:21
+   |
+LL |     let mut var = NotCopyable;
+   |         ------- captured outer variable
+...
+LL |         move || {
+   |         ------- captured by this `FnMut` closure
+LL |             let x = var;
+   |                     ^^^ move occurs because `var` has type `NotCopyable`, which does not implement the `Copy` trait
+   |
+help: consider borrowing here
+   |
+LL |             let x = &var;
+   |                     +
+
+error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure
+  --> $DIR/option-content-move3.rs:10:9
+   |
+LL |     let mut var = NotCopyable;
+   |         ------- captured outer variable
+LL |     func(|| {
+   |          -- captured by this `FnMut` closure
+LL |         // Shouldn't suggest `move ||.as_ref()` here
+LL |         move || {
+   |         ^^^^^^^ `var` is moved here
+LL |             let x = var;
+   |                     ---
+   |                     |
+   |                     variable moved due to use in closure
+   |                     move occurs because `var` has type `NotCopyable`, which does not implement the `Copy` trait
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/union/union-borrow-move-parent-sibling.stderr b/tests/ui/union/union-borrow-move-parent-sibling.stderr
index 782fa63280e..f8e9609cb1c 100644
--- a/tests/ui/union/union-borrow-move-parent-sibling.stderr
+++ b/tests/ui/union/union-borrow-move-parent-sibling.stderr
@@ -54,7 +54,10 @@ note: if `MockVec<u8>` implemented `Clone`, you could clone the value
   --> $DIR/union-borrow-move-parent-sibling.rs:25:1
    |
 LL | struct MockVec<T> {
-   | ^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let a = (u.x.0).0;
+   |             --------- you could clone this value
 help: consider borrowing here
    |
 LL |     let a = &(u.x.0).0;
diff --git a/tests/ui/union/union-move.stderr b/tests/ui/union/union-move.stderr
index 5ebb2716e5a..d520fb00ea9 100644
--- a/tests/ui/union/union-move.stderr
+++ b/tests/ui/union/union-move.stderr
@@ -20,7 +20,10 @@ note: if `U1` implemented `Clone`, you could clone the value
   --> $DIR/union-move.rs:9:1
    |
 LL | union U1 {
-   | ^^^^^^^^
+   | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |         move_out(x.f1_nocopy);
+   |                  ----------- you could clone this value
 
 error[E0382]: use of moved value: `x`
   --> $DIR/union-move.rs:42:18
@@ -44,7 +47,10 @@ note: if `U1` implemented `Clone`, you could clone the value
   --> $DIR/union-move.rs:9:1
    |
 LL | union U1 {
-   | ^^^^^^^^
+   | ^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |         move_out(x.f2_nocopy);
+   |                  ----------- you could clone this value
 
 error[E0509]: cannot move out of type `U2`, which implements the `Drop` trait
   --> $DIR/union-move.rs:49:18
diff --git a/tests/ui/unop-move-semantics.stderr b/tests/ui/unop-move-semantics.stderr
index 187dd66b2fe..bc9b3ea9903 100644
--- a/tests/ui/unop-move-semantics.stderr
+++ b/tests/ui/unop-move-semantics.stderr
@@ -33,6 +33,14 @@ LL |     !x;
 ...
 LL |     use_mut(n); use_imm(m);
    |                         - borrow later used here
+   |
+help: if `T` implemented `Clone`, you could clone the value
+  --> $DIR/unop-move-semantics.rs:11:18
+   |
+LL | fn move_borrowed<T: Not<Output=T>>(x: T, mut y: T) {
+   |                  ^ consider constraining this type parameter with `Clone`
+LL |     let m = &x;
+   |             -- you could clone this value
 
 error[E0505]: cannot move out of `y` because it is borrowed
   --> $DIR/unop-move-semantics.rs:17:6
@@ -47,6 +55,15 @@ LL |     !y;
    |      ^ move out of `y` occurs here
 LL |     use_mut(n); use_imm(m);
    |             - borrow later used here
+   |
+help: if `T` implemented `Clone`, you could clone the value
+  --> $DIR/unop-move-semantics.rs:11:18
+   |
+LL | fn move_borrowed<T: Not<Output=T>>(x: T, mut y: T) {
+   |                  ^ consider constraining this type parameter with `Clone`
+LL |     let m = &x;
+LL |     let n = &mut y;
+   |             ------ you could clone this value
 
 error[E0507]: cannot move out of `*m` which is behind a mutable reference
   --> $DIR/unop-move-semantics.rs:24:6
@@ -59,6 +76,14 @@ LL |     !*m;
    |
 note: calling this operator moves the value
   --> $SRC_DIR/core/src/ops/bit.rs:LL:COL
+help: if `T` implemented `Clone`, you could clone the value
+  --> $DIR/unop-move-semantics.rs:20:24
+   |
+LL | fn illegal_dereference<T: Not<Output=T>>(mut x: T, y: T) {
+   |                        ^ consider constraining this type parameter with `Clone`
+...
+LL |     !*m;
+   |      -- you could clone this value
 
 error[E0507]: cannot move out of `*n` which is behind a shared reference
   --> $DIR/unop-move-semantics.rs:26:6
@@ -68,6 +93,15 @@ LL |     !*n;
    |     ||
    |     |move occurs because `*n` has type `T`, which does not implement the `Copy` trait
    |     `*n` moved due to usage in operator
+   |
+help: if `T` implemented `Clone`, you could clone the value
+  --> $DIR/unop-move-semantics.rs:20:24
+   |
+LL | fn illegal_dereference<T: Not<Output=T>>(mut x: T, y: T) {
+   |                        ^ consider constraining this type parameter with `Clone`
+...
+LL |     !*n;
+   |      -- you could clone this value
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/variance/variance-issue-20533.stderr b/tests/ui/variance/variance-issue-20533.stderr
index 4515d313ec0..03cada07a9e 100644
--- a/tests/ui/variance/variance-issue-20533.stderr
+++ b/tests/ui/variance/variance-issue-20533.stderr
@@ -14,7 +14,10 @@ note: if `AffineU32` implemented `Clone`, you could clone the value
   --> $DIR/variance-issue-20533.rs:26:1
    |
 LL | struct AffineU32(u32);
-   | ^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |         let x = foo(&a);
+   |                     -- you could clone this value
 
 error[E0505]: cannot move out of `a` because it is borrowed
   --> $DIR/variance-issue-20533.rs:41:14
@@ -32,7 +35,10 @@ note: if `AffineU32` implemented `Clone`, you could clone the value
   --> $DIR/variance-issue-20533.rs:26:1
    |
 LL | struct AffineU32(u32);
-   | ^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |         let x = bar(&a);
+   |                     -- you could clone this value
 
 error[E0505]: cannot move out of `a` because it is borrowed
   --> $DIR/variance-issue-20533.rs:47:14
@@ -50,7 +56,10 @@ note: if `AffineU32` implemented `Clone`, you could clone the value
   --> $DIR/variance-issue-20533.rs:26:1
    |
 LL | struct AffineU32(u32);
-   | ^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |         let x = baz(&a);
+   |                     -- you could clone this value
 
 error[E0505]: cannot move out of `a` because it is borrowed
   --> $DIR/variance-issue-20533.rs:53:14