@@ -432,7 +432,7 @@ fn collect_items_rec<'tcx>(
432
432
hir:: InlineAsmOperand :: SymFn { anon_const } => {
433
433
let fn_ty =
434
434
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) ;
436
436
}
437
437
hir:: InlineAsmOperand :: SymStatic { path : _, def_id } => {
438
438
let instance = Instance :: mono ( tcx, * def_id) ;
@@ -593,11 +593,7 @@ struct MirUsedCollector<'a, 'tcx> {
593
593
instance : Instance < ' tcx > ,
594
594
/// Spans for move size lints already emitted. Helps avoid duplicate lints.
595
595
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 ,
601
597
}
602
598
603
599
impl < ' a , ' tcx > MirUsedCollector < ' a , ' tcx > {
@@ -614,14 +610,19 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
614
610
}
615
611
616
612
fn check_operand_move_size ( & mut self , operand : & mir:: Operand < ' tcx > , location : Location ) {
617
- if self . skip_move_size_check {
618
- return ;
619
- }
620
613
let limit = self . tcx . move_size_limit ( ) . 0 ;
621
614
if limit == 0 {
622
615
return ;
623
616
}
624
617
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
+
625
626
let limit = Size :: from_bytes ( limit) ;
626
627
let ty = operand. ty ( self . body , self . tcx ) ;
627
628
let ty = self . monomorphize ( ty) ;
@@ -659,6 +660,59 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
659
660
) ;
660
661
self . move_size_spans . push ( source_info. span ) ;
661
662
}
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
+ }
662
716
}
663
717
664
718
impl < ' a , ' tcx > MirVisitor < ' tcx > for MirUsedCollector < ' a , ' tcx > {
@@ -704,14 +758,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
704
758
) => {
705
759
let fn_ty = operand. ty ( self . body , self . tcx ) ;
706
760
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 ) ;
715
762
}
716
763
mir:: Rvalue :: Cast (
717
764
mir:: CastKind :: PointerCoercion ( PointerCoercion :: ClosureFnPointer ( _) ) ,
@@ -783,17 +830,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
783
830
} ;
784
831
785
832
match terminator. kind {
786
- mir:: TerminatorKind :: Call { ref func, .. } => {
833
+ mir:: TerminatorKind :: Call { ref func, ref args , .. } => {
787
834
let callee_ty = func. ty ( self . body , tcx) ;
788
835
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 )
797
838
}
798
839
mir:: TerminatorKind :: Drop { ref place, .. } => {
799
840
let ty = place. ty ( self . body , self . tcx ) . ty ;
@@ -805,7 +846,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
805
846
match * op {
806
847
mir:: InlineAsmOperand :: SymFn { ref value } => {
807
848
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 ) ;
809
850
}
810
851
mir:: InlineAsmOperand :: SymStatic { def_id } => {
811
852
let instance = Instance :: mono ( self . tcx , def_id) ;
@@ -843,8 +884,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
843
884
push_mono_lang_item ( self , reason. lang_item ( ) ) ;
844
885
}
845
886
887
+ self . visiting_call_terminator = matches ! ( terminator. kind, mir:: TerminatorKind :: Call { .. } ) ;
846
888
self . super_terminator ( terminator, location) ;
847
- self . skip_move_size_check = false ;
889
+ self . visiting_call_terminator = false ;
848
890
}
849
891
850
892
fn visit_operand ( & mut self , operand : & mir:: Operand < ' tcx > , location : Location ) {
@@ -878,11 +920,8 @@ fn visit_fn_use<'tcx>(
878
920
is_direct_call : bool ,
879
921
source : Span ,
880
922
output : & mut MonoItems < ' tcx > ,
881
- skip_move_check_fns : & [ DefId ] ,
882
- ) -> bool {
883
- let mut skip_move_size_check = false ;
923
+ ) {
884
924
if let ty:: FnDef ( def_id, args) = * ty. kind ( ) {
885
- skip_move_size_check = skip_move_check_fns. contains ( & def_id) ;
886
925
let instance = if is_direct_call {
887
926
ty:: Instance :: expect_resolve ( tcx, ty:: ParamEnv :: reveal_all ( ) , def_id, args)
888
927
} else {
@@ -893,7 +932,6 @@ fn visit_fn_use<'tcx>(
893
932
} ;
894
933
visit_instance_use ( tcx, instance, is_direct_call, source, output) ;
895
934
}
896
- skip_move_size_check
897
935
}
898
936
899
937
fn visit_instance_use < ' tcx > (
@@ -1409,36 +1447,13 @@ fn collect_used_items<'tcx>(
1409
1447
) {
1410
1448
let body = tcx. instance_mir ( instance. def ) ;
1411
1449
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
-
1434
1450
MirUsedCollector {
1435
1451
tcx,
1436
1452
body : & body,
1437
1453
output,
1438
1454
instance,
1439
1455
move_size_spans : vec ! [ ] ,
1440
- skip_move_size_check : false ,
1441
- skip_move_check_fns,
1456
+ visiting_call_terminator : false ,
1442
1457
}
1443
1458
. visit_body ( & body) ;
1444
1459
}
0 commit comments