@@ -205,16 +205,25 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
205205 is_loop_move = true ;
206206 }
207207
208+ let mut has_suggest_reborrow = false ;
208209 if !seen_spans. contains ( & move_span) {
209210 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+ ) ;
211219 }
212220
213221 let msg_opt = CapturedMessageOpt {
214222 is_partial_move,
215223 is_loop_message,
216224 is_move_msg,
217225 is_loop_move,
226+ has_suggest_reborrow,
218227 maybe_reinitialized_locations_is_empty : maybe_reinitialized_locations
219228 . is_empty ( ) ,
220229 } ;
@@ -259,17 +268,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
259268 if is_loop_move & !in_pattern && !matches ! ( use_spans, UseSpans :: ClosureUse { .. } ) {
260269 if let ty:: Ref ( _, _, hir:: Mutability :: Mut ) = ty. kind ( ) {
261270 // 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) ;
273272 }
274273 }
275274
@@ -346,6 +345,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
346345 err : & mut Diag < ' infcx > ,
347346 in_pattern : & mut bool ,
348347 move_spans : UseSpans < ' tcx > ,
348+ moved_place : PlaceRef < ' tcx > ,
349+ has_suggest_reborrow : & mut bool ,
349350 ) {
350351 let move_span = match move_spans {
351352 UseSpans :: ClosureUse { capture_kind_span, .. } => capture_kind_span,
@@ -435,20 +436,44 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
435436 let parent = self . infcx . tcx . parent_hir_node ( expr. hir_id ) ;
436437 let ( def_id, args, offset) = if let hir:: Node :: Expr ( parent_expr) = parent
437438 && let hir:: ExprKind :: MethodCall ( _, _, args, _) = parent_expr. kind
438- && let Some ( def_id) = typeck. type_dependent_def_id ( parent_expr. hir_id )
439439 {
440- ( def_id . as_local ( ) , args, 1 )
440+ ( typeck . type_dependent_def_id ( parent_expr . hir_id ) , args, 1 )
441441 } else if let hir:: Node :: Expr ( parent_expr) = parent
442442 && let hir:: ExprKind :: Call ( call, args) = parent_expr. kind
443443 && let ty:: FnDef ( def_id, _) = typeck. node_type ( call. hir_id ) . kind ( )
444444 {
445- ( def_id . as_local ( ) , args, 0 )
445+ ( Some ( * def_id ) , args, 0 )
446446 } else {
447447 ( None , & [ ] [ ..] , 0 )
448448 } ;
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+
449473 let mut can_suggest_clone = true ;
450474 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)
452477 && let Some ( fn_sig) = node. fn_sig ( )
453478 && let Some ( ident) = node. ident ( )
454479 && let Some ( pos) = args. iter ( ) . position ( |arg| arg. hir_id == expr. hir_id )
@@ -622,6 +647,25 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
622647 }
623648 }
624649
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+
625669 fn report_use_of_uninitialized (
626670 & self ,
627671 mpi : MovePathIndex ,
0 commit comments