Skip to content

Commit 706ef34

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 a03b4e6 commit 706ef34

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 {
@@ -1085,6 +1085,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
10851085
ty: Ty<'tcx>,
10861086
mut expr: &'cx hir::Expr<'cx>,
10871087
mut other_expr: Option<&'cx hir::Expr<'cx>>,
1088+
use_spans: Option<UseSpans<'tcx>>,
10881089
) {
10891090
if let hir::ExprKind::Struct(_, _, Some(_)) = expr.kind {
10901091
// We have `S { foo: val, ..base }`. In `check_aggregate_rvalue` we have a single
@@ -1197,8 +1198,44 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
11971198
.all(|field| self.implements_clone(field.ty(self.infcx.tcx, args)))
11981199
})
11991200
{
1201+
let ty_span = self.infcx.tcx.def_span(def.did());
1202+
let mut span: MultiSpan = ty_span.into();
1203+
span.push_span_label(ty_span, "consider implementing `Clone` for this type");
1204+
span.push_span_label(expr.span, "you could clone this value");
12001205
err.span_note(
1201-
self.infcx.tcx.def_span(def.did()),
1206+
span,
1207+
format!("if `{ty}` implemented `Clone`, you could clone the value"),
1208+
);
1209+
} else if let ty::Param(param) = ty.kind()
1210+
&& let Some(_clone_trait_def) = self.infcx.tcx.lang_items().clone_trait()
1211+
&& let generics = self.infcx.tcx.generics_of(self.mir_def_id())
1212+
&& let generic_param = generics.type_param(*param, self.infcx.tcx)
1213+
&& let param_span = self.infcx.tcx.def_span(generic_param.def_id)
1214+
&& if let Some(UseSpans::FnSelfUse { kind, .. }) = use_spans
1215+
&& let CallKind::FnCall { fn_trait_id, self_ty } = kind
1216+
&& let ty::Param(_) = self_ty.kind()
1217+
&& ty == self_ty
1218+
&& [
1219+
self.infcx.tcx.lang_items().fn_once_trait(),
1220+
self.infcx.tcx.lang_items().fn_mut_trait(),
1221+
self.infcx.tcx.lang_items().fn_trait(),
1222+
]
1223+
.contains(&Some(fn_trait_id))
1224+
{
1225+
// Do not suggest `F: FnOnce() + Clone`.
1226+
false
1227+
} else {
1228+
true
1229+
}
1230+
{
1231+
let mut span: MultiSpan = param_span.into();
1232+
span.push_span_label(
1233+
param_span,
1234+
"consider constraining this type parameter with `Clone`",
1235+
);
1236+
span.push_span_label(expr.span, "you could clone this value");
1237+
err.span_help(
1238+
span,
12021239
format!("if `{ty}` implemented `Clone`, you could clone the value"),
12031240
);
12041241
}
@@ -1403,7 +1440,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
14031440
if let Some(expr) = self.find_expr(borrow_span)
14041441
&& let Some(ty) = typeck_results.node_type_opt(expr.hir_id)
14051442
{
1406-
self.suggest_cloning(&mut err, ty, expr, self.find_expr(span));
1443+
self.suggest_cloning(&mut err, ty, expr, self.find_expr(span), Some(move_spans));
14071444
}
14081445
self.buffer_error(err);
14091446
}

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)