@@ -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,7 @@ 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 ,
599- /// Set of functions for which it is OK to move large data into.
600- skip_move_check_fns : Vec < DefId > ,
596+ visiting_call_terminator : bool ,
601597}
602598
603599impl < ' a , ' tcx > MirUsedCollector < ' a , ' tcx > {
@@ -614,14 +610,19 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
614610 }
615611
616612 fn check_operand_move_size ( & mut self , operand : & mir:: Operand < ' tcx > , location : Location ) {
617- if self . skip_move_size_check {
618- return ;
619- }
620613 let limit = self . tcx . move_size_limit ( ) . 0 ;
621614 if limit == 0 {
622615 return ;
623616 }
624617
618+ // This function is called by visit_operand() which visits _all_
619+ // operands, including TerminatorKind::Call operands. But if
620+ // check_fn_args_move_size() has been called, the operands have already
621+ // been visited. Do not visit them again.
622+ if self . visiting_call_terminator {
623+ return ;
624+ }
625+
625626 let limit = Size :: from_bytes ( limit) ;
626627 let ty = operand. ty ( self . body , self . tcx ) ;
627628 let ty = self . monomorphize ( ty) ;
@@ -659,6 +660,59 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
659660 ) ;
660661 self . move_size_spans . push ( source_info. span ) ;
661662 }
663+
664+ fn check_fn_args_move_size (
665+ & mut self ,
666+ callee_ty : Ty < ' tcx > ,
667+ args : & [ mir:: Operand < ' tcx > ] ,
668+ location : Location ,
669+ ) {
670+ let limit = self . tcx . move_size_limit ( ) ;
671+ if limit. 0 == 0 {
672+ return ;
673+ }
674+
675+ if args. is_empty ( ) {
676+ return ;
677+ }
678+
679+ // Allow large moves into container types that themselves are cheap to move
680+ let ty:: FnDef ( def_id, _) = * callee_ty. kind ( ) else {
681+ return ;
682+ } ;
683+ static SKIP_MOVE_CHECK_FNS : std:: sync:: OnceLock < Vec < DefId > > = std:: sync:: OnceLock :: new ( ) ;
684+ if SKIP_MOVE_CHECK_FNS
685+ . get_or_init ( || {
686+ let mut skip_move_check_fns = vec ! [ ] ;
687+ add_assoc_fn (
688+ self . tcx ,
689+ self . tcx . lang_items ( ) . owned_box ( ) ,
690+ Ident :: from_str ( "new" ) ,
691+ & mut skip_move_check_fns,
692+ ) ;
693+ add_assoc_fn (
694+ self . tcx ,
695+ self . tcx . get_diagnostic_item ( sym:: Arc ) ,
696+ Ident :: from_str ( "new" ) ,
697+ & mut skip_move_check_fns,
698+ ) ;
699+ add_assoc_fn (
700+ self . tcx ,
701+ self . tcx . get_diagnostic_item ( sym:: Rc ) ,
702+ Ident :: from_str ( "new" ) ,
703+ & mut skip_move_check_fns,
704+ ) ;
705+ skip_move_check_fns
706+ } )
707+ . contains ( & def_id)
708+ {
709+ return ;
710+ }
711+
712+ for arg in args {
713+ self . check_operand_move_size ( arg, location) ;
714+ }
715+ }
662716}
663717
664718impl < ' a , ' tcx > MirVisitor < ' tcx > for MirUsedCollector < ' a , ' tcx > {
@@ -704,14 +758,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
704758 ) => {
705759 let fn_ty = operand. ty ( self . body , self . tcx ) ;
706760 let fn_ty = self . monomorphize ( fn_ty) ;
707- visit_fn_use (
708- self . tcx ,
709- fn_ty,
710- false ,
711- span,
712- & mut self . output ,
713- & self . skip_move_check_fns ,
714- ) ;
761+ visit_fn_use ( self . tcx , fn_ty, false , span, & mut self . output ) ;
715762 }
716763 mir:: Rvalue :: Cast (
717764 mir:: CastKind :: PointerCoercion ( PointerCoercion :: ClosureFnPointer ( _) ) ,
@@ -783,17 +830,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
783830 } ;
784831
785832 match terminator. kind {
786- mir:: TerminatorKind :: Call { ref func, .. } => {
833+ mir:: TerminatorKind :: Call { ref func, ref args , .. } => {
787834 let callee_ty = func. ty ( self . body , tcx) ;
788835 let callee_ty = self . monomorphize ( callee_ty) ;
789- self . skip_move_size_check = visit_fn_use (
790- self . tcx ,
791- callee_ty,
792- true ,
793- source,
794- & mut self . output ,
795- & self . skip_move_check_fns ,
796- )
836+ self . check_fn_args_move_size ( callee_ty, args, location) ;
837+ visit_fn_use ( self . tcx , callee_ty, true , source, & mut self . output )
797838 }
798839 mir:: TerminatorKind :: Drop { ref place, .. } => {
799840 let ty = place. ty ( self . body , self . tcx ) . ty ;
@@ -805,7 +846,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
805846 match * op {
806847 mir:: InlineAsmOperand :: SymFn { ref value } => {
807848 let fn_ty = self . monomorphize ( value. const_ . ty ( ) ) ;
808- visit_fn_use ( self . tcx , fn_ty, false , source, & mut self . output , & [ ] ) ;
849+ visit_fn_use ( self . tcx , fn_ty, false , source, & mut self . output ) ;
809850 }
810851 mir:: InlineAsmOperand :: SymStatic { def_id } => {
811852 let instance = Instance :: mono ( self . tcx , def_id) ;
@@ -843,8 +884,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
843884 push_mono_lang_item ( self , reason. lang_item ( ) ) ;
844885 }
845886
887+ self . visiting_call_terminator = matches ! ( terminator. kind, mir:: TerminatorKind :: Call { .. } ) ;
846888 self . super_terminator ( terminator, location) ;
847- self . skip_move_size_check = false ;
889+ self . visiting_call_terminator = false ;
848890 }
849891
850892 fn visit_operand ( & mut self , operand : & mir:: Operand < ' tcx > , location : Location ) {
@@ -878,11 +920,8 @@ fn visit_fn_use<'tcx>(
878920 is_direct_call : bool ,
879921 source : Span ,
880922 output : & mut MonoItems < ' tcx > ,
881- skip_move_check_fns : & [ DefId ] ,
882- ) -> bool {
883- let mut skip_move_size_check = false ;
923+ ) {
884924 if let ty:: FnDef ( def_id, args) = * ty. kind ( ) {
885- skip_move_size_check = skip_move_check_fns. contains ( & def_id) ;
886925 let instance = if is_direct_call {
887926 ty:: Instance :: expect_resolve ( tcx, ty:: ParamEnv :: reveal_all ( ) , def_id, args)
888927 } else {
@@ -893,7 +932,6 @@ fn visit_fn_use<'tcx>(
893932 } ;
894933 visit_instance_use ( tcx, instance, is_direct_call, source, output) ;
895934 }
896- skip_move_size_check
897935}
898936
899937fn visit_instance_use < ' tcx > (
@@ -1409,36 +1447,13 @@ fn collect_used_items<'tcx>(
14091447) {
14101448 let body = tcx. instance_mir ( instance. def ) ;
14111449
1412- let mut skip_move_check_fns = vec ! [ ] ;
1413- if tcx. move_size_limit ( ) . 0 > 0 {
1414- add_assoc_fn (
1415- tcx,
1416- tcx. lang_items ( ) . owned_box ( ) ,
1417- Ident :: from_str ( "new" ) ,
1418- & mut skip_move_check_fns,
1419- ) ;
1420- add_assoc_fn (
1421- tcx,
1422- tcx. get_diagnostic_item ( sym:: Arc ) ,
1423- Ident :: from_str ( "new" ) ,
1424- & mut skip_move_check_fns,
1425- ) ;
1426- add_assoc_fn (
1427- tcx,
1428- tcx. get_diagnostic_item ( sym:: Rc ) ,
1429- Ident :: from_str ( "new" ) ,
1430- & mut skip_move_check_fns,
1431- ) ;
1432- }
1433-
14341450 MirUsedCollector {
14351451 tcx,
14361452 body : & body,
14371453 output,
14381454 instance,
14391455 move_size_spans : vec ! [ ] ,
1440- skip_move_size_check : false ,
1441- skip_move_check_fns,
1456+ visiting_call_terminator : false ,
14421457 }
14431458 . visit_body ( & body) ;
14441459}
0 commit comments