Skip to content

Commit 87c8e79

Browse files
authored
Unrolled build for #127579
Rollup merge of #127579 - surechen:fix_127285, r=lcnr Solve a error `.clone()` suggestion when moving a mutable reference If the moved value is a mut reference, it is used in a generic function and it's type is a generic param, suggest it can be reborrowed to avoid moving. for example: ```rust struct Y(u32); // x's type is '& mut Y' and it is used in `fn generic<T>(x: T) {}`. fn generic<T>(x: T) {} ``` fixes #127285
2 parents fcc325f + 4821b84 commit 87c8e79

7 files changed

+128
-41
lines changed

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+60-16
Original file line numberDiff line numberDiff line change
@@ -205,16 +205,25 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
205205
is_loop_move = true;
206206
}
207207

208+
let mut has_suggest_reborrow = false;
208209
if !seen_spans.contains(&move_span) {
209210
if !closure {
210-
self.suggest_ref_or_clone(mpi, &mut err, &mut in_pattern, move_spans);
211+
self.suggest_ref_or_clone(
212+
mpi,
213+
&mut err,
214+
&mut in_pattern,
215+
move_spans,
216+
moved_place.as_ref(),
217+
&mut has_suggest_reborrow,
218+
);
211219
}
212220

213221
let msg_opt = CapturedMessageOpt {
214222
is_partial_move,
215223
is_loop_message,
216224
is_move_msg,
217225
is_loop_move,
226+
has_suggest_reborrow,
218227
maybe_reinitialized_locations_is_empty: maybe_reinitialized_locations
219228
.is_empty(),
220229
};
@@ -259,17 +268,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
259268
if is_loop_move & !in_pattern && !matches!(use_spans, UseSpans::ClosureUse { .. }) {
260269
if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
261270
// We have a `&mut` ref, we need to reborrow on each iteration (#62112).
262-
err.span_suggestion_verbose(
263-
span.shrink_to_lo(),
264-
format!(
265-
"consider creating a fresh reborrow of {} here",
266-
self.describe_place(moved_place)
267-
.map(|n| format!("`{n}`"))
268-
.unwrap_or_else(|| "the mutable reference".to_string()),
269-
),
270-
"&mut *",
271-
Applicability::MachineApplicable,
272-
);
271+
self.suggest_reborrow(&mut err, span, moved_place);
273272
}
274273
}
275274

@@ -346,6 +345,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
346345
err: &mut Diag<'infcx>,
347346
in_pattern: &mut bool,
348347
move_spans: UseSpans<'tcx>,
348+
moved_place: PlaceRef<'tcx>,
349+
has_suggest_reborrow: &mut bool,
349350
) {
350351
let move_span = match move_spans {
351352
UseSpans::ClosureUse { capture_kind_span, .. } => capture_kind_span,
@@ -435,20 +436,44 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
435436
let parent = self.infcx.tcx.parent_hir_node(expr.hir_id);
436437
let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent
437438
&& let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind
438-
&& let Some(def_id) = typeck.type_dependent_def_id(parent_expr.hir_id)
439439
{
440-
(def_id.as_local(), args, 1)
440+
(typeck.type_dependent_def_id(parent_expr.hir_id), args, 1)
441441
} else if let hir::Node::Expr(parent_expr) = parent
442442
&& let hir::ExprKind::Call(call, args) = parent_expr.kind
443443
&& let ty::FnDef(def_id, _) = typeck.node_type(call.hir_id).kind()
444444
{
445-
(def_id.as_local(), args, 0)
445+
(Some(*def_id), args, 0)
446446
} else {
447447
(None, &[][..], 0)
448448
};
449+
450+
// If the moved value is a mut reference, it is used in a
451+
// generic function and it's type is a generic param, it can be
452+
// reborrowed to avoid moving.
453+
// for example:
454+
// struct Y(u32);
455+
// x's type is '& mut Y' and it is used in `fn generic<T>(x: T) {}`.
456+
if let Some(def_id) = def_id
457+
&& self.infcx.tcx.def_kind(def_id).is_fn_like()
458+
&& let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id)
459+
&& let ty::Param(_) =
460+
self.infcx.tcx.fn_sig(def_id).skip_binder().skip_binder().inputs()
461+
[pos + offset]
462+
.kind()
463+
{
464+
let place = &self.move_data.move_paths[mpi].place;
465+
let ty = place.ty(self.body, self.infcx.tcx).ty;
466+
if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
467+
*has_suggest_reborrow = true;
468+
self.suggest_reborrow(err, expr.span, moved_place);
469+
return;
470+
}
471+
}
472+
449473
let mut can_suggest_clone = true;
450474
if let Some(def_id) = def_id
451-
&& let node = self.infcx.tcx.hir_node_by_def_id(def_id)
475+
&& let Some(local_def_id) = def_id.as_local()
476+
&& let node = self.infcx.tcx.hir_node_by_def_id(local_def_id)
452477
&& let Some(fn_sig) = node.fn_sig()
453478
&& let Some(ident) = node.ident()
454479
&& let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id)
@@ -622,6 +647,25 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
622647
}
623648
}
624649

650+
pub fn suggest_reborrow(
651+
&self,
652+
err: &mut Diag<'infcx>,
653+
span: Span,
654+
moved_place: PlaceRef<'tcx>,
655+
) {
656+
err.span_suggestion_verbose(
657+
span.shrink_to_lo(),
658+
format!(
659+
"consider creating a fresh reborrow of {} here",
660+
self.describe_place(moved_place)
661+
.map(|n| format!("`{n}`"))
662+
.unwrap_or_else(|| "the mutable reference".to_string()),
663+
),
664+
"&mut *",
665+
Applicability::MachineApplicable,
666+
);
667+
}
668+
625669
fn report_use_of_uninitialized(
626670
&self,
627671
mpi: MovePathIndex,

compiler/rustc_borrowck/src/diagnostics/mod.rs

+12-13
Original file line numberDiff line numberDiff line change
@@ -768,10 +768,11 @@ struct CapturedMessageOpt {
768768
is_loop_message: bool,
769769
is_move_msg: bool,
770770
is_loop_move: bool,
771+
has_suggest_reborrow: bool,
771772
maybe_reinitialized_locations_is_empty: bool,
772773
}
773774

774-
impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
775+
impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
775776
/// Finds the spans associated to a move or copy of move_place at location.
776777
pub(super) fn move_spans(
777778
&self,
@@ -997,7 +998,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
997998
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
998999
fn explain_captures(
9991000
&mut self,
1000-
err: &mut Diag<'_>,
1001+
err: &mut Diag<'infcx>,
10011002
span: Span,
10021003
move_span: Span,
10031004
move_spans: UseSpans<'tcx>,
@@ -1009,6 +1010,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
10091010
is_loop_message,
10101011
is_move_msg,
10111012
is_loop_move,
1013+
has_suggest_reborrow,
10121014
maybe_reinitialized_locations_is_empty,
10131015
} = msg_opt;
10141016
if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
@@ -1182,18 +1184,15 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
11821184
if let ty::Ref(_, _, hir::Mutability::Mut) =
11831185
moved_place.ty(self.body, self.infcx.tcx).ty.kind()
11841186
{
1185-
// If we are in a loop this will be suggested later.
1186-
if !is_loop_move {
1187-
err.span_suggestion_verbose(
1187+
// Suggest `reborrow` in other place for following situations:
1188+
// 1. If we are in a loop this will be suggested later.
1189+
// 2. If the moved value is a mut reference, it is used in a
1190+
// generic function and the corresponding arg's type is generic param.
1191+
if !is_loop_move && !has_suggest_reborrow {
1192+
self.suggest_reborrow(
1193+
err,
11881194
move_span.shrink_to_lo(),
1189-
format!(
1190-
"consider creating a fresh reborrow of {} here",
1191-
self.describe_place(moved_place.as_ref())
1192-
.map(|n| format!("`{n}`"))
1193-
.unwrap_or_else(|| "the mutable reference".to_string()),
1194-
),
1195-
"&mut *",
1196-
Applicability::MachineApplicable,
1195+
moved_place.as_ref(),
11971196
);
11981197
}
11991198
}

compiler/rustc_borrowck/src/diagnostics/move_errors.rs

+1
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
554554
is_loop_message: false,
555555
is_move_msg: false,
556556
is_loop_move: false,
557+
has_suggest_reborrow: false,
557558
maybe_reinitialized_locations_is_empty: true,
558559
};
559560
if let Some(use_spans) = use_spans {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//@ run-rustfix
2+
3+
#![allow(dead_code)]
4+
5+
struct X(u32);
6+
7+
impl X {
8+
fn f(&mut self) {
9+
generic(&mut *self);
10+
self.0 += 1;
11+
//~^ ERROR: use of moved value: `self` [E0382]
12+
}
13+
}
14+
15+
fn generic<T>(_x: T) {}
16+
17+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//@ run-rustfix
2+
3+
#![allow(dead_code)]
4+
5+
struct X(u32);
6+
7+
impl X {
8+
fn f(&mut self) {
9+
generic(self);
10+
self.0 += 1;
11+
//~^ ERROR: use of moved value: `self` [E0382]
12+
}
13+
}
14+
15+
fn generic<T>(_x: T) {}
16+
17+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error[E0382]: use of moved value: `self`
2+
--> $DIR/moved-value-suggest-reborrow-issue-127285.rs:10:9
3+
|
4+
LL | fn f(&mut self) {
5+
| --------- move occurs because `self` has type `&mut X`, which does not implement the `Copy` trait
6+
LL | generic(self);
7+
| ---- value moved here
8+
LL | self.0 += 1;
9+
| ^^^^^^^^^^^ value used here after move
10+
|
11+
help: consider creating a fresh reborrow of `self` here
12+
|
13+
LL | generic(&mut *self);
14+
| ++++++
15+
16+
error: aborting due to 1 previous error
17+
18+
For more information about this error, try `rustc --explain E0382`.

tests/ui/borrowck/mut-borrow-in-loop-2.stderr

+3-12
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,10 @@ LL | for _ in 0..3 {
88
LL | Other::handle(value);
99
| ^^^^^ value moved here, in previous iteration of loop
1010
|
11-
note: consider changing this parameter type in function `handle` to borrow instead if owning the value isn't necessary
12-
--> $DIR/mut-borrow-in-loop-2.rs:8:22
13-
|
14-
LL | fn handle(value: T) -> Self;
15-
| ------ ^ this parameter takes ownership of the value
16-
| |
17-
| in this function
18-
help: consider moving the expression out of the loop so it is only moved once
19-
|
20-
LL ~ let mut value = Other::handle(value);
21-
LL ~ for _ in 0..3 {
22-
LL ~ value;
11+
help: consider creating a fresh reborrow of `value` here
2312
|
13+
LL | Other::handle(&mut *value);
14+
| ++++++
2415
help: consider creating a fresh reborrow of `value` here
2516
|
2617
LL | Other::handle(&mut *value);

0 commit comments

Comments
 (0)