@@ -205,7 +205,13 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
205205
206206 if !seen_spans. contains ( & move_span) {
207207 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+ ) ;
209215 }
210216
211217 let msg_opt = CapturedMessageOpt {
@@ -257,17 +263,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
257263 if is_loop_move & !in_pattern && !matches ! ( use_spans, UseSpans :: ClosureUse { .. } ) {
258264 if let ty:: Ref ( _, _, hir:: Mutability :: Mut ) = ty. kind ( ) {
259265 // 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) ;
271267 }
272268 }
273269
@@ -344,6 +340,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
344340 err : & mut Diag < ' tcx > ,
345341 in_pattern : & mut bool ,
346342 move_spans : UseSpans < ' tcx > ,
343+ moved_place : PlaceRef < ' tcx > ,
347344 ) {
348345 let move_span = match move_spans {
349346 UseSpans :: ClosureUse { capture_kind_span, .. } => capture_kind_span,
@@ -444,13 +441,37 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
444441 } else {
445442 ( None , & [ ] [ ..] , 0 )
446443 } ;
444+ let mut reborrow = false ;
447445 if let Some ( def_id) = def_id
448446 && let node = self . infcx . tcx . hir_node_by_def_id ( def_id)
449447 && let Some ( fn_sig) = node. fn_sig ( )
450448 && let Some ( ident) = node. ident ( )
451449 && let Some ( pos) = args. iter ( ) . position ( |arg| arg. hir_id == expr. hir_id )
452450 && let Some ( arg) = fn_sig. decl . inputs . get ( pos + offset)
453451 {
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+
454475 let mut span: MultiSpan = arg. span . into ( ) ;
455476 span. push_span_label (
456477 arg. span ,
@@ -472,6 +493,10 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
472493 }
473494 let place = & self . move_data . move_paths [ mpi] . place ;
474495 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+ }
475500 if let hir:: Node :: Expr ( parent_expr) = parent
476501 && let hir:: ExprKind :: Call ( call_expr, _) = parent_expr. kind
477502 && let hir:: ExprKind :: Path ( hir:: QPath :: LangItem ( LangItem :: IntoIterIntoIter , _) ) =
@@ -509,6 +534,20 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
509534 }
510535 }
511536
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+
512551 fn report_use_of_uninitialized (
513552 & self ,
514553 mpi : MovePathIndex ,
0 commit comments