@@ -204,16 +204,25 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
204
204
is_loop_move = true ;
205
205
}
206
206
207
+ let mut has_suggest_reborrow = false ;
207
208
if !seen_spans. contains ( & move_span) {
208
209
if !closure {
209
- self . suggest_ref_or_clone ( mpi, & mut err, & mut in_pattern, move_spans) ;
210
+ self . suggest_ref_or_clone (
211
+ mpi,
212
+ & mut err,
213
+ & mut in_pattern,
214
+ move_spans,
215
+ moved_place. as_ref ( ) ,
216
+ & mut has_suggest_reborrow,
217
+ ) ;
210
218
}
211
219
212
220
let msg_opt = CapturedMessageOpt {
213
221
is_partial_move,
214
222
is_loop_message,
215
223
is_move_msg,
216
224
is_loop_move,
225
+ has_suggest_reborrow,
217
226
maybe_reinitialized_locations_is_empty : maybe_reinitialized_locations
218
227
. is_empty ( ) ,
219
228
} ;
@@ -258,17 +267,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
258
267
if is_loop_move & !in_pattern && !matches ! ( use_spans, UseSpans :: ClosureUse { .. } ) {
259
268
if let ty:: Ref ( _, _, hir:: Mutability :: Mut ) = ty. kind ( ) {
260
269
// 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
- ) ;
270
+ self . suggest_reborrow ( & mut err, span, moved_place) ;
272
271
}
273
272
}
274
273
@@ -345,6 +344,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
345
344
err : & mut Diag < ' infcx > ,
346
345
in_pattern : & mut bool ,
347
346
move_spans : UseSpans < ' tcx > ,
347
+ moved_place : PlaceRef < ' tcx > ,
348
+ has_suggest_reborrow : & mut bool ,
348
349
) {
349
350
let move_span = match move_spans {
350
351
UseSpans :: ClosureUse { capture_kind_span, .. } => capture_kind_span,
@@ -434,20 +435,50 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
434
435
let parent = self . infcx . tcx . parent_hir_node ( expr. hir_id ) ;
435
436
let ( def_id, args, offset) = if let hir:: Node :: Expr ( parent_expr) = parent
436
437
&& let hir:: ExprKind :: MethodCall ( _, _, args, _) = parent_expr. kind
437
- && let Some ( def_id) = typeck. type_dependent_def_id ( parent_expr. hir_id )
438
438
{
439
- ( def_id . as_local ( ) , args, 1 )
439
+ ( typeck . type_dependent_def_id ( parent_expr . hir_id ) , args, 1 )
440
440
} else if let hir:: Node :: Expr ( parent_expr) = parent
441
441
&& let hir:: ExprKind :: Call ( call, args) = parent_expr. kind
442
442
&& let ty:: FnDef ( def_id, _) = typeck. node_type ( call. hir_id ) . kind ( )
443
443
{
444
- ( def_id . as_local ( ) , args, 0 )
444
+ ( Some ( * def_id ) , args, 0 )
445
445
} else {
446
446
( None , & [ ] [ ..] , 0 )
447
447
} ;
448
+
449
+ // If the moved value is a mut reference, it is used in a
450
+ // generic function and it's type is a generic param, it can be
451
+ // reborrowed to avoid moving.
452
+ // for example:
453
+ // struct Y(u32);
454
+ // x's type is '& mut Y' and it is used in `fn generic<T>(x: T) {}`.
455
+ let is_sugg_reborrow = || {
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
+ return true ;
468
+ }
469
+ }
470
+ false
471
+ } ;
472
+ * has_suggest_reborrow = is_sugg_reborrow ( ) ;
473
+ if * has_suggest_reborrow {
474
+ self . suggest_reborrow ( err, expr. span , moved_place) ;
475
+ return ;
476
+ }
477
+
448
478
let mut can_suggest_clone = true ;
449
479
if let Some ( def_id) = def_id
450
- && let node = self . infcx . tcx . hir_node_by_def_id ( def_id)
480
+ && let Some ( local_def_id) = def_id. as_local ( )
481
+ && let node = self . infcx . tcx . hir_node_by_def_id ( local_def_id)
451
482
&& let Some ( fn_sig) = node. fn_sig ( )
452
483
&& let Some ( ident) = node. ident ( )
453
484
&& let Some ( pos) = args. iter ( ) . position ( |arg| arg. hir_id == expr. hir_id )
@@ -561,6 +592,25 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
561
592
}
562
593
}
563
594
595
+ pub fn suggest_reborrow (
596
+ & self ,
597
+ err : & mut Diag < ' infcx > ,
598
+ span : Span ,
599
+ moved_place : PlaceRef < ' tcx > ,
600
+ ) {
601
+ err. span_suggestion_verbose (
602
+ span. shrink_to_lo ( ) ,
603
+ format ! (
604
+ "consider creating a fresh reborrow of {} here" ,
605
+ self . describe_place( moved_place)
606
+ . map( |n| format!( "`{n}`" ) )
607
+ . unwrap_or_else( || "the mutable reference" . to_string( ) ) ,
608
+ ) ,
609
+ "&mut *" ,
610
+ Applicability :: MachineApplicable ,
611
+ ) ;
612
+ }
613
+
564
614
fn report_use_of_uninitialized (
565
615
& self ,
566
616
mpi : MovePathIndex ,
0 commit comments