@@ -432,7 +432,7 @@ fn collect_items_rec<'tcx>(
432432                        hir:: InlineAsmOperand :: SymFn  {  anon_const }  => { 
433433                            let  fn_ty =
434434                                tcx. typeck_body ( anon_const. body ) . node_type ( anon_const. hir_id ) ; 
435-                             visit_fn_use ( tcx,  fn_ty,  false ,  * op_sp,  & mut  used_items,   & [ ] ) ; 
435+                             visit_fn_use ( tcx,  fn_ty,  false ,  * op_sp,  & mut  used_items) ; 
436436                        } 
437437                        hir:: InlineAsmOperand :: SymStatic  {  path :  _,  def_id }  => { 
438438                            let  instance = Instance :: mono ( tcx,  * def_id) ; 
@@ -593,11 +593,9 @@ struct MirUsedCollector<'a, 'tcx> {
593593    instance :  Instance < ' tcx > , 
594594    /// Spans for move size lints already emitted. Helps avoid duplicate lints. 
595595     move_size_spans :  Vec < Span > , 
596-     /// If true, we should temporarily skip move size checks, because we are 
597-      /// processing an operand to a `skip_move_check_fns` function call. 
598-      skip_move_size_check :  bool , 
596+     visiting_call_terminator :  bool , 
599597    /// Set of functions for which it is OK to move large data into. 
600-      skip_move_check_fns :  Vec < DefId > , 
598+      skip_move_check_fns :  Option < Vec < DefId > > , 
601599} 
602600
603601impl < ' a ,  ' tcx >  MirUsedCollector < ' a ,  ' tcx >  { 
@@ -613,7 +611,20 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
613611        ) 
614612    } 
615613
616-     fn  check_move_size ( & mut  self ,  limit :  usize ,  operand :  & mir:: Operand < ' tcx > ,  location :  Location )  { 
614+     fn  check_operand_move_size ( & mut  self ,  operand :  & mir:: Operand < ' tcx > ,  location :  Location )  { 
615+         let  limit = self . tcx . move_size_limit ( ) . 0 ; 
616+         if  limit == 0  { 
617+             return ; 
618+         } 
619+ 
620+         // This function is called by visit_operand() which visits _all_ 
621+         // operands, including TerminatorKind::Call operands. But if 
622+         // check_fn_args_move_size() has been called, the operands have already 
623+         // been visited. Do not visit them again. 
624+         if  self . visiting_call_terminator  { 
625+             return ; 
626+         } 
627+ 
617628        let  limit = Size :: from_bytes ( limit) ; 
618629        let  ty = operand. ty ( self . body ,  self . tcx ) ; 
619630        let  ty = self . monomorphize ( ty) ; 
@@ -651,6 +662,38 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
651662        ) ; 
652663        self . move_size_spans . push ( source_info. span ) ; 
653664    } 
665+ 
666+     fn  check_fn_args_move_size ( 
667+         & mut  self , 
668+         callee_ty :  Ty < ' tcx > , 
669+         args :  & [ mir:: Operand < ' tcx > ] , 
670+         location :  Location , 
671+     )  { 
672+         let  limit = self . tcx . move_size_limit ( ) ; 
673+         if  limit. 0  == 0  { 
674+             return ; 
675+         } 
676+ 
677+         if  args. is_empty ( )  { 
678+             return ; 
679+         } 
680+ 
681+         // Allow large moves into container types that themselves are cheap to move 
682+         let  ty:: FnDef ( def_id,  _)  = * callee_ty. kind ( )  else  { 
683+             return ; 
684+         } ; 
685+         if  self 
686+             . skip_move_check_fns 
687+             . get_or_insert_with ( || build_skip_move_check_fns ( self . tcx ) ) 
688+             . contains ( & def_id) 
689+         { 
690+             return ; 
691+         } 
692+ 
693+         for  arg in  args { 
694+             self . check_operand_move_size ( arg,  location) ; 
695+         } 
696+     } 
654697} 
655698
656699impl < ' a ,  ' tcx >  MirVisitor < ' tcx >  for  MirUsedCollector < ' a ,  ' tcx >  { 
@@ -696,14 +739,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
696739            )  => { 
697740                let  fn_ty = operand. ty ( self . body ,  self . tcx ) ; 
698741                let  fn_ty = self . monomorphize ( fn_ty) ; 
699-                 visit_fn_use ( 
700-                     self . tcx , 
701-                     fn_ty, 
702-                     false , 
703-                     span, 
704-                     & mut  self . output , 
705-                     & self . skip_move_check_fns , 
706-                 ) ; 
742+                 visit_fn_use ( self . tcx ,  fn_ty,  false ,  span,  & mut  self . output ) ; 
707743            } 
708744            mir:: Rvalue :: Cast ( 
709745                mir:: CastKind :: PointerCoercion ( PointerCoercion :: ClosureFnPointer ( _) ) , 
@@ -775,17 +811,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
775811        } ; 
776812
777813        match  terminator. kind  { 
778-             mir:: TerminatorKind :: Call  {  ref  func,  .. }  => { 
814+             mir:: TerminatorKind :: Call  {  ref  func,  ref  args ,   .. }  => { 
779815                let  callee_ty = func. ty ( self . body ,  tcx) ; 
780816                let  callee_ty = self . monomorphize ( callee_ty) ; 
781-                 self . skip_move_size_check  = visit_fn_use ( 
782-                     self . tcx , 
783-                     callee_ty, 
784-                     true , 
785-                     source, 
786-                     & mut  self . output , 
787-                     & self . skip_move_check_fns , 
788-                 ) 
817+                 self . check_fn_args_move_size ( callee_ty,  args,  location) ; 
818+                 visit_fn_use ( self . tcx ,  callee_ty,  true ,  source,  & mut  self . output ) 
789819            } 
790820            mir:: TerminatorKind :: Drop  {  ref  place,  .. }  => { 
791821                let  ty = place. ty ( self . body ,  self . tcx ) . ty ; 
@@ -797,7 +827,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
797827                    match  * op { 
798828                        mir:: InlineAsmOperand :: SymFn  {  ref  value }  => { 
799829                            let  fn_ty = self . monomorphize ( value. const_ . ty ( ) ) ; 
800-                             visit_fn_use ( self . tcx ,  fn_ty,  false ,  source,  & mut  self . output ,   & [ ] ) ; 
830+                             visit_fn_use ( self . tcx ,  fn_ty,  false ,  source,  & mut  self . output ) ; 
801831                        } 
802832                        mir:: InlineAsmOperand :: SymStatic  {  def_id }  => { 
803833                            let  instance = Instance :: mono ( self . tcx ,  def_id) ; 
@@ -835,16 +865,14 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
835865            push_mono_lang_item ( self ,  reason. lang_item ( ) ) ; 
836866        } 
837867
868+         self . visiting_call_terminator  = matches ! ( terminator. kind,  mir:: TerminatorKind :: Call  {  .. } ) ; 
838869        self . super_terminator ( terminator,  location) ; 
839-         self . skip_move_size_check  = false ; 
870+         self . visiting_call_terminator  = false ; 
840871    } 
841872
842873    fn  visit_operand ( & mut  self ,  operand :  & mir:: Operand < ' tcx > ,  location :  Location )  { 
843874        self . super_operand ( operand,  location) ; 
844-         let  move_size_limit = self . tcx . move_size_limit ( ) . 0 ; 
845-         if  move_size_limit > 0  && !self . skip_move_size_check  { 
846-             self . check_move_size ( move_size_limit,  operand,  location) ; 
847-         } 
875+         self . check_operand_move_size ( operand,  location) ; 
848876    } 
849877
850878    fn  visit_local ( 
@@ -873,11 +901,8 @@ fn visit_fn_use<'tcx>(
873901    is_direct_call :  bool , 
874902    source :  Span , 
875903    output :  & mut  MonoItems < ' tcx > , 
876-     skip_move_check_fns :  & [ DefId ] , 
877- )  -> bool  { 
878-     let  mut  skip_move_size_check = false ; 
904+ )  { 
879905    if  let  ty:: FnDef ( def_id,  args)  = * ty. kind ( )  { 
880-         skip_move_size_check = skip_move_check_fns. contains ( & def_id) ; 
881906        let  instance = if  is_direct_call { 
882907            ty:: Instance :: expect_resolve ( tcx,  ty:: ParamEnv :: reveal_all ( ) ,  def_id,  args) 
883908        }  else  { 
@@ -888,7 +913,6 @@ fn visit_fn_use<'tcx>(
888913        } ; 
889914        visit_instance_use ( tcx,  instance,  is_direct_call,  source,  output) ; 
890915    } 
891-     skip_move_size_check
892916} 
893917
894918fn  visit_instance_use < ' tcx > ( 
@@ -1395,6 +1419,29 @@ fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) ->
13951419    return  None ; 
13961420} 
13971421
1422+ fn  build_skip_move_check_fns ( tcx :  TyCtxt < ' _ > )  -> Vec < DefId >  { 
1423+     let  mut  skip_move_check_fns = vec ! [ ] ; 
1424+     add_assoc_fn ( 
1425+         tcx, 
1426+         tcx. lang_items ( ) . owned_box ( ) , 
1427+         Ident :: from_str ( "new" ) , 
1428+         & mut  skip_move_check_fns, 
1429+     ) ; 
1430+     add_assoc_fn ( 
1431+         tcx, 
1432+         tcx. get_diagnostic_item ( sym:: Arc ) , 
1433+         Ident :: from_str ( "new" ) , 
1434+         & mut  skip_move_check_fns, 
1435+     ) ; 
1436+     add_assoc_fn ( 
1437+         tcx, 
1438+         tcx. get_diagnostic_item ( sym:: Rc ) , 
1439+         Ident :: from_str ( "new" ) , 
1440+         & mut  skip_move_check_fns, 
1441+     ) ; 
1442+     skip_move_check_fns
1443+ } 
1444+ 
13981445/// Scans the MIR in order to find function calls, closures, and drop-glue. 
13991446#[ instrument( skip( tcx,  output) ,  level = "debug" ) ]  
14001447fn  collect_used_items < ' tcx > ( 
@@ -1404,28 +1451,6 @@ fn collect_used_items<'tcx>(
14041451)  { 
14051452    let  body = tcx. instance_mir ( instance. def ) ; 
14061453
1407-     let  mut  skip_move_check_fns = vec ! [ ] ; 
1408-     if  tcx. move_size_limit ( ) . 0  > 0  { 
1409-         add_assoc_fn ( 
1410-             tcx, 
1411-             tcx. lang_items ( ) . owned_box ( ) , 
1412-             Ident :: from_str ( "new" ) , 
1413-             & mut  skip_move_check_fns, 
1414-         ) ; 
1415-         add_assoc_fn ( 
1416-             tcx, 
1417-             tcx. get_diagnostic_item ( sym:: Arc ) , 
1418-             Ident :: from_str ( "new" ) , 
1419-             & mut  skip_move_check_fns, 
1420-         ) ; 
1421-         add_assoc_fn ( 
1422-             tcx, 
1423-             tcx. get_diagnostic_item ( sym:: Rc ) , 
1424-             Ident :: from_str ( "new" ) , 
1425-             & mut  skip_move_check_fns, 
1426-         ) ; 
1427-     } 
1428- 
14291454    // Here we rely on the visitor also visiting `required_consts`, so that we evaluate them 
14301455    // and abort compilation if any of them errors. 
14311456    MirUsedCollector  { 
@@ -1434,8 +1459,8 @@ fn collect_used_items<'tcx>(
14341459        output, 
14351460        instance, 
14361461        move_size_spans :  vec ! [ ] , 
1437-         skip_move_size_check :  false , 
1438-         skip_move_check_fns, 
1462+         visiting_call_terminator :  false , 
1463+         skip_move_check_fns :   None , 
14391464    } 
14401465    . visit_body ( & body) ; 
14411466} 
0 commit comments