@@ -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,
@@ -445,13 +442,36 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
445442 } else {
446443 ( None , & [ ] [ ..] , 0 )
447444 } ;
445+ let mut reborrow = false ;
448446 if let Some ( def_id) = def_id
449447 && let node = self . infcx . tcx . hir_node_by_def_id ( def_id)
450448 && let Some ( fn_sig) = node. fn_sig ( )
451449 && let Some ( ident) = node. ident ( )
452450 && let Some ( pos) = args. iter ( ) . position ( |arg| arg. hir_id == expr. hir_id )
453451 && let Some ( arg) = fn_sig. decl . inputs . get ( pos + offset)
454452 {
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+
455475 let mut span: MultiSpan = arg. span . into ( ) ;
456476 span. push_span_label (
457477 arg. span ,
@@ -473,6 +493,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
473493 }
474494 let place = & self . move_data . move_paths [ mpi] . place ;
475495 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+ }
476500 if let hir:: Node :: Expr ( parent_expr) = parent
477501 && let hir:: ExprKind :: Call ( call_expr, _) = parent_expr. kind
478502 && let hir:: ExprKind :: Path ( hir:: QPath :: LangItem ( LangItem :: IntoIterIntoIter , _) ) =
@@ -510,6 +534,20 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
510534 }
511535 }
512536
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+
513551 fn report_use_of_uninitialized (
514552 & self ,
515553 mpi : MovePathIndex ,
0 commit comments