@@ -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,
@@ -434,19 +431,48 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
434431 let parent = self . infcx . tcx . parent_hir_node ( expr. hir_id ) ;
435432 let ( def_id, args, offset) = if let hir:: Node :: Expr ( parent_expr) = parent
436433 && let hir:: ExprKind :: MethodCall ( _, _, args, _) = parent_expr. kind
437- && let Some ( def_id) = typeck. type_dependent_def_id ( parent_expr. hir_id )
438434 {
439- ( def_id . as_local ( ) , args, 1 )
435+ ( typeck . type_dependent_def_id ( parent_expr . hir_id ) , args, 1 )
440436 } else if let hir:: Node :: Expr ( parent_expr) = parent
441437 && let hir:: ExprKind :: Call ( call, args) = parent_expr. kind
442438 && let ty:: FnDef ( def_id, _) = typeck. node_type ( call. hir_id ) . kind ( )
443439 {
444- ( def_id . as_local ( ) , args, 0 )
440+ ( Some ( * def_id ) , args, 0 )
445441 } else {
446442 ( None , & [ ] [ ..] , 0 )
447443 } ;
444+
445+ // If the moved value is a mut reference, it is used in a
446+ // generic function and it's type is a generic param, it can be
447+ // reborrowed to avoid moving.
448+ // for example:
449+ // struct Y(u32);
450+ // x's type is '& mut Y' and it is used in `fn generic<T>(x: T) {}`.
451+ let is_sugg_reborrow = || {
452+ if let Some ( def_id) = def_id
453+ && let Some ( pos) = args. iter ( ) . position ( |arg| arg. hir_id == expr. hir_id )
454+ && let ty:: Param ( _) =
455+ self . infcx . tcx . fn_sig ( def_id) . skip_binder ( ) . skip_binder ( ) . inputs ( )
456+ [ pos + offset]
457+ . kind ( )
458+ {
459+ let place = & self . move_data . move_paths [ mpi] . place ;
460+ let ty = place. ty ( self . body , self . infcx . tcx ) . ty ;
461+ if let ty:: Ref ( _, _, hir:: Mutability :: Mut ) = ty. kind ( ) {
462+ return true ;
463+ }
464+ }
465+ false
466+ } ;
467+ let suggest_reborrow = is_sugg_reborrow ( ) ;
468+ if suggest_reborrow {
469+ self . suggest_reborrow ( err, expr. span , moved_place) ;
470+ return ;
471+ }
472+
448473 if let Some ( def_id) = def_id
449- && let node = self . infcx . tcx . hir_node_by_def_id ( def_id)
474+ && let Some ( local_def_id) = def_id. as_local ( )
475+ && let node = self . infcx . tcx . hir_node_by_def_id ( local_def_id)
450476 && let Some ( fn_sig) = node. fn_sig ( )
451477 && let Some ( ident) = node. ident ( )
452478 && let Some ( pos) = args. iter ( ) . position ( |arg| arg. hir_id == expr. hir_id )
@@ -463,13 +489,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
463489 Some ( hir:: intravisit:: FnKind :: Closure ) => "closure" ,
464490 } ;
465491 span. push_span_label ( ident. span , format ! ( "in this {descr}" ) ) ;
466- err. span_note (
467- span,
468- format ! (
469- "consider changing this parameter type in {descr} `{ident}` to borrow \
470- instead if owning the value isn't necessary",
471- ) ,
472- ) ;
492+ if !suggest_reborrow {
493+ err. span_note (
494+ span,
495+ format ! (
496+ "consider changing this parameter type in {descr} `{ident}` to borrow \
497+ instead if owning the value isn't necessary",
498+ ) ,
499+ ) ;
500+ }
473501 }
474502 let place = & self . move_data . move_paths [ mpi] . place ;
475503 let ty = place. ty ( self . body , self . infcx . tcx ) . ty ;
@@ -510,6 +538,20 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
510538 }
511539 }
512540
541+ fn suggest_reborrow ( & self , err : & mut Diag < ' infcx > , span : Span , moved_place : PlaceRef < ' tcx > ) {
542+ err. span_suggestion_verbose (
543+ span. shrink_to_lo ( ) ,
544+ format ! (
545+ "consider creating a fresh reborrow of {} here" ,
546+ self . describe_place( moved_place)
547+ . map( |n| format!( "`{n}`" ) )
548+ . unwrap_or_else( || "the mutable reference" . to_string( ) ) ,
549+ ) ,
550+ "&mut *" ,
551+ Applicability :: MachineApplicable ,
552+ ) ;
553+ }
554+
513555 fn report_use_of_uninitialized (
514556 & self ,
515557 mpi : MovePathIndex ,
0 commit comments