@@ -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