@@ -205,16 +205,25 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
205
205
is_loop_move = true ;
206
206
}
207
207
208
+ let mut has_suggest_reborrow = false ;
208
209
if !seen_spans. contains ( & move_span) {
209
210
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
+ ) ;
211
219
}
212
220
213
221
let msg_opt = CapturedMessageOpt {
214
222
is_partial_move,
215
223
is_loop_message,
216
224
is_move_msg,
217
225
is_loop_move,
226
+ has_suggest_reborrow,
218
227
maybe_reinitialized_locations_is_empty : maybe_reinitialized_locations
219
228
. is_empty ( ) ,
220
229
} ;
@@ -259,17 +268,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
259
268
if is_loop_move & !in_pattern && !matches ! ( use_spans, UseSpans :: ClosureUse { .. } ) {
260
269
if let ty:: Ref ( _, _, hir:: Mutability :: Mut ) = ty. kind ( ) {
261
270
// 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) ;
273
272
}
274
273
}
275
274
@@ -346,6 +345,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
346
345
err : & mut Diag < ' infcx > ,
347
346
in_pattern : & mut bool ,
348
347
move_spans : UseSpans < ' tcx > ,
348
+ moved_place : PlaceRef < ' tcx > ,
349
+ has_suggest_reborrow : & mut bool ,
349
350
) {
350
351
let move_span = match move_spans {
351
352
UseSpans :: ClosureUse { capture_kind_span, .. } => capture_kind_span,
@@ -435,20 +436,44 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
435
436
let parent = self . infcx . tcx . parent_hir_node ( expr. hir_id ) ;
436
437
let ( def_id, args, offset) = if let hir:: Node :: Expr ( parent_expr) = parent
437
438
&& let hir:: ExprKind :: MethodCall ( _, _, args, _) = parent_expr. kind
438
- && let Some ( def_id) = typeck. type_dependent_def_id ( parent_expr. hir_id )
439
439
{
440
- ( def_id . as_local ( ) , args, 1 )
440
+ ( typeck . type_dependent_def_id ( parent_expr . hir_id ) , args, 1 )
441
441
} else if let hir:: Node :: Expr ( parent_expr) = parent
442
442
&& let hir:: ExprKind :: Call ( call, args) = parent_expr. kind
443
443
&& let ty:: FnDef ( def_id, _) = typeck. node_type ( call. hir_id ) . kind ( )
444
444
{
445
- ( def_id . as_local ( ) , args, 0 )
445
+ ( Some ( * def_id ) , args, 0 )
446
446
} else {
447
447
( None , & [ ] [ ..] , 0 )
448
448
} ;
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
+
449
473
let mut can_suggest_clone = true ;
450
474
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)
452
477
&& let Some ( fn_sig) = node. fn_sig ( )
453
478
&& let Some ( ident) = node. ident ( )
454
479
&& let Some ( pos) = args. iter ( ) . position ( |arg| arg. hir_id == expr. hir_id )
@@ -622,6 +647,25 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
622
647
}
623
648
}
624
649
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
+
625
669
fn report_use_of_uninitialized (
626
670
& self ,
627
671
mpi : MovePathIndex ,
0 commit comments