@@ -193,7 +193,7 @@ impl<'tcx> FnDecl<'tcx> {
193193 fn_ir,
194194 visited : HashMap :: new ( ) ,
195195 } ;
196- visitor. visit_expr ( self . body . value , Access :: Read ) ;
196+ visitor. visit_expr ( self . body . value , Access :: Borrow ) ;
197197 }
198198}
199199
@@ -290,6 +290,21 @@ fn decl_source_file(
290290 )
291291}
292292
293+ fn is_copy < ' tcx > ( tcx : rustc_middle:: ty:: TyCtxt < ' tcx > , ty : rustc_middle:: ty:: Ty < ' tcx > ) -> bool {
294+ use rustc_infer:: infer:: TyCtxtInferExt ;
295+ use rustc_trait_selection:: infer:: InferCtxtExt ;
296+
297+ let Some ( copy_trait) = tcx. lang_items ( ) . copy_trait ( ) else {
298+ return false ;
299+ } ;
300+ let infcx = tcx
301+ . infer_ctxt ( )
302+ . build ( rustc_middle:: ty:: TypingMode :: non_body_analysis ( ) ) ;
303+ infcx
304+ . type_implements_trait ( copy_trait, [ ty] , rustc_middle:: ty:: ParamEnv :: empty ( ) )
305+ . must_apply_modulo_regions ( )
306+ }
307+
293308fn type_derives < ' tcx > (
294309 tcx : rustc_middle:: ty:: TyCtxt < ' tcx > ,
295310 ty : rustc_middle:: ty:: Ty < ' tcx > ,
@@ -353,10 +368,15 @@ impl<'a, 'tcx> AstVisitor<'a, 'tcx> {
353368 fn visit_expr ( & mut self , expr : & ' tcx rustc_hir:: Expr < ' tcx > , context : Access ) {
354369 // Reached an argument used inside the rule body
355370 if let Some ( param) = self . expr_as_decl_ref ( expr) {
371+ let access = if context == Access :: Borrow && self . is_moved ( expr) {
372+ Access :: Read
373+ } else {
374+ context
375+ } ;
356376 self . fn_ir
357377 . resolve_next_param ( & param, & mut self . visited , |p| {
358378 if p. access == Access :: Unknown {
359- p. access = context ;
379+ p. access = access ;
360380 }
361381 } ) ;
362382 return ;
@@ -370,53 +390,62 @@ impl<'a, 'tcx> AstVisitor<'a, 'tcx> {
370390 param_access. first ( ) . copied ( ) . unwrap_or ( Access :: Unknown ) ,
371391 ) ;
372392 for ( i, arg) in args. iter ( ) . enumerate ( ) {
373- let access = param_access. get ( i + 1 ) . copied ( ) . unwrap_or ( Access :: Read ) ;
393+ let access = param_access. get ( i + 1 ) . copied ( ) . unwrap_or ( Access :: Borrow ) ;
374394 self . visit_expr ( arg, access) ;
375395 }
376396 }
377397 rustc_hir:: ExprKind :: Call ( callee, args) => {
378398 if self . is_std_mem_take ( expr) && args. len ( ) == 1 {
379- self . visit_expr ( & args[ 0 ] , Access :: Move ) ;
399+ self . visit_expr ( & args[ 0 ] , Access :: Take ) ;
380400 } else {
381401 self . visit_expr ( callee, context) ;
382402 let param_access = self . resolve_callee_param_access ( expr) ;
383403 for ( i, arg) in args. iter ( ) . enumerate ( ) {
384- let access = param_access. get ( i) . copied ( ) . unwrap_or ( Access :: Read ) ;
404+ let access = param_access. get ( i) . copied ( ) . unwrap_or ( Access :: Borrow ) ;
385405 self . visit_expr ( arg, access) ;
386406 }
387407 }
388408 }
389409
390410 rustc_hir:: ExprKind :: Assign ( lhs, rhs, _)
391411 | rustc_hir:: ExprKind :: AssignOp ( _, lhs, rhs) => {
392- self . visit_expr ( lhs, Access :: Write ) ;
393- self . visit_expr ( rhs, Access :: Read ) ;
412+ self . visit_expr ( lhs, Access :: BorrowMut ) ;
413+ self . visit_expr ( rhs, Access :: Borrow ) ;
394414 }
395415
396416 rustc_hir:: ExprKind :: AddrOf ( _, rustc_hir:: Mutability :: Mut , inner) => {
397417 self . visit_expr (
398418 inner,
399- if context == Access :: Move {
400- Access :: Move
419+ if context == Access :: Take {
420+ Access :: Take
401421 } else {
402- Access :: Write
422+ Access :: BorrowMut
403423 } ,
404424 ) ;
405425 }
406426 rustc_hir:: ExprKind :: AddrOf ( _, rustc_hir:: Mutability :: Not , inner) => {
407- self . visit_expr ( inner, Access :: Read ) ;
427+ if let Some ( param) = self . expr_as_decl_ref ( inner) {
428+ self . fn_ir
429+ . resolve_next_param ( & param, & mut self . visited , |p| {
430+ if p. access == Access :: Unknown {
431+ p. access = Access :: Borrow ;
432+ }
433+ } ) ;
434+ return ;
435+ }
436+ self . visit_expr ( inner, Access :: Borrow ) ;
408437 }
409438
410439 rustc_hir:: ExprKind :: Block ( block, _) | rustc_hir:: ExprKind :: Loop ( block, _, _, _) => {
411440 for stmt in block. stmts {
412441 match & stmt. kind {
413442 rustc_hir:: StmtKind :: Let ( local) => {
414443 if let Some ( init) = local. init {
415- self . visit_expr ( init, Access :: Read ) ;
444+ self . visit_expr ( init, Access :: Borrow ) ;
416445 }
417446 }
418447 rustc_hir:: StmtKind :: Expr ( e) | rustc_hir:: StmtKind :: Semi ( e) => {
419- self . visit_expr ( e, Access :: Read ) ;
448+ self . visit_expr ( e, Access :: Borrow ) ;
420449 }
421450 _ => { }
422451 }
@@ -427,22 +456,36 @@ impl<'a, 'tcx> AstVisitor<'a, 'tcx> {
427456 }
428457
429458 rustc_hir:: ExprKind :: If ( cond, then_branch, else_branch) => {
430- self . visit_expr ( cond, Access :: Read ) ;
459+ self . visit_expr ( cond, Access :: Borrow ) ;
431460 self . visit_expr ( then_branch, context) ;
432461 if let Some ( e) = else_branch {
433462 self . visit_expr ( e, context) ;
434463 }
435464 }
436465 rustc_hir:: ExprKind :: Match ( scrutinee, arms, _) => {
437- self . visit_expr ( scrutinee, Access :: Read ) ;
466+ self . visit_expr ( scrutinee, Access :: Borrow ) ;
438467 for arm in arms. iter ( ) {
468+ if let Some ( guard) = arm. guard {
469+ self . visit_expr ( guard, Access :: Borrow ) ;
470+ }
439471 self . visit_expr ( arm. body , context) ;
440472 }
441473 }
442474
475+ rustc_hir:: ExprKind :: Field ( base, _) => {
476+ if let Some ( param) = self . expr_as_decl_ref ( base) {
477+ self . fn_ir
478+ . resolve_next_param ( & param, & mut self . visited , |p| {
479+ if p. access == Access :: Unknown {
480+ p. access = context;
481+ }
482+ } ) ;
483+ return ;
484+ }
485+ self . visit_expr ( base, context) ;
486+ }
443487 rustc_hir:: ExprKind :: Unary ( _, e)
444488 | rustc_hir:: ExprKind :: Cast ( e, _)
445- | rustc_hir:: ExprKind :: Field ( e, _)
446489 | rustc_hir:: ExprKind :: DropTemps ( e)
447490 | rustc_hir:: ExprKind :: Repeat ( e, _) => {
448491 self . visit_expr ( e, context) ;
@@ -480,7 +523,7 @@ impl<'a, 'tcx> AstVisitor<'a, 'tcx> {
480523 | rustc_hir:: ExprKind :: Continue ( _) => { }
481524
482525 rustc_hir:: ExprKind :: Ret ( Some ( e) ) | rustc_hir:: ExprKind :: Break ( _, Some ( e) ) => {
483- self . visit_expr ( e, Access :: Read ) ;
526+ self . visit_expr ( e, Access :: Borrow ) ;
484527 }
485528
486529 other => {
@@ -494,6 +537,15 @@ impl<'a, 'tcx> AstVisitor<'a, 'tcx> {
494537 }
495538 }
496539
540+ fn is_moved ( & self , expr : & rustc_hir:: Expr < ' tcx > ) -> bool {
541+ let results = self . tcx . typeck ( expr. hir_id . owner ) ;
542+ let borrowed = results
543+ . expr_adjustments ( expr)
544+ . iter ( )
545+ . any ( |adj| matches ! ( adj. kind, rustc_middle:: ty:: adjustment:: Adjust :: Borrow ( _) ) ) ;
546+ !borrowed && !is_copy ( self . tcx , results. expr_ty ( expr) )
547+ }
548+
497549 fn expr_as_decl_ref ( & self , expr : & rustc_hir:: Expr < ' _ > ) -> Option < String > {
498550 if let rustc_hir:: ExprKind :: Path ( rustc_hir:: QPath :: Resolved ( _, path) ) = & expr. kind
499551 && let Some ( seg) = path. segments . last ( )
@@ -548,11 +600,19 @@ impl<'a, 'tcx> AstVisitor<'a, 'tcx> {
548600
549601 fn access_for_type ( ty : & rustc_middle:: ty:: Ty < ' _ > ) -> Access {
550602 match ty. kind ( ) {
551- rustc_middle:: ty:: TyKind :: Ref ( _, _, rustc_middle:: ty:: Mutability :: Mut ) => Access :: Write ,
552- rustc_middle:: ty:: TyKind :: Ref ( _, _, rustc_middle:: ty:: Mutability :: Not ) => Access :: Read ,
553- rustc_middle:: ty:: TyKind :: RawPtr ( _, rustc_middle:: ty:: Mutability :: Mut ) => Access :: Write ,
554- rustc_middle:: ty:: TyKind :: RawPtr ( _, rustc_middle:: ty:: Mutability :: Not ) => Access :: Read ,
555- _ => Access :: Read ,
603+ rustc_middle:: ty:: TyKind :: Ref ( _, _, rustc_middle:: ty:: Mutability :: Mut ) => {
604+ Access :: BorrowMut
605+ }
606+ rustc_middle:: ty:: TyKind :: Ref ( _, _, rustc_middle:: ty:: Mutability :: Not ) => {
607+ Access :: Borrow
608+ }
609+ rustc_middle:: ty:: TyKind :: RawPtr ( _, rustc_middle:: ty:: Mutability :: Mut ) => {
610+ Access :: BorrowMut
611+ }
612+ rustc_middle:: ty:: TyKind :: RawPtr ( _, rustc_middle:: ty:: Mutability :: Not ) => {
613+ Access :: Borrow
614+ }
615+ _ => Access :: Borrow ,
556616 }
557617 }
558618}
0 commit comments