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