Suggest .clone() when moved while borrowed

This commit is contained in:
Esteban Küber 2024-03-13 01:51:08 +00:00
parent ccae456863
commit fa2fc3ab96
29 changed files with 246 additions and 19 deletions

View file

@ -987,6 +987,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
can_suggest_clone 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> { pub(crate) fn clone_on_reference(&self, expr: &hir::Expr<'_>) -> Option<Span> {
let typeck_results = self.infcx.tcx.typeck(self.mir_def_id()); let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
if let hir::ExprKind::MethodCall(segment, rcvr, args, span) = expr.kind 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; let tcx = self.infcx.tcx;
// Try to find predicates on *generic params* that would allow copying `ty` // Try to find predicates on *generic params* that would allow copying `ty`
let suggestion = let suggestion =
@ -1136,6 +1159,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
None, None,
); );
self.suggest_copy_for_type_in_cloned_ref(&mut err, place); 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); self.buffer_error(err);
} }
@ -1553,22 +1582,32 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
} }
} }
for ty in types_to_constrain { for ty in types_to_constrain {
self.suggest_adding_bounds(err, ty, clone, body.span); self.suggest_adding_bounds_or_derive(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( pub(crate) fn suggest_adding_bounds_or_derive(
self.infcx.tcx, &self,
ObligationCause::dummy(), err: &mut Diag<'_>,
self.param_env, ty: Ty<'tcx>,
trait_ref, def_id: DefId,
); span: Span,
self.infcx.err_ctxt().suggest_derive( ) {
&obligation, self.suggest_adding_bounds(err, ty, def_id, span);
err, if let ty::Adt(..) = ty.kind() {
trait_ref.to_predicate(self.infcx.tcx), // 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),
);
} }
} }

View file

@ -10,6 +10,11 @@ LL | drop(x);
| ^ move out of `x` occurs here | ^ move out of `x` occurs here
LL | return f(y); LL | return f(y);
| - borrow later used here | - 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 error: aborting due to 1 previous error

View file

@ -51,6 +51,11 @@ LL | x
... ...
LL | use_mut(n); use_imm(m); LL | use_mut(n); use_imm(m);
| - borrow later used here | - 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 error[E0505]: cannot move out of `y` because it is borrowed
--> $DIR/binop-move-semantics.rs:23:5 --> $DIR/binop-move-semantics.rs:23:5

View file

@ -10,6 +10,11 @@ LL | let y = x;
LL | LL |
LL | r.use_ref(); LL | r.use_ref();
| - borrow later used here | - 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 error[E0502]: cannot borrow `x.0` as mutable because it is also borrowed as immutable
--> $DIR/borrow-tuple-fields.rs:18:13 --> $DIR/borrow-tuple-fields.rs:18:13
@ -42,6 +47,11 @@ LL | let y = x;
| ^ move out of `x` occurs here | ^ move out of `x` occurs here
LL | r.use_ref(); LL | r.use_ref();
| - borrow later used here | - 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 error[E0502]: cannot borrow `x.0` as mutable because it is also borrowed as immutable
--> $DIR/borrow-tuple-fields.rs:33:13 --> $DIR/borrow-tuple-fields.rs:33:13

View file

@ -10,6 +10,11 @@ LL | &*a,
| --- borrow of `*a` occurs here | --- borrow of `*a` occurs here
LL | a); LL | a);
| ^ move out of `a` occurs here | ^ 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 error[E0505]: cannot move out of `a` because it is borrowed
--> $DIR/borrowck-bad-nested-calls-move.rs:32:9 --> $DIR/borrowck-bad-nested-calls-move.rs:32:9
@ -22,6 +27,11 @@ LL | &*a,
| --- borrow of `*a` occurs here | --- borrow of `*a` occurs here
LL | a); LL | a);
| ^ move out of `a` occurs here | ^ 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 error: aborting due to 2 previous errors

View file

@ -49,6 +49,11 @@ LL | drop(x.b);
| ^^^ move out of `x.b` occurs here | ^^^ move out of `x.b` occurs here
LL | drop(**p); LL | drop(**p);
| --- borrow later used here | --- 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 error[E0505]: cannot move out of `x.b` because it is borrowed
--> $DIR/borrowck-field-sensitivity.rs:41:14 --> $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 | ^^^^^^^^^^^^^^^^ move out of `x.b` occurs here
LL | drop(**p); LL | drop(**p);
| --- borrow later used here | --- 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 error[E0499]: cannot borrow `x.a` as mutable more than once at a time
--> $DIR/borrowck-field-sensitivity.rs:48:13 --> $DIR/borrowck-field-sensitivity.rs:48:13

View file

@ -13,6 +13,11 @@ LL | println!("v={}", *v);
LL | }); LL | });
LL | w.use_ref(); LL | w.use_ref();
| - borrow later used here | - 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 error[E0505]: cannot move out of `v` because it is borrowed
--> $DIR/borrowck-loan-blocks-move-cc.rs:24:19 --> $DIR/borrowck-loan-blocks-move-cc.rs:24:19
@ -29,6 +34,11 @@ LL | println!("v={}", *v);
LL | }); LL | });
LL | w.use_ref(); LL | w.use_ref();
| - borrow later used here | - 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 error: aborting due to 2 previous errors

View file

@ -9,6 +9,11 @@ LL | take(v);
| ^ move out of `v` occurs here | ^ move out of `v` occurs here
LL | w.use_ref(); LL | w.use_ref();
| - borrow later used here | - 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 error: aborting due to 1 previous error

View file

@ -10,6 +10,11 @@ LL | let z = *a;
| ^^ move out of `*a` occurs here | ^^ move out of `*a` occurs here
LL | b.use_ref(); LL | b.use_ref();
| - borrow later used here | - 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 error: aborting due to 1 previous error

View file

@ -10,6 +10,11 @@ LL | let t1 = t0;
LL | *t1 = 22; LL | *t1 = 22;
LL | p.use_ref(); LL | p.use_ref();
| - borrow later used here | - 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 error: aborting due to 1 previous error

View file

@ -9,6 +9,11 @@ LL | let S { x: ax } = a;
| ^^ move out of `a.x` occurs here | ^^ move out of `a.x` occurs here
LL | f(pb); LL | f(pb);
| -- borrow later used here | -- 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 error: aborting due to 1 previous error

View file

@ -14,6 +14,11 @@ LL | drop(x1);
... ...
LL | borrow(&*p1); LL | borrow(&*p1);
| ---- borrow later used here | ---- 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 error[E0505]: cannot move out of `x2` because it is borrowed
--> $DIR/borrowck-multiple-captures.rs:12:19 --> $DIR/borrowck-multiple-captures.rs:12:19
@ -30,6 +35,11 @@ LL | drop(x2);
... ...
LL | borrow(&*p2); LL | borrow(&*p2);
| ---- borrow later used here | ---- 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` error[E0382]: use of moved value: `x1`
--> $DIR/borrowck-multiple-captures.rs:27:19 --> $DIR/borrowck-multiple-captures.rs:27:19
@ -93,6 +103,11 @@ LL | drop(x);
... ...
LL | borrow(&*p); LL | borrow(&*p);
| --- borrow later used here | --- 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` error[E0382]: use of moved value: `x`
--> $DIR/borrowck-multiple-captures.rs:52:14 --> $DIR/borrowck-multiple-captures.rs:52:14

View file

@ -9,6 +9,11 @@ LL | free(x);
| ^ move out of `x` occurs here | ^ move out of `x` occurs here
LL | *y LL | *y
| -- borrow later used here | -- 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 error: aborting due to 1 previous error

View file

@ -9,7 +9,7 @@ fn foo<T: Default + Clone>(list: &mut Vec<T>) {
drop(cloned_items); drop(cloned_items);
} }
fn bar<T: std::fmt::Display + Clone>(x: T) { fn bar<T: std::fmt::Display + Clone>(x: T) {
let a = &x; let a = &x.clone();
let b = a.clone(); let b = a.clone();
drop(x); drop(x);
//~^ ERROR cannot move out of `x` because it is borrowed //~^ 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)] #[derive(Clone)]
struct A; struct A;
fn qux(x: A) { fn qux(x: A) {
let a = &x; let a = &x.clone();
let b = a.clone(); let b = a.clone();
drop(x); drop(x);
//~^ ERROR cannot move out of `x` because it is borrowed //~^ ERROR cannot move out of `x` because it is borrowed

View file

@ -36,6 +36,10 @@ help: consider further restricting this bound
| |
LL | fn bar<T: std::fmt::Display + Clone>(x: T) { 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 error[E0505]: cannot move out of `x` because it is borrowed
--> $DIR/clone-on-ref.rs:23:10 --> $DIR/clone-on-ref.rs:23:10
@ -57,6 +61,10 @@ help: consider annotating `A` with `#[derive(Clone)]`
LL + #[derive(Clone)] LL + #[derive(Clone)]
LL | struct A; 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 error: aborting due to 3 previous errors

View file

@ -9,6 +9,11 @@ LL | drop(s);
| ^ move out of `s` occurs here | ^ move out of `s` occurs here
LL | } LL | }
| - borrow might be used here, when `_map` is dropped and runs the `Drop` code for type `BTreeMap` | - 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 error: aborting due to 1 previous error

View file

@ -9,6 +9,11 @@ LL | drop(a);
| ^ move out of `a` occurs here | ^ move out of `a` occurs here
LL | for s in &b { LL | for s in &b {
| -- borrow later used here | -- 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 error: aborting due to 1 previous error

View file

@ -13,6 +13,11 @@ LL | println!("child function: {}", fancy_num.num);
... ...
LL | println!("main function: {}", fancy_ref.num); LL | println!("main function: {}", fancy_ref.num);
| ------------- borrow later used here | ------------- 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 error: aborting due to 1 previous error

View file

@ -10,6 +10,11 @@ LL | eat(x);
| ^ move out of `x` occurs here | ^ move out of `x` occurs here
LL | _ref_to_val.use_ref(); LL | _ref_to_val.use_ref();
| ----------- borrow later used here | ----------- 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 error: aborting due to 1 previous error

View file

@ -10,6 +10,11 @@ LL | drop(x);
LL | LL |
LL | println!("{}", y); LL | println!("{}", y);
| - borrow later used here | - 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 error: aborting due to 1 previous error

View file

@ -27,6 +27,11 @@ LL | drop(x);
| ^ move out of `x` occurs here | ^ move out of `x` occurs here
LL | println!("{}", y); LL | println!("{}", y);
| - borrow later used here | - 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 error: aborting due to 2 previous errors

View file

@ -10,6 +10,11 @@ LL | drop(x);
LL | LL |
LL | println!("{}", y); LL | println!("{}", y);
| - borrow later used here | - 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 error: aborting due to 1 previous error

View file

@ -57,6 +57,11 @@ LL | || x;
| move out of `x` occurs here | move out of `x` occurs here
LL | r.use_ref(); LL | r.use_ref();
| - borrow later used here | - 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` error[E0382]: borrow of moved value: `x`
--> $DIR/closure-access-spans.rs:35:5 --> $DIR/closure-access-spans.rs:35:5

View file

@ -10,6 +10,11 @@ LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
LL | _x1 = U; LL | _x1 = U;
LL | drop(hold_all); LL | drop(hold_all);
| -------- borrow later used here | -------- 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` error[E0384]: cannot assign twice to immutable variable `_x1`
--> $DIR/borrowck-move-ref-pattern.rs:9:5 --> $DIR/borrowck-move-ref-pattern.rs:9:5

View file

@ -57,6 +57,11 @@ LL | f(Box::new(|a| {
LL | LL |
LL | foo(f); LL | foo(f);
| - move occurs due to use in closure | - 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 error: aborting due to 5 previous errors

View file

@ -11,6 +11,11 @@ LL | drop(y);
... ...
LL | *lock.lock().unwrap() = &z; LL | *lock.lock().unwrap() = &z;
| ---- borrow later used here | ---- 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 error[E0597]: `z` does not live long enough
--> $DIR/send-is-not-static-std-sync.rs:16:33 --> $DIR/send-is-not-static-std-sync.rs:16:33
@ -38,6 +43,11 @@ LL | drop(y);
... ...
LL | *lock.write().unwrap() = &z; LL | *lock.write().unwrap() = &z;
| ---- borrow later used here | ---- 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 error[E0597]: `z` does not live long enough
--> $DIR/send-is-not-static-std-sync.rs:30:34 --> $DIR/send-is-not-static-std-sync.rs:30:34
@ -65,6 +75,11 @@ LL | drop(y);
... ...
LL | tx.send(&z).unwrap(); LL | tx.send(&z).unwrap();
| -- borrow later used here | -- 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 error[E0597]: `z` does not live long enough
--> $DIR/send-is-not-static-std-sync.rs:46:17 --> $DIR/send-is-not-static-std-sync.rs:46:17

View file

@ -7,6 +7,11 @@ LL | for i in &a {
| -- borrow of `a` occurs here | -- borrow of `a` occurs here
LL | for j in a { LL | for j in a {
| ^ move out of `a` occurs here | ^ 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` error[E0382]: use of moved value: `a`
--> $DIR/borrow-for-loop-head.rs:4:18 --> $DIR/borrow-for-loop-head.rs:4:18

View file

@ -33,6 +33,11 @@ LL | !x;
... ...
LL | use_mut(n); use_imm(m); LL | use_mut(n); use_imm(m);
| - borrow later used here | - 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 error[E0505]: cannot move out of `y` because it is borrowed
--> $DIR/unop-move-semantics.rs:17:6 --> $DIR/unop-move-semantics.rs:17:6

View file

@ -9,6 +9,11 @@ LL | drop(a);
| ^ move out of `a` occurs here | ^ move out of `a` occurs here
LL | drop(x); LL | drop(x);
| - borrow later used here | - 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 error[E0505]: cannot move out of `a` because it is borrowed
--> $DIR/variance-issue-20533.rs:34:14 --> $DIR/variance-issue-20533.rs:34:14
@ -21,6 +26,11 @@ LL | drop(a);
| ^ move out of `a` occurs here | ^ move out of `a` occurs here
LL | drop(x); LL | drop(x);
| - borrow later used here | - 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 error[E0505]: cannot move out of `a` because it is borrowed
--> $DIR/variance-issue-20533.rs:40:14 --> $DIR/variance-issue-20533.rs:40:14
@ -33,6 +43,11 @@ LL | drop(a);
| ^ move out of `a` occurs here | ^ move out of `a` occurs here
LL | drop(x); LL | drop(x);
| - borrow later used here | - 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 error: aborting due to 3 previous errors