about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2024-03-13 01:51:08 +0000
committerEsteban Küber <esteban@kuber.com.ar>2024-04-11 16:41:41 +0000
commitfa2fc3ab9638aec571574e551cd9708aa4b64280 (patch)
treed4e1e696e03bd7b9a8858841cda70da7928813cb
parentccae456863cf2c10e66d1e179b74ff8e950ebfa4 (diff)
downloadrust-fa2fc3ab9638aec571574e551cd9708aa4b64280.tar.gz
rust-fa2fc3ab9638aec571574e551cd9708aa4b64280.zip
Suggest `.clone()` when moved while borrowed
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs73
-rw-r--r--tests/ui/associated-types/associated-types-outlives.stderr5
-rw-r--r--tests/ui/binop/binop-move-semantics.stderr5
-rw-r--r--tests/ui/borrowck/borrow-tuple-fields.stderr10
-rw-r--r--tests/ui/borrowck/borrowck-bad-nested-calls-move.stderr10
-rw-r--r--tests/ui/borrowck/borrowck-field-sensitivity.stderr10
-rw-r--r--tests/ui/borrowck/borrowck-loan-blocks-move-cc.stderr10
-rw-r--r--tests/ui/borrowck/borrowck-loan-blocks-move.stderr5
-rw-r--r--tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr5
-rw-r--r--tests/ui/borrowck/borrowck-move-mut-base-ptr.stderr5
-rw-r--r--tests/ui/borrowck/borrowck-move-subcomponent.stderr5
-rw-r--r--tests/ui/borrowck/borrowck-multiple-captures.stderr15
-rw-r--r--tests/ui/borrowck/borrowck-unary-move.stderr5
-rw-r--r--tests/ui/borrowck/clone-on-ref.fixed4
-rw-r--r--tests/ui/borrowck/clone-on-ref.stderr8
-rw-r--r--tests/ui/btreemap/btreemap_dropck.stderr5
-rw-r--r--tests/ui/dropck/drop-with-active-borrows-1.stderr5
-rw-r--r--tests/ui/error-codes/E0504.stderr5
-rw-r--r--tests/ui/error-codes/E0505.stderr5
-rw-r--r--tests/ui/fn/implied-bounds-unnorm-associated-type-4.stderr5
-rw-r--r--tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr5
-rw-r--r--tests/ui/fn/implied-bounds-unnorm-associated-type.stderr5
-rw-r--r--tests/ui/nll/closure-access-spans.stderr5
-rw-r--r--tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr5
-rw-r--r--tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr5
-rw-r--r--tests/ui/span/send-is-not-static-std-sync.stderr15
-rw-r--r--tests/ui/suggestions/borrow-for-loop-head.stderr5
-rw-r--r--tests/ui/unop-move-semantics.stderr5
-rw-r--r--tests/ui/variance/variance-issue-20533.stderr15
29 files changed, 246 insertions, 19 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index cf550a2e5d8..8249d5142ed 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -987,6 +987,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         can_suggest_clone
     }
 
+    pub(crate) fn suggest_cloning(
+        &self,
+        err: &mut Diag<'_>,
+        ty: Ty<'tcx>,
+        expr: &hir::Expr<'_>,
+        span: Span,
+    ) {
+        if let Some(clone_trait_def) = self.infcx.tcx.lang_items().clone_trait()
+            && self
+                .infcx
+                .type_implements_trait(clone_trait_def, [ty], self.param_env)
+                .must_apply_modulo_regions()
+        {
+            self.suggest_cloning_inner(err, ty, expr, span);
+        }
+    }
+
     pub(crate) fn clone_on_reference(&self, expr: &hir::Expr<'_>) -> Option<Span> {
         let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
         if let hir::ExprKind::MethodCall(segment, rcvr, args, span) = expr.kind
@@ -1002,7 +1019,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         }
     }
 
-    fn suggest_cloning(&self, err: &mut Diag<'_>, ty: Ty<'tcx>, expr: &hir::Expr<'_>, span: Span) {
+    fn suggest_cloning_inner(
+        &self,
+        err: &mut Diag<'_>,
+        ty: Ty<'tcx>,
+        expr: &hir::Expr<'_>,
+        span: Span,
+    ) {
         let tcx = self.infcx.tcx;
         // Try to find predicates on *generic params* that would allow copying `ty`
         let suggestion =
@@ -1136,6 +1159,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 None,
             );
         self.suggest_copy_for_type_in_cloned_ref(&mut err, place);
+        let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
+        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, borrow_span);
+        }
         self.buffer_error(err);
     }
 
@@ -1553,22 +1582,32 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             }
         }
         for ty in types_to_constrain {
-            self.suggest_adding_bounds(err, ty, clone, body.span);
-            if let ty::Adt(..) = ty.kind() {
-                // The type doesn't implement Clone.
-                let trait_ref = ty::Binder::dummy(ty::TraitRef::new(self.infcx.tcx, clone, [ty]));
-                let obligation = Obligation::new(
-                    self.infcx.tcx,
-                    ObligationCause::dummy(),
-                    self.param_env,
-                    trait_ref,
-                );
-                self.infcx.err_ctxt().suggest_derive(
-                    &obligation,
-                    err,
-                    trait_ref.to_predicate(self.infcx.tcx),
-                );
-            }
+            self.suggest_adding_bounds_or_derive(err, ty, clone, body.span);
+        }
+    }
+
+    pub(crate) fn suggest_adding_bounds_or_derive(
+        &self,
+        err: &mut Diag<'_>,
+        ty: Ty<'tcx>,
+        def_id: DefId,
+        span: Span,
+    ) {
+        self.suggest_adding_bounds(err, ty, def_id, span);
+        if let ty::Adt(..) = ty.kind() {
+            // The type doesn't implement DefId.
+            let trait_ref = ty::Binder::dummy(ty::TraitRef::new(self.infcx.tcx, def_id, [ty]));
+            let obligation = Obligation::new(
+                self.infcx.tcx,
+                ObligationCause::dummy(),
+                self.param_env,
+                trait_ref,
+            );
+            self.infcx.err_ctxt().suggest_derive(
+                &obligation,
+                err,
+                trait_ref.to_predicate(self.infcx.tcx),
+            );
         }
     }
 
diff --git a/tests/ui/associated-types/associated-types-outlives.stderr b/tests/ui/associated-types/associated-types-outlives.stderr
index deeedd22266..dcd05ba9c2e 100644
--- a/tests/ui/associated-types/associated-types-outlives.stderr
+++ b/tests/ui/associated-types/associated-types-outlives.stderr
@@ -10,6 +10,11 @@ LL |         drop(x);
    |              ^ move out of `x` occurs here
 LL |         return f(y);
    |                  - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         's: loop { y = denormalise(&x.clone()); break }
+   |                                      ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/binop/binop-move-semantics.stderr b/tests/ui/binop/binop-move-semantics.stderr
index 1dd8c9a87d4..06dd84c3b9a 100644
--- a/tests/ui/binop/binop-move-semantics.stderr
+++ b/tests/ui/binop/binop-move-semantics.stderr
@@ -51,6 +51,11 @@ LL |     x
 ...
 LL |     use_mut(n); use_imm(m);
    |                         - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let m = &x.clone();
+   |               ++++++++
 
 error[E0505]: cannot move out of `y` because it is borrowed
   --> $DIR/binop-move-semantics.rs:23:5
diff --git a/tests/ui/borrowck/borrow-tuple-fields.stderr b/tests/ui/borrowck/borrow-tuple-fields.stderr
index e324ebfb50f..277c335cfcc 100644
--- a/tests/ui/borrowck/borrow-tuple-fields.stderr
+++ b/tests/ui/borrowck/borrow-tuple-fields.stderr
@@ -10,6 +10,11 @@ LL |     let y = x;
 LL |
 LL |     r.use_ref();
    |     - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let r = &x.0.clone();
+   |                 ++++++++
 
 error[E0502]: cannot borrow `x.0` as mutable because it is also borrowed as immutable
   --> $DIR/borrow-tuple-fields.rs:18:13
@@ -42,6 +47,11 @@ LL |     let y = x;
    |             ^ move out of `x` occurs here
 LL |     r.use_ref();
    |     - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let r = &x.0.clone();
+   |                 ++++++++
 
 error[E0502]: cannot borrow `x.0` as mutable because it is also borrowed as immutable
   --> $DIR/borrow-tuple-fields.rs:33:13
diff --git a/tests/ui/borrowck/borrowck-bad-nested-calls-move.stderr b/tests/ui/borrowck/borrowck-bad-nested-calls-move.stderr
index e582ec605de..eb5e2fa89f8 100644
--- a/tests/ui/borrowck/borrowck-bad-nested-calls-move.stderr
+++ b/tests/ui/borrowck/borrowck-bad-nested-calls-move.stderr
@@ -10,6 +10,11 @@ LL |         &*a,
    |         --- borrow of `*a` occurs here
 LL |         a);
    |         ^ move out of `a` occurs here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         &*a.clone(),
+   |            ++++++++
 
 error[E0505]: cannot move out of `a` because it is borrowed
   --> $DIR/borrowck-bad-nested-calls-move.rs:32:9
@@ -22,6 +27,11 @@ LL |         &*a,
    |         --- borrow of `*a` occurs here
 LL |         a);
    |         ^ move out of `a` occurs here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         &*a.clone(),
+   |            ++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/borrowck/borrowck-field-sensitivity.stderr b/tests/ui/borrowck/borrowck-field-sensitivity.stderr
index 11812847dd1..b30dd144a4d 100644
--- a/tests/ui/borrowck/borrowck-field-sensitivity.stderr
+++ b/tests/ui/borrowck/borrowck-field-sensitivity.stderr
@@ -49,6 +49,11 @@ LL |     drop(x.b);
    |          ^^^ move out of `x.b` occurs here
 LL |     drop(**p);
    |          --- borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let p = &x.b.clone();
+   |                 ++++++++
 
 error[E0505]: cannot move out of `x.b` because it is borrowed
   --> $DIR/borrowck-field-sensitivity.rs:41:14
@@ -61,6 +66,11 @@ LL |     let _y = A { a: 3, .. x };
    |              ^^^^^^^^^^^^^^^^ move out of `x.b` occurs here
 LL |     drop(**p);
    |          --- borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let p = &x.b.clone();
+   |                 ++++++++
 
 error[E0499]: cannot borrow `x.a` as mutable more than once at a time
   --> $DIR/borrowck-field-sensitivity.rs:48:13
diff --git a/tests/ui/borrowck/borrowck-loan-blocks-move-cc.stderr b/tests/ui/borrowck/borrowck-loan-blocks-move-cc.stderr
index 86479043a06..d9af5cf7d12 100644
--- a/tests/ui/borrowck/borrowck-loan-blocks-move-cc.stderr
+++ b/tests/ui/borrowck/borrowck-loan-blocks-move-cc.stderr
@@ -13,6 +13,11 @@ LL |         println!("v={}", *v);
 LL |     });
 LL |     w.use_ref();
    |     - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let w = &v.clone();
+   |               ++++++++
 
 error[E0505]: cannot move out of `v` because it is borrowed
   --> $DIR/borrowck-loan-blocks-move-cc.rs:24:19
@@ -29,6 +34,11 @@ LL |         println!("v={}", *v);
 LL |     });
 LL |     w.use_ref();
    |     - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let w = &v.clone();
+   |               ++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/borrowck/borrowck-loan-blocks-move.stderr b/tests/ui/borrowck/borrowck-loan-blocks-move.stderr
index d1fbc5b47db..1698035f20f 100644
--- a/tests/ui/borrowck/borrowck-loan-blocks-move.stderr
+++ b/tests/ui/borrowck/borrowck-loan-blocks-move.stderr
@@ -9,6 +9,11 @@ LL |     take(v);
    |          ^ move out of `v` occurs here
 LL |     w.use_ref();
    |     - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let w = &v.clone();
+   |               ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr b/tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr
index a41c4af98e7..b78c374c456 100644
--- a/tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr
+++ b/tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr
@@ -10,6 +10,11 @@ LL |     let z = *a;
    |             ^^ move out of `*a` occurs here
 LL |     b.use_ref();
    |     - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let b = &a.clone();
+   |               ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-move-mut-base-ptr.stderr b/tests/ui/borrowck/borrowck-move-mut-base-ptr.stderr
index 88eb6c8ceee..3e540a5dc98 100644
--- a/tests/ui/borrowck/borrowck-move-mut-base-ptr.stderr
+++ b/tests/ui/borrowck/borrowck-move-mut-base-ptr.stderr
@@ -10,6 +10,11 @@ LL |     let t1 = t0;
 LL |     *t1 = 22;
 LL |     p.use_ref();
    |     - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let p: &isize = &*t0.clone(); // Freezes `*t0`
+   |                         ++++++++
 
 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 8408d99156a..5eb02ee2be9 100644
--- a/tests/ui/borrowck/borrowck-move-subcomponent.stderr
+++ b/tests/ui/borrowck/borrowck-move-subcomponent.stderr
@@ -9,6 +9,11 @@ LL |   let S { x: ax } = a;
    |              ^^ move out of `a.x` occurs here
 LL |   f(pb);
    |     -- borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |   let pb = &a.clone();
+   |              ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-multiple-captures.stderr b/tests/ui/borrowck/borrowck-multiple-captures.stderr
index 70abe7b346e..01b648ea647 100644
--- a/tests/ui/borrowck/borrowck-multiple-captures.stderr
+++ b/tests/ui/borrowck/borrowck-multiple-captures.stderr
@@ -14,6 +14,11 @@ LL |         drop(x1);
 ...
 LL |     borrow(&*p1);
    |            ---- borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let p1 = &x1.clone();
+   |                 ++++++++
 
 error[E0505]: cannot move out of `x2` because it is borrowed
   --> $DIR/borrowck-multiple-captures.rs:12:19
@@ -30,6 +35,11 @@ LL |         drop(x2);
 ...
 LL |     borrow(&*p2);
    |            ---- borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let p2 = &x2.clone();
+   |                 ++++++++
 
 error[E0382]: use of moved value: `x1`
   --> $DIR/borrowck-multiple-captures.rs:27:19
@@ -93,6 +103,11 @@ LL |         drop(x);
 ...
 LL |     borrow(&*p);
    |            --- borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let p = &x.clone();
+   |               ++++++++
 
 error[E0382]: use of moved value: `x`
   --> $DIR/borrowck-multiple-captures.rs:52:14
diff --git a/tests/ui/borrowck/borrowck-unary-move.stderr b/tests/ui/borrowck/borrowck-unary-move.stderr
index e6c3869f67a..a4118b3d1a3 100644
--- a/tests/ui/borrowck/borrowck-unary-move.stderr
+++ b/tests/ui/borrowck/borrowck-unary-move.stderr
@@ -9,6 +9,11 @@ LL |     free(x);
    |          ^ move out of `x` occurs here
 LL |     *y
    |     -- borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let y = &*x.clone();
+   |                ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/clone-on-ref.fixed b/tests/ui/borrowck/clone-on-ref.fixed
index b6927ba590e..58339919696 100644
--- a/tests/ui/borrowck/clone-on-ref.fixed
+++ b/tests/ui/borrowck/clone-on-ref.fixed
@@ -9,7 +9,7 @@ fn foo<T: Default + Clone>(list: &mut Vec<T>) {
     drop(cloned_items);
 }
 fn bar<T: std::fmt::Display + Clone>(x: T) {
-    let a = &x;
+    let a = &x.clone();
     let b = a.clone();
     drop(x);
     //~^ ERROR cannot move out of `x` because it is borrowed
@@ -19,7 +19,7 @@ fn bar<T: std::fmt::Display + Clone>(x: T) {
 #[derive(Clone)]
 struct A;
 fn qux(x: A) {
-    let a = &x;
+    let a = &x.clone();
     let b = a.clone();
     drop(x);
     //~^ ERROR cannot move out of `x` because it is borrowed
diff --git a/tests/ui/borrowck/clone-on-ref.stderr b/tests/ui/borrowck/clone-on-ref.stderr
index ee4fcadf55a..732a9370fa7 100644
--- a/tests/ui/borrowck/clone-on-ref.stderr
+++ b/tests/ui/borrowck/clone-on-ref.stderr
@@ -36,6 +36,10 @@ help: consider further restricting this bound
    |
 LL | fn bar<T: std::fmt::Display + Clone>(x: T) {
    |                             +++++++
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let a = &x.clone();
+   |               ++++++++
 
 error[E0505]: cannot move out of `x` because it is borrowed
   --> $DIR/clone-on-ref.rs:23:10
@@ -57,6 +61,10 @@ help: consider annotating `A` with `#[derive(Clone)]`
 LL + #[derive(Clone)]
 LL | struct A;
    |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let a = &x.clone();
+   |               ++++++++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/btreemap/btreemap_dropck.stderr b/tests/ui/btreemap/btreemap_dropck.stderr
index 805c2112bdc..e8f14552af2 100644
--- a/tests/ui/btreemap/btreemap_dropck.stderr
+++ b/tests/ui/btreemap/btreemap_dropck.stderr
@@ -9,6 +9,11 @@ LL |     drop(s);
    |          ^ move out of `s` occurs here
 LL | }
    | - borrow might be used here, when `_map` is dropped and runs the `Drop` code for type `BTreeMap`
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let _map = BTreeMap::from_iter([((), PrintOnDrop(&s.clone()))]);
+   |                                                        ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/dropck/drop-with-active-borrows-1.stderr b/tests/ui/dropck/drop-with-active-borrows-1.stderr
index 229514c6fee..7d1633267f0 100644
--- a/tests/ui/dropck/drop-with-active-borrows-1.stderr
+++ b/tests/ui/dropck/drop-with-active-borrows-1.stderr
@@ -9,6 +9,11 @@ LL |     drop(a);
    |          ^ move out of `a` occurs here
 LL |     for s in &b {
    |              -- borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let b: Vec<&str> = a.clone().lines().collect();
+   |                         ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/error-codes/E0504.stderr b/tests/ui/error-codes/E0504.stderr
index c8a48961cb3..9759e81a2c7 100644
--- a/tests/ui/error-codes/E0504.stderr
+++ b/tests/ui/error-codes/E0504.stderr
@@ -13,6 +13,11 @@ LL |         println!("child function: {}", fancy_num.num);
 ...
 LL |     println!("main function: {}", fancy_ref.num);
    |                                   ------------- borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let fancy_ref = &fancy_num.clone();
+   |                               ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/error-codes/E0505.stderr b/tests/ui/error-codes/E0505.stderr
index 250680d2c1c..6808943796c 100644
--- a/tests/ui/error-codes/E0505.stderr
+++ b/tests/ui/error-codes/E0505.stderr
@@ -10,6 +10,11 @@ LL |         eat(x);
    |             ^ move out of `x` occurs here
 LL |         _ref_to_val.use_ref();
    |         ----------- borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         let _ref_to_val: &Value = &x.clone();
+   |                                     ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/fn/implied-bounds-unnorm-associated-type-4.stderr b/tests/ui/fn/implied-bounds-unnorm-associated-type-4.stderr
index 3be630e2b23..4e64ed6f482 100644
--- a/tests/ui/fn/implied-bounds-unnorm-associated-type-4.stderr
+++ b/tests/ui/fn/implied-bounds-unnorm-associated-type-4.stderr
@@ -10,6 +10,11 @@ LL |     drop(x);
 LL |
 LL |     println!("{}", y);
    |                    - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let y = f(&x.clone(), ());
+   |                 ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr b/tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr
index bf6d77b6269..b898df0835c 100644
--- a/tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr
+++ b/tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr
@@ -27,6 +27,11 @@ LL |     drop(x);
    |          ^ move out of `x` occurs here
 LL |     println!("{}", y);
    |                    - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let y = f(&x.clone(), ());
+   |                 ++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/fn/implied-bounds-unnorm-associated-type.stderr b/tests/ui/fn/implied-bounds-unnorm-associated-type.stderr
index c2a8fa741ca..2a7431305fe 100644
--- a/tests/ui/fn/implied-bounds-unnorm-associated-type.stderr
+++ b/tests/ui/fn/implied-bounds-unnorm-associated-type.stderr
@@ -10,6 +10,11 @@ LL |     drop(x);
 LL |
 LL |     println!("{}", y);
    |                    - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let y = f(&x.clone(), ());
+   |                 ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/nll/closure-access-spans.stderr b/tests/ui/nll/closure-access-spans.stderr
index 3e98fbd5e1d..a8024a8c20b 100644
--- a/tests/ui/nll/closure-access-spans.stderr
+++ b/tests/ui/nll/closure-access-spans.stderr
@@ -57,6 +57,11 @@ LL |     || x;
    |     move out of `x` occurs here
 LL |     r.use_ref();
    |     - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let r = &x.clone();
+   |               ++++++++
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/closure-access-spans.rs:35:5
diff --git a/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
index a033cc0655e..62896e1fd03 100644
--- a/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
+++ b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
@@ -10,6 +10,11 @@ LL |     let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
 LL |     _x1 = U;
 LL |     drop(hold_all);
    |          -------- borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let hold_all = &arr.clone();
+   |                        ++++++++
 
 error[E0384]: cannot assign twice to immutable variable `_x1`
   --> $DIR/borrowck-move-ref-pattern.rs:9:5
diff --git a/tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr b/tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr
index 29a606c4f01..bac7801f7f4 100644
--- a/tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr
+++ b/tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr
@@ -57,6 +57,11 @@ LL |     f(Box::new(|a| {
 LL |
 LL |         foo(f);
    |             - move occurs due to use in closure
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     f.clone()(Box::new(|a| {
+   |      ++++++++
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/span/send-is-not-static-std-sync.stderr b/tests/ui/span/send-is-not-static-std-sync.stderr
index 46534b39168..1f4462f4fe7 100644
--- a/tests/ui/span/send-is-not-static-std-sync.stderr
+++ b/tests/ui/span/send-is-not-static-std-sync.stderr
@@ -11,6 +11,11 @@ LL |     drop(y);
 ...
 LL |         *lock.lock().unwrap() = &z;
    |          ---- borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     *lock.lock().unwrap() = &*y.clone();
+   |                                ++++++++
 
 error[E0597]: `z` does not live long enough
   --> $DIR/send-is-not-static-std-sync.rs:16:33
@@ -38,6 +43,11 @@ LL |     drop(y);
 ...
 LL |         *lock.write().unwrap() = &z;
    |          ---- borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     *lock.write().unwrap() = &*y.clone();
+   |                                 ++++++++
 
 error[E0597]: `z` does not live long enough
   --> $DIR/send-is-not-static-std-sync.rs:30:34
@@ -65,6 +75,11 @@ LL |     drop(y);
 ...
 LL |         tx.send(&z).unwrap();
    |         -- borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     tx.send(&*y.clone());
+   |                ++++++++
 
 error[E0597]: `z` does not live long enough
   --> $DIR/send-is-not-static-std-sync.rs:46:17
diff --git a/tests/ui/suggestions/borrow-for-loop-head.stderr b/tests/ui/suggestions/borrow-for-loop-head.stderr
index 0f179438a12..55fcb44168c 100644
--- a/tests/ui/suggestions/borrow-for-loop-head.stderr
+++ b/tests/ui/suggestions/borrow-for-loop-head.stderr
@@ -7,6 +7,11 @@ LL |     for i in &a {
    |              -- borrow of `a` occurs here
 LL |         for j in a {
    |                  ^ move out of `a` occurs here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     for i in &a.clone() {
+   |                ++++++++
 
 error[E0382]: use of moved value: `a`
   --> $DIR/borrow-for-loop-head.rs:4:18
diff --git a/tests/ui/unop-move-semantics.stderr b/tests/ui/unop-move-semantics.stderr
index 187dd66b2fe..a6549d84a8a 100644
--- a/tests/ui/unop-move-semantics.stderr
+++ b/tests/ui/unop-move-semantics.stderr
@@ -33,6 +33,11 @@ LL |     !x;
 ...
 LL |     use_mut(n); use_imm(m);
    |                         - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let m = &x.clone();
+   |               ++++++++
 
 error[E0505]: cannot move out of `y` because it is borrowed
   --> $DIR/unop-move-semantics.rs:17:6
diff --git a/tests/ui/variance/variance-issue-20533.stderr b/tests/ui/variance/variance-issue-20533.stderr
index 258f67db5ce..7fed947972f 100644
--- a/tests/ui/variance/variance-issue-20533.stderr
+++ b/tests/ui/variance/variance-issue-20533.stderr
@@ -9,6 +9,11 @@ LL |         drop(a);
    |              ^ move out of `a` occurs here
 LL |         drop(x);
    |              - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         let x = foo(&a.clone());
+   |                       ++++++++
 
 error[E0505]: cannot move out of `a` because it is borrowed
   --> $DIR/variance-issue-20533.rs:34:14
@@ -21,6 +26,11 @@ LL |         drop(a);
    |              ^ move out of `a` occurs here
 LL |         drop(x);
    |              - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         let x = bar(&a.clone());
+   |                       ++++++++
 
 error[E0505]: cannot move out of `a` because it is borrowed
   --> $DIR/variance-issue-20533.rs:40:14
@@ -33,6 +43,11 @@ LL |         drop(a);
    |              ^ move out of `a` occurs here
 LL |         drop(x);
    |              - borrow later used here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         let x = baz(&a.clone());
+   |                       ++++++++
 
 error: aborting due to 3 previous errors