@@ -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 > {
@@ -614,14 +612,19 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
614612 }
615613
616614 fn check_operand_move_size ( & mut self , operand : & mir:: Operand < ' tcx > , location : Location ) {
617- if self . skip_move_size_check {
618- return ;
619- }
620615 let limit = self . tcx . move_size_limit ( ) . 0 ;
621616 if limit == 0 {
622617 return ;
623618 }
624619
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+
625628 let limit = Size :: from_bytes ( limit) ;
626629 let ty = operand. ty ( self . body , self . tcx ) ;
627630 let ty = self . monomorphize ( ty) ;
@@ -659,6 +662,38 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
659662 ) ;
660663 self . move_size_spans . push ( source_info. span ) ;
661664 }
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+ }
662697}
663698
664699impl < ' a , ' tcx > MirVisitor < ' tcx > for MirUsedCollector < ' a , ' tcx > {
@@ -704,14 +739,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
704739 ) => {
705740 let fn_ty = operand. ty ( self . body , self . tcx ) ;
706741 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- ) ;
742+ visit_fn_use ( self . tcx , fn_ty, false , span, & mut self . output ) ;
715743 }
716744 mir:: Rvalue :: Cast (
717745 mir:: CastKind :: PointerCoercion ( PointerCoercion :: ClosureFnPointer ( _) ) ,
@@ -783,17 +811,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
783811 } ;
784812
785813 match terminator. kind {
786- mir:: TerminatorKind :: Call { ref func, .. } => {
814+ mir:: TerminatorKind :: Call { ref func, ref args , .. } => {
787815 let callee_ty = func. ty ( self . body , tcx) ;
788816 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- )
817+ self . check_fn_args_move_size ( callee_ty, args, location) ;
818+ visit_fn_use ( self . tcx , callee_ty, true , source, & mut self . output )
797819 }
798820 mir:: TerminatorKind :: Drop { ref place, .. } => {
799821 let ty = place. ty ( self . body , self . tcx ) . ty ;
@@ -805,7 +827,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
805827 match * op {
806828 mir:: InlineAsmOperand :: SymFn { ref value } => {
807829 let fn_ty = self . monomorphize ( value. const_ . ty ( ) ) ;
808- 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 ) ;
809831 }
810832 mir:: InlineAsmOperand :: SymStatic { def_id } => {
811833 let instance = Instance :: mono ( self . tcx , def_id) ;
@@ -843,8 +865,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
843865 push_mono_lang_item ( self , reason. lang_item ( ) ) ;
844866 }
845867
868+ self . visiting_call_terminator = matches ! ( terminator. kind, mir:: TerminatorKind :: Call { .. } ) ;
846869 self . super_terminator ( terminator, location) ;
847- self . skip_move_size_check = false ;
870+ self . visiting_call_terminator = false ;
848871 }
849872
850873 fn visit_operand ( & mut self , operand : & mir:: Operand < ' tcx > , location : Location ) {
@@ -878,11 +901,8 @@ fn visit_fn_use<'tcx>(
878901 is_direct_call : bool ,
879902 source : Span ,
880903 output : & mut MonoItems < ' tcx > ,
881- skip_move_check_fns : & [ DefId ] ,
882- ) -> bool {
883- let mut skip_move_size_check = false ;
904+ ) {
884905 if let ty:: FnDef ( def_id, args) = * ty. kind ( ) {
885- skip_move_size_check = skip_move_check_fns. contains ( & def_id) ;
886906 let instance = if is_direct_call {
887907 ty:: Instance :: expect_resolve ( tcx, ty:: ParamEnv :: reveal_all ( ) , def_id, args)
888908 } else {
@@ -893,7 +913,6 @@ fn visit_fn_use<'tcx>(
893913 } ;
894914 visit_instance_use ( tcx, instance, is_direct_call, source, output) ;
895915 }
896- skip_move_size_check
897916}
898917
899918fn visit_instance_use < ' tcx > (
@@ -1400,6 +1419,29 @@ fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) ->
14001419 return None ;
14011420}
14021421
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+
14031445/// Scans the MIR in order to find function calls, closures, and drop-glue.
14041446#[ instrument( skip( tcx, output) , level = "debug" ) ]
14051447fn collect_used_items < ' tcx > (
@@ -1409,28 +1451,6 @@ fn collect_used_items<'tcx>(
14091451) {
14101452 let body = tcx. instance_mir ( instance. def ) ;
14111453
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-
14341454 // Here we rely on the visitor also visiting `required_consts`, so that we evaluate them
14351455 // and abort compilation if any of them errors.
14361456 MirUsedCollector {
@@ -1439,8 +1459,8 @@ fn collect_used_items<'tcx>(
14391459 output,
14401460 instance,
14411461 move_size_spans : vec ! [ ] ,
1442- skip_move_size_check : false ,
1443- skip_move_check_fns,
1462+ visiting_call_terminator : false ,
1463+ skip_move_check_fns : None ,
14441464 }
14451465 . visit_body ( & body) ;
14461466}
0 commit comments