@@ -205,7 +205,13 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
205
205
206
206
if !seen_spans. contains ( & move_span) {
207
207
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
+ ) ;
209
215
}
210
216
211
217
let msg_opt = CapturedMessageOpt {
@@ -257,17 +263,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
257
263
if is_loop_move & !in_pattern && !matches ! ( use_spans, UseSpans :: ClosureUse { .. } ) {
258
264
if let ty:: Ref ( _, _, hir:: Mutability :: Mut ) = ty. kind ( ) {
259
265
// 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) ;
271
267
}
272
268
}
273
269
@@ -344,6 +340,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
344
340
err : & mut Diag < ' tcx > ,
345
341
in_pattern : & mut bool ,
346
342
move_spans : UseSpans < ' tcx > ,
343
+ moved_place : PlaceRef < ' tcx > ,
347
344
) {
348
345
let move_span = match move_spans {
349
346
UseSpans :: ClosureUse { capture_kind_span, .. } => capture_kind_span,
@@ -444,13 +441,37 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
444
441
} else {
445
442
( None , & [ ] [ ..] , 0 )
446
443
} ;
444
+ let mut reborrow = false ;
447
445
if let Some ( def_id) = def_id
448
446
&& let node = self . infcx . tcx . hir_node_by_def_id ( def_id)
449
447
&& let Some ( fn_sig) = node. fn_sig ( )
450
448
&& let Some ( ident) = node. ident ( )
451
449
&& let Some ( pos) = args. iter ( ) . position ( |arg| arg. hir_id == expr. hir_id )
452
450
&& let Some ( arg) = fn_sig. decl . inputs . get ( pos + offset)
453
451
{
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
+
454
475
let mut span: MultiSpan = arg. span . into ( ) ;
455
476
span. push_span_label (
456
477
arg. span ,
@@ -472,6 +493,10 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
472
493
}
473
494
let place = & self . move_data . move_paths [ mpi] . place ;
474
495
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
+ }
475
500
if let hir:: Node :: Expr ( parent_expr) = parent
476
501
&& let hir:: ExprKind :: Call ( call_expr, _) = parent_expr. kind
477
502
&& let hir:: ExprKind :: Path ( hir:: QPath :: LangItem ( LangItem :: IntoIterIntoIter , _) ) =
@@ -509,6 +534,20 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
509
534
}
510
535
}
511
536
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
+
512
551
fn report_use_of_uninitialized (
513
552
& self ,
514
553
mpi : MovePathIndex ,
0 commit comments