Skip to content

Commit 61018e6

Browse files
committed
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; | + ```
1 parent 494f6d7 commit 61018e6

File tree

51 files changed

+640
-86
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+640
-86
lines changed

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+42-5
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
347347
mpi: MovePathIndex,
348348
err: &mut Diag<'tcx>,
349349
in_pattern: &mut bool,
350-
move_spans: UseSpans<'_>,
350+
move_spans: UseSpans<'tcx>,
351351
) {
352352
let move_span = match move_spans {
353353
UseSpans::ClosureUse { capture_kind_span, .. } => capture_kind_span,
@@ -491,11 +491,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
491491
..
492492
} = move_spans
493493
{
494-
self.suggest_cloning(err, ty, expr, None);
494+
self.suggest_cloning(err, ty, expr, None, Some(move_spans));
495495
} else if self.suggest_hoisting_call_outside_loop(err, expr) {
496496
// The place where the the type moves would be misleading to suggest clone.
497497
// #121466
498-
self.suggest_cloning(err, ty, expr, None);
498+
self.suggest_cloning(err, ty, expr, None, Some(move_spans));
499499
}
500500
}
501501
if let Some(pat) = finder.pat {
@@ -1146,6 +1146,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
11461146
ty: Ty<'tcx>,
11471147
mut expr: &'cx hir::Expr<'cx>,
11481148
mut other_expr: Option<&'cx hir::Expr<'cx>>,
1149+
use_spans: Option<UseSpans<'tcx>>,
11491150
) {
11501151
if let hir::ExprKind::Struct(_, _, Some(_)) = expr.kind {
11511152
// We have `S { foo: val, ..base }`. In `check_aggregate_rvalue` we have a single
@@ -1258,8 +1259,44 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
12581259
.all(|field| self.implements_clone(field.ty(self.infcx.tcx, args)))
12591260
})
12601261
{
1262+
let ty_span = self.infcx.tcx.def_span(def.did());
1263+
let mut span: MultiSpan = ty_span.into();
1264+
span.push_span_label(ty_span, "consider implementing `Clone` for this type");
1265+
span.push_span_label(expr.span, "you could clone this value");
12611266
err.span_note(
1262-
self.infcx.tcx.def_span(def.did()),
1267+
span,
1268+
format!("if `{ty}` implemented `Clone`, you could clone the value"),
1269+
);
1270+
} else if let ty::Param(param) = ty.kind()
1271+
&& let Some(_clone_trait_def) = self.infcx.tcx.lang_items().clone_trait()
1272+
&& let generics = self.infcx.tcx.generics_of(self.mir_def_id())
1273+
&& let generic_param = generics.type_param(&param, self.infcx.tcx)
1274+
&& let param_span = self.infcx.tcx.def_span(generic_param.def_id)
1275+
&& if let Some(UseSpans::FnSelfUse { kind, .. }) = use_spans
1276+
&& let CallKind::FnCall { fn_trait_id, self_ty } = kind
1277+
&& let ty::Param(_) = self_ty.kind()
1278+
&& ty == self_ty
1279+
&& [
1280+
self.infcx.tcx.lang_items().fn_once_trait(),
1281+
self.infcx.tcx.lang_items().fn_mut_trait(),
1282+
self.infcx.tcx.lang_items().fn_trait(),
1283+
]
1284+
.contains(&Some(fn_trait_id))
1285+
{
1286+
// Do not suggest `F: FnOnce() + Clone`.
1287+
false
1288+
} else {
1289+
true
1290+
}
1291+
{
1292+
let mut span: MultiSpan = param_span.into();
1293+
span.push_span_label(
1294+
param_span,
1295+
"consider constraining this type parameter with `Clone`",
1296+
);
1297+
span.push_span_label(expr.span, "you could clone this value");
1298+
err.span_help(
1299+
span,
12631300
format!("if `{ty}` implemented `Clone`, you could clone the value"),
12641301
);
12651302
}
@@ -1464,7 +1501,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
14641501
if let Some(expr) = self.find_expr(borrow_span)
14651502
&& let Some(ty) = typeck_results.node_type_opt(expr.hir_id)
14661503
{
1467-
self.suggest_cloning(&mut err, ty, expr, self.find_expr(span));
1504+
self.suggest_cloning(&mut err, ty, expr, self.find_expr(span), Some(move_spans));
14681505
}
14691506
self.buffer_error(err);
14701507
}

compiler/rustc_borrowck/src/diagnostics/move_errors.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
447447
};
448448

449449
if let Some(expr) = self.find_expr(span) {
450-
self.suggest_cloning(err, place_ty, expr, self.find_expr(other_span));
450+
self.suggest_cloning(err, place_ty, expr, self.find_expr(other_span), None);
451451
}
452452

453453
err.subdiagnostic(
@@ -482,7 +482,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
482482
};
483483

484484
if let Some(expr) = self.find_expr(use_span) {
485-
self.suggest_cloning(err, place_ty, expr, self.find_expr(span));
485+
self.suggest_cloning(
486+
err,
487+
place_ty,
488+
expr,
489+
self.find_expr(span),
490+
Some(use_spans),
491+
);
486492
}
487493

488494
err.subdiagnostic(
@@ -595,7 +601,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
595601
let place_desc = &format!("`{}`", self.local_names[*local].unwrap());
596602

597603
if let Some(expr) = self.find_expr(binding_span) {
598-
self.suggest_cloning(err, bind_to.ty, expr, None);
604+
self.suggest_cloning(err, bind_to.ty, expr, None, None);
599605
}
600606

601607
err.subdiagnostic(

tests/ui/associated-types/issue-25700.stderr

+4-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ note: if `S<()>` implemented `Clone`, you could clone the value
1212
--> $DIR/issue-25700.rs:1:1
1313
|
1414
LL | struct S<T: 'static>(#[allow(dead_code)] Option<&'static T>);
15-
| ^^^^^^^^^^^^^^^^^^^^
15+
| ^^^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
16+
...
17+
LL | drop(t);
18+
| - you could clone this value
1619

1720
error: aborting due to 1 previous error
1821

tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr

+7
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ LL | fn copy<T: Magic>(x: T) -> (T, T) { (x, x) }
2323
| | value moved here
2424
| move occurs because `x` has type `T`, which does not implement the `Copy` trait
2525
|
26+
help: if `T` implemented `Clone`, you could clone the value
27+
--> $DIR/typeck-auto-trait-no-supertraits-2.rs:8:9
28+
|
29+
LL | fn copy<T: Magic>(x: T) -> (T, T) { (x, x) }
30+
| ^ - you could clone this value
31+
| |
32+
| consider constraining this type parameter with `Clone`
2633
help: consider further restricting this bound
2734
|
2835
LL | fn copy<T: Magic + Copy>(x: T) -> (T, T) { (x, x) }

0 commit comments

Comments
 (0)