Skip to content

Commit 2311ecb

Browse files
committed
Suggest .clone() when moved while borrowed
1 parent 863b638 commit 2311ecb

29 files changed

+246
-19
lines changed

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -977,6 +977,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
977977
can_suggest_clone
978978
}
979979

980+
pub(crate) fn suggest_cloning(
981+
&self,
982+
err: &mut Diag<'_>,
983+
ty: Ty<'tcx>,
984+
expr: &hir::Expr<'_>,
985+
span: Span,
986+
) {
987+
if let Some(clone_trait_def) = self.infcx.tcx.lang_items().clone_trait()
988+
&& self
989+
.infcx
990+
.type_implements_trait(clone_trait_def, [ty], self.param_env)
991+
.must_apply_modulo_regions()
992+
{
993+
self.suggest_cloning_inner(err, ty, expr, span);
994+
}
995+
}
996+
980997
pub(crate) fn clone_on_reference(&self, expr: &hir::Expr<'_>) -> Option<Span> {
981998
let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
982999
if let hir::ExprKind::MethodCall(segment, rcvr, args, span) = expr.kind
@@ -992,7 +1009,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
9921009
}
9931010
}
9941011

995-
fn suggest_cloning(&self, err: &mut Diag<'_>, ty: Ty<'tcx>, expr: &hir::Expr<'_>, span: Span) {
1012+
fn suggest_cloning_inner(
1013+
&self,
1014+
err: &mut Diag<'_>,
1015+
ty: Ty<'tcx>,
1016+
expr: &hir::Expr<'_>,
1017+
span: Span,
1018+
) {
9961019
let tcx = self.infcx.tcx;
9971020
// Try to find predicates on *generic params* that would allow copying `ty`
9981021
let suggestion =
@@ -1126,6 +1149,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
11261149
None,
11271150
);
11281151
self.suggest_copy_for_type_in_cloned_ref(&mut err, place);
1152+
let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
1153+
if let Some(expr) = self.find_expr(borrow_span)
1154+
&& let Some(ty) = typeck_results.node_type_opt(expr.hir_id)
1155+
{
1156+
self.suggest_cloning(&mut err, ty, expr, borrow_span);
1157+
}
11291158
self.buffer_error(err);
11301159
}
11311160

@@ -1543,22 +1572,32 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
15431572
}
15441573
}
15451574
for ty in types_to_constrain {
1546-
self.suggest_adding_bounds(err, ty, clone, body.span);
1547-
if let ty::Adt(..) = ty.kind() {
1548-
// The type doesn't implement Clone.
1549-
let trait_ref = ty::Binder::dummy(ty::TraitRef::new(self.infcx.tcx, clone, [ty]));
1550-
let obligation = Obligation::new(
1551-
self.infcx.tcx,
1552-
ObligationCause::dummy(),
1553-
self.param_env,
1554-
trait_ref,
1555-
);
1556-
self.infcx.err_ctxt().suggest_derive(
1557-
&obligation,
1558-
err,
1559-
trait_ref.to_predicate(self.infcx.tcx),
1560-
);
1561-
}
1575+
self.suggest_adding_bounds_or_derive(err, ty, clone, body.span);
1576+
}
1577+
}
1578+
1579+
pub(crate) fn suggest_adding_bounds_or_derive(
1580+
&self,
1581+
err: &mut Diag<'_>,
1582+
ty: Ty<'tcx>,
1583+
def_id: DefId,
1584+
span: Span,
1585+
) {
1586+
self.suggest_adding_bounds(err, ty, def_id, span);
1587+
if let ty::Adt(..) = ty.kind() {
1588+
// The type doesn't implement DefId.
1589+
let trait_ref = ty::Binder::dummy(ty::TraitRef::new(self.infcx.tcx, def_id, [ty]));
1590+
let obligation = Obligation::new(
1591+
self.infcx.tcx,
1592+
ObligationCause::dummy(),
1593+
self.param_env,
1594+
trait_ref,
1595+
);
1596+
self.infcx.err_ctxt().suggest_derive(
1597+
&obligation,
1598+
err,
1599+
trait_ref.to_predicate(self.infcx.tcx),
1600+
);
15621601
}
15631602
}
15641603

tests/ui/associated-types/associated-types-outlives.stderr

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ LL | drop(x);
1010
| ^ move out of `x` occurs here
1111
LL | return f(y);
1212
| - borrow later used here
13+
|
14+
help: consider cloning the value if the performance cost is acceptable
15+
|
16+
LL | 's: loop { y = denormalise(&x.clone()); break }
17+
| ++++++++
1318

1419
error: aborting due to 1 previous error
1520

tests/ui/binop/binop-move-semantics.stderr

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ LL | x
5151
...
5252
LL | use_mut(n); use_imm(m);
5353
| - borrow later used here
54+
|
55+
help: consider cloning the value if the performance cost is acceptable
56+
|
57+
LL | let m = &x.clone();
58+
| ++++++++
5459

5560
error[E0505]: cannot move out of `y` because it is borrowed
5661
--> $DIR/binop-move-semantics.rs:23:5

tests/ui/borrowck/borrow-tuple-fields.stderr

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ LL | let y = x;
1010
LL |
1111
LL | r.use_ref();
1212
| - borrow later used here
13+
|
14+
help: consider cloning the value if the performance cost is acceptable
15+
|
16+
LL | let r = &x.0.clone();
17+
| ++++++++
1318

1419
error[E0502]: cannot borrow `x.0` as mutable because it is also borrowed as immutable
1520
--> $DIR/borrow-tuple-fields.rs:18:13
@@ -42,6 +47,11 @@ LL | let y = x;
4247
| ^ move out of `x` occurs here
4348
LL | r.use_ref();
4449
| - borrow later used here
50+
|
51+
help: consider cloning the value if the performance cost is acceptable
52+
|
53+
LL | let r = &x.0.clone();
54+
| ++++++++
4555

4656
error[E0502]: cannot borrow `x.0` as mutable because it is also borrowed as immutable
4757
--> $DIR/borrow-tuple-fields.rs:33:13

tests/ui/borrowck/borrowck-bad-nested-calls-move.stderr

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ LL | &*a,
1010
| --- borrow of `*a` occurs here
1111
LL | a);
1212
| ^ move out of `a` occurs here
13+
|
14+
help: consider cloning the value if the performance cost is acceptable
15+
|
16+
LL | &*a.clone(),
17+
| ++++++++
1318

1419
error[E0505]: cannot move out of `a` because it is borrowed
1520
--> $DIR/borrowck-bad-nested-calls-move.rs:32:9
@@ -22,6 +27,11 @@ LL | &*a,
2227
| --- borrow of `*a` occurs here
2328
LL | a);
2429
| ^ move out of `a` occurs here
30+
|
31+
help: consider cloning the value if the performance cost is acceptable
32+
|
33+
LL | &*a.clone(),
34+
| ++++++++
2535

2636
error: aborting due to 2 previous errors
2737

tests/ui/borrowck/borrowck-field-sensitivity.stderr

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ LL | drop(x.b);
4949
| ^^^ move out of `x.b` occurs here
5050
LL | drop(**p);
5151
| --- borrow later used here
52+
|
53+
help: consider cloning the value if the performance cost is acceptable
54+
|
55+
LL | let p = &x.b.clone();
56+
| ++++++++
5257

5358
error[E0505]: cannot move out of `x.b` because it is borrowed
5459
--> $DIR/borrowck-field-sensitivity.rs:41:14
@@ -61,6 +66,11 @@ LL | let _y = A { a: 3, .. x };
6166
| ^^^^^^^^^^^^^^^^ move out of `x.b` occurs here
6267
LL | drop(**p);
6368
| --- borrow later used here
69+
|
70+
help: consider cloning the value if the performance cost is acceptable
71+
|
72+
LL | let p = &x.b.clone();
73+
| ++++++++
6474

6575
error[E0499]: cannot borrow `x.a` as mutable more than once at a time
6676
--> $DIR/borrowck-field-sensitivity.rs:48:13

tests/ui/borrowck/borrowck-loan-blocks-move-cc.stderr

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ LL | println!("v={}", *v);
1313
LL | });
1414
LL | w.use_ref();
1515
| - borrow later used here
16+
|
17+
help: consider cloning the value if the performance cost is acceptable
18+
|
19+
LL | let w = &v.clone();
20+
| ++++++++
1621

1722
error[E0505]: cannot move out of `v` because it is borrowed
1823
--> $DIR/borrowck-loan-blocks-move-cc.rs:24:19
@@ -29,6 +34,11 @@ LL | println!("v={}", *v);
2934
LL | });
3035
LL | w.use_ref();
3136
| - borrow later used here
37+
|
38+
help: consider cloning the value if the performance cost is acceptable
39+
|
40+
LL | let w = &v.clone();
41+
| ++++++++
3242

3343
error: aborting due to 2 previous errors
3444

tests/ui/borrowck/borrowck-loan-blocks-move.stderr

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ LL | take(v);
99
| ^ move out of `v` occurs here
1010
LL | w.use_ref();
1111
| - borrow later used here
12+
|
13+
help: consider cloning the value if the performance cost is acceptable
14+
|
15+
LL | let w = &v.clone();
16+
| ++++++++
1217

1318
error: aborting due to 1 previous error
1419

tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ LL | let z = *a;
1010
| ^^ move out of `*a` occurs here
1111
LL | b.use_ref();
1212
| - borrow later used here
13+
|
14+
help: consider cloning the value if the performance cost is acceptable
15+
|
16+
LL | let b = &a.clone();
17+
| ++++++++
1318

1419
error: aborting due to 1 previous error
1520

tests/ui/borrowck/borrowck-move-mut-base-ptr.stderr

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ LL | let t1 = t0;
1010
LL | *t1 = 22;
1111
LL | p.use_ref();
1212
| - borrow later used here
13+
|
14+
help: consider cloning the value if the performance cost is acceptable
15+
|
16+
LL | let p: &isize = &*t0.clone(); // Freezes `*t0`
17+
| ++++++++
1318

1419
error: aborting due to 1 previous error
1520

0 commit comments

Comments
 (0)