Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit eb11798

Browse files
committedJul 11, 2024·
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 d819876 commit eb11798

File tree

4 files changed

+109
-12
lines changed

4 files changed

+109
-12
lines changed
 

‎compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+50-12
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
206206

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

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

@@ -345,6 +341,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
345341
err: &mut Diag<'infcx>,
346342
in_pattern: &mut bool,
347343
move_spans: UseSpans<'tcx>,
344+
moved_place: PlaceRef<'tcx>,
348345
) {
349346
let move_span = match move_spans {
350347
UseSpans::ClosureUse { capture_kind_span, .. } => capture_kind_span,
@@ -445,13 +442,36 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
445442
} else {
446443
(None, &[][..], 0)
447444
};
445+
let mut reborrow = false;
448446
if let Some(def_id) = def_id
449447
&& let node = self.infcx.tcx.hir_node_by_def_id(def_id)
450448
&& let Some(fn_sig) = node.fn_sig()
451449
&& let Some(ident) = node.ident()
452450
&& let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id)
453451
&& let Some(arg) = fn_sig.decl.inputs.get(pos + offset)
454452
{
453+
// If the moved value is a mut reference, it is used in a
454+
// generic function and it's type is a generic param, it can be
455+
// reborrowed to avoid moving.
456+
// for example:
457+
// struct Y(u32);
458+
// x's type is '& mut Y' and it is used in `fn generic<T>(x: T) {}`.
459+
let is_sugg_reborrow = || {
460+
if let Some((def_id, _)) = arg.as_generic_param()
461+
&& let Some(generics) = node.generics()
462+
&& let Some(def_id) = def_id.as_local()
463+
&& generics.params.iter().any(|param| param.def_id == def_id)
464+
{
465+
let place = &self.move_data.move_paths[mpi].place;
466+
let ty = place.ty(self.body, self.infcx.tcx).ty;
467+
if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
468+
return true;
469+
}
470+
}
471+
false
472+
};
473+
reborrow = is_sugg_reborrow();
474+
455475
let mut span: MultiSpan = arg.span.into();
456476
span.push_span_label(
457477
arg.span,
@@ -473,6 +493,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
473493
}
474494
let place = &self.move_data.move_paths[mpi].place;
475495
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+
}
476500
if let hir::Node::Expr(parent_expr) = parent
477501
&& let hir::ExprKind::Call(call_expr, _) = parent_expr.kind
478502
&& let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IntoIterIntoIter, _)) =
@@ -510,6 +534,20 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
510534
}
511535
}
512536

537+
fn suggest_reborrow(&self, err: &mut Diag<'infcx>, 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+
513551
fn report_use_of_uninitialized(
514552
&self,
515553
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)
Please sign in to comment.