Skip to content

Commit d5d3e30

Browse files
committed
fix #104232, suggest clone for Arc/Rc
1 parent 9cdfe03 commit d5d3e30

File tree

6 files changed

+145
-7
lines changed

6 files changed

+145
-7
lines changed

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
130130
let partial_str = if is_partial_move { "partial " } else { "" };
131131
let partially_str = if is_partial_move { "partially " } else { "" };
132132

133+
let mpi = self.move_data.moves[move_out_indices[0]].path;
134+
let place = &self.move_data.move_paths[mpi].place;
135+
let ty = place.ty(self.body, self.infcx.tcx).ty;
136+
133137
let mut err = self.cannot_act_on_moved_value(
134138
span,
135139
desired_action.as_noun(),
@@ -186,6 +190,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
186190
} else {
187191
""
188192
};
193+
let suggest_clone = self.suggest_using_clone(ty) && !move_spans.for_closure();
189194

190195
if location == move_out.source {
191196
is_loop_move = true;
@@ -202,6 +207,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
202207
move_msg,
203208
is_loop_move,
204209
maybe_reinitialized_locations.is_empty(),
210+
suggest_clone,
205211
);
206212

207213
if let (UseSpans::PatUse(span), []) =
@@ -237,8 +243,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
237243
);
238244
}
239245

240-
let ty = used_place.ty(self.body, self.infcx.tcx).ty;
241-
let needs_note = match ty.kind() {
246+
let used_ty = used_place.ty(self.body, self.infcx.tcx).ty;
247+
let needs_note = match used_ty.kind() {
242248
ty::Closure(id, _) => {
243249
let tables = self.infcx.tcx.typeck(id.expect_local());
244250
let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(id.expect_local());
@@ -248,10 +254,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
248254
_ => true,
249255
};
250256

251-
let mpi = self.move_data.moves[move_out_indices[0]].path;
252-
let place = &self.move_data.move_paths[mpi].place;
253-
let ty = place.ty(self.body, self.infcx.tcx).ty;
254-
255257
// If we're in pattern, we do nothing in favor of the previous suggestion (#80913).
256258
// Same for if we're in a loop, see #101119.
257259
if is_loop_move & !in_pattern && !matches!(use_spans, UseSpans::ClosureUse { .. }) {

compiler/rustc_borrowck/src/diagnostics/mod.rs

+19
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
301301
}
302302
}
303303

304+
/// We only suggest clone for `std::sync::Arc` and `std::rc::Rc` types.
305+
fn suggest_using_clone(&self, ty: Ty<'tcx>) -> bool {
306+
if let ty::Adt(adt, _) = ty.kind() &&
307+
(self.infcx.tcx.is_diagnostic_item(sym::Arc, adt.did()) ||
308+
self.infcx.tcx.is_diagnostic_item(sym::Rc, adt.did())) {
309+
return true;
310+
}
311+
false
312+
}
313+
304314
/// End-user visible description of the `field`nth field of `base`
305315
fn describe_field(
306316
&self,
@@ -1029,6 +1039,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
10291039
move_msg: &str,
10301040
is_loop_move: bool,
10311041
maybe_reinitialized_locations_is_empty: bool,
1042+
suggest_clone: bool,
10321043
) {
10331044
if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
10341045
let place_name = self
@@ -1166,6 +1177,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
11661177
move_span,
11671178
format!("value {}moved{} here{}", partially_str, move_msg, loop_message),
11681179
);
1180+
if suggest_clone {
1181+
err.span_suggestion_verbose(
1182+
move_span.shrink_to_hi(),
1183+
"consider cloning here",
1184+
".clone()",
1185+
Applicability::MaybeIncorrect,
1186+
);
1187+
}
11691188
}
11701189
// If the move error occurs due to a loop, don't show
11711190
// another message for the same span

compiler/rustc_borrowck/src/diagnostics/move_errors.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
401401
};
402402
if let Some(use_spans) = use_spans {
403403
self.explain_captures(
404-
&mut err, span, span, use_spans, move_place, "", "", "", false, true,
404+
&mut err, span, span, use_spans, move_place, "", "", "", false, true, false,
405405
);
406406
}
407407
err
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
use std::sync::Arc;
2+
use std::rc::Rc;
3+
4+
fn foo1(_: Arc<usize>) {}
5+
fn bar1(_: Arc<usize>) {}
6+
fn test_arc() {
7+
let x = Arc::new(1);
8+
foo1(x);
9+
foo1(x); //~ ERROR use of moved value
10+
bar1(x); //~ ERROR use of moved value
11+
}
12+
13+
fn foo2(_: Rc<usize>) {}
14+
fn bar2(_: Rc<usize>) {}
15+
fn test_rc() {
16+
let x = Rc::new(1);
17+
foo2(x);
18+
foo2(x); //~ ERROR use of moved value
19+
bar2(x); //~ ERROR use of moved value
20+
}
21+
22+
fn test_closure() {
23+
let x = Arc::new(1);
24+
for _ in 0..4 {
25+
// Ideally we should suggest `let x = x.clone();` here.
26+
std::thread::spawn(move || { //~ ERROR use of moved value
27+
println!("{}", x);
28+
});
29+
}
30+
}
31+
32+
fn main() {
33+
test_rc();
34+
test_arc();
35+
test_closure();
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
error[E0382]: use of moved value: `x`
2+
--> $DIR/issue-104232-suggest-clone.rs:9:10
3+
|
4+
LL | let x = Arc::new(1);
5+
| - move occurs because `x` has type `Arc<usize>`, which does not implement the `Copy` trait
6+
LL | foo1(x);
7+
| - value moved here
8+
LL | foo1(x);
9+
| ^ value used here after move
10+
|
11+
help: consider cloning here
12+
|
13+
LL | foo1(x.clone());
14+
| ++++++++
15+
16+
error[E0382]: use of moved value: `x`
17+
--> $DIR/issue-104232-suggest-clone.rs:10:10
18+
|
19+
LL | let x = Arc::new(1);
20+
| - move occurs because `x` has type `Arc<usize>`, which does not implement the `Copy` trait
21+
LL | foo1(x);
22+
LL | foo1(x);
23+
| - value moved here
24+
LL | bar1(x);
25+
| ^ value used here after move
26+
|
27+
help: consider cloning here
28+
|
29+
LL | foo1(x.clone());
30+
| ++++++++
31+
32+
error[E0382]: use of moved value: `x`
33+
--> $DIR/issue-104232-suggest-clone.rs:18:10
34+
|
35+
LL | let x = Rc::new(1);
36+
| - move occurs because `x` has type `Rc<usize>`, which does not implement the `Copy` trait
37+
LL | foo2(x);
38+
| - value moved here
39+
LL | foo2(x);
40+
| ^ value used here after move
41+
|
42+
help: consider cloning here
43+
|
44+
LL | foo2(x.clone());
45+
| ++++++++
46+
47+
error[E0382]: use of moved value: `x`
48+
--> $DIR/issue-104232-suggest-clone.rs:19:10
49+
|
50+
LL | let x = Rc::new(1);
51+
| - move occurs because `x` has type `Rc<usize>`, which does not implement the `Copy` trait
52+
LL | foo2(x);
53+
LL | foo2(x);
54+
| - value moved here
55+
LL | bar2(x);
56+
| ^ value used here after move
57+
|
58+
help: consider cloning here
59+
|
60+
LL | foo2(x.clone());
61+
| ++++++++
62+
63+
error[E0382]: use of moved value: `x`
64+
--> $DIR/issue-104232-suggest-clone.rs:26:28
65+
|
66+
LL | let x = Arc::new(1);
67+
| - move occurs because `x` has type `Arc<i32>`, which does not implement the `Copy` trait
68+
...
69+
LL | std::thread::spawn(move || {
70+
| ^^^^^^^ value moved into closure here, in previous iteration of loop
71+
LL | println!("{}", x);
72+
| - use occurs due to use in closure
73+
74+
error: aborting due to 5 previous errors
75+
76+
For more information about this error, try `rustc --explain E0382`.

src/test/ui/moves/use_of_moved_value_clone_suggestions.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ LL | (t, t)
77
| - ^ value used here after move
88
| |
99
| value moved here
10+
|
11+
help: consider cloning here
12+
|
13+
LL | (t.clone(), t)
14+
| ++++++++
1015

1116
error: aborting due to previous error
1217

0 commit comments

Comments
 (0)