Skip to content

Commit 7739079

Browse files
committed
If the moved value is a mut reference, it is used in a generic function and it's type is a generic param, 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
1 parent ad12a2a commit 7739079

File tree

4 files changed

+110
-12
lines changed

4 files changed

+110
-12
lines changed

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+51-12
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,13 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
205205

206206
if !seen_spans.contains(&move_span) {
207207
if !closure {
208-
self.suggest_ref_or_clone(mpi, &mut err, &mut in_pattern, move_spans);
208+
self.suggest_ref_or_clone(
209+
mpi,
210+
&mut err,
211+
&mut in_pattern,
212+
move_spans,
213+
moved_place.as_ref(),
214+
);
209215
}
210216

211217
let msg_opt = CapturedMessageOpt {
@@ -257,17 +263,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
257263
if is_loop_move & !in_pattern && !matches!(use_spans, UseSpans::ClosureUse { .. }) {
258264
if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
259265
// We have a `&mut` ref, we need to reborrow on each iteration (#62112).
260-
err.span_suggestion_verbose(
261-
span.shrink_to_lo(),
262-
format!(
263-
"consider creating a fresh reborrow of {} here",
264-
self.describe_place(moved_place)
265-
.map(|n| format!("`{n}`"))
266-
.unwrap_or_else(|| "the mutable reference".to_string()),
267-
),
268-
"&mut *",
269-
Applicability::MachineApplicable,
270-
);
266+
self.suggest_reborrow(&mut err, span, moved_place);
271267
}
272268
}
273269

@@ -344,6 +340,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
344340
err: &mut Diag<'tcx>,
345341
in_pattern: &mut bool,
346342
move_spans: UseSpans<'tcx>,
343+
moved_place: PlaceRef<'tcx>,
347344
) {
348345
let move_span = match move_spans {
349346
UseSpans::ClosureUse { capture_kind_span, .. } => capture_kind_span,
@@ -444,13 +441,37 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
444441
} else {
445442
(None, &[][..], 0)
446443
};
444+
let mut reborrow = false;
447445
if let Some(def_id) = def_id
448446
&& let node = self.infcx.tcx.hir_node_by_def_id(def_id)
449447
&& let Some(fn_sig) = node.fn_sig()
450448
&& let Some(ident) = node.ident()
451449
&& let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id)
452450
&& let Some(arg) = fn_sig.decl.inputs.get(pos + offset)
453451
{
452+
// If the moved value is a mut reference, it is used in a
453+
// generic function and it's type is a generic param, it can be
454+
// reborrowed to avoid moving.
455+
// for example:
456+
// struct Y(u32);
457+
// x's type is '& mut Y' and it is used in `fn generic<T>(x: T) {}`.
458+
let is_sugg_reborrow = || {
459+
if let Some((def_id, _)) = arg.as_generic_param()
460+
&& let Some(generics) = node.generics()
461+
&& let Some(def_id) = def_id.as_local()
462+
{
463+
if generics.params.iter().any(|param| param.def_id == def_id) {
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+
return true;
468+
}
469+
}
470+
}
471+
false
472+
};
473+
reborrow = is_sugg_reborrow();
474+
454475
let mut span: MultiSpan = arg.span.into();
455476
span.push_span_label(
456477
arg.span,
@@ -472,6 +493,10 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
472493
}
473494
let place = &self.move_data.move_paths[mpi].place;
474495
let ty = place.ty(self.body, self.infcx.tcx).ty;
496+
if reborrow {
497+
self.suggest_reborrow(err, expr.span, moved_place);
498+
return;
499+
}
475500
if let hir::Node::Expr(parent_expr) = parent
476501
&& let hir::ExprKind::Call(call_expr, _) = parent_expr.kind
477502
&& let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IntoIterIntoIter, _)) =
@@ -509,6 +534,20 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
509534
}
510535
}
511536

537+
fn suggest_reborrow(&self, err: &mut Diag<'tcx>, span: Span, moved_place: PlaceRef<'tcx>) {
538+
err.span_suggestion_verbose(
539+
span.shrink_to_lo(),
540+
format!(
541+
"consider creating a fresh reborrow of {} here",
542+
self.describe_place(moved_place)
543+
.map(|n| format!("`{n}`"))
544+
.unwrap_or_else(|| "the mutable reference".to_string()),
545+
),
546+
"&mut *",
547+
Applicability::MachineApplicable,
548+
);
549+
}
550+
512551
fn report_use_of_uninitialized(
513552
&self,
514553
mpi: MovePathIndex,
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,25 @@
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+
note: consider changing this parameter type in function `generic` to borrow instead if owning the value isn't necessary
12+
--> $DIR/moved-value-suggest-reborrow-issue-127285.rs:15:19
13+
|
14+
LL | fn generic<T>(_x: T) {}
15+
| ------- ^ this parameter takes ownership of the value
16+
| |
17+
| in this function
18+
help: consider creating a fresh reborrow of `self` here
19+
|
20+
LL | generic(&mut *self);
21+
| ++++++
22+
23+
error: aborting due to 1 previous error
24+
25+
For more information about this error, try `rustc --explain E0382`.

0 commit comments

Comments
 (0)