@@ -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,9 @@ 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 ,
596
+ visiting_call_terminator : bool ,
599
597
/// 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 > > ,
601
599
}
602
600
603
601
impl < ' a , ' tcx > MirUsedCollector < ' a , ' tcx > {
@@ -614,14 +612,19 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
614
612
}
615
613
616
614
fn check_operand_move_size ( & mut self , operand : & mir:: Operand < ' tcx > , location : Location ) {
617
- if self . skip_move_size_check {
618
- return ;
619
- }
620
615
let limit = self . tcx . move_size_limit ( ) . 0 ;
621
616
if limit == 0 {
622
617
return ;
623
618
}
624
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
+
625
628
let limit = Size :: from_bytes ( limit) ;
626
629
let ty = operand. ty ( self . body , self . tcx ) ;
627
630
let ty = self . monomorphize ( ty) ;
@@ -659,6 +662,38 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
659
662
) ;
660
663
self . move_size_spans . push ( source_info. span ) ;
661
664
}
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
+ }
662
697
}
663
698
664
699
impl < ' a , ' tcx > MirVisitor < ' tcx > for MirUsedCollector < ' a , ' tcx > {
@@ -704,14 +739,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
704
739
) => {
705
740
let fn_ty = operand. ty ( self . body , self . tcx ) ;
706
741
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 ) ;
715
743
}
716
744
mir:: Rvalue :: Cast (
717
745
mir:: CastKind :: PointerCoercion ( PointerCoercion :: ClosureFnPointer ( _) ) ,
@@ -783,17 +811,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
783
811
} ;
784
812
785
813
match terminator. kind {
786
- mir:: TerminatorKind :: Call { ref func, .. } => {
814
+ mir:: TerminatorKind :: Call { ref func, ref args , .. } => {
787
815
let callee_ty = func. ty ( self . body , tcx) ;
788
816
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 )
797
819
}
798
820
mir:: TerminatorKind :: Drop { ref place, .. } => {
799
821
let ty = place. ty ( self . body , self . tcx ) . ty ;
@@ -805,7 +827,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
805
827
match * op {
806
828
mir:: InlineAsmOperand :: SymFn { ref value } => {
807
829
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 ) ;
809
831
}
810
832
mir:: InlineAsmOperand :: SymStatic { def_id } => {
811
833
let instance = Instance :: mono ( self . tcx , def_id) ;
@@ -843,8 +865,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
843
865
push_mono_lang_item ( self , reason. lang_item ( ) ) ;
844
866
}
845
867
868
+ self . visiting_call_terminator = matches ! ( terminator. kind, mir:: TerminatorKind :: Call { .. } ) ;
846
869
self . super_terminator ( terminator, location) ;
847
- self . skip_move_size_check = false ;
870
+ self . visiting_call_terminator = false ;
848
871
}
849
872
850
873
fn visit_operand ( & mut self , operand : & mir:: Operand < ' tcx > , location : Location ) {
@@ -878,11 +901,8 @@ fn visit_fn_use<'tcx>(
878
901
is_direct_call : bool ,
879
902
source : Span ,
880
903
output : & mut MonoItems < ' tcx > ,
881
- skip_move_check_fns : & [ DefId ] ,
882
- ) -> bool {
883
- let mut skip_move_size_check = false ;
904
+ ) {
884
905
if let ty:: FnDef ( def_id, args) = * ty. kind ( ) {
885
- skip_move_size_check = skip_move_check_fns. contains ( & def_id) ;
886
906
let instance = if is_direct_call {
887
907
ty:: Instance :: expect_resolve ( tcx, ty:: ParamEnv :: reveal_all ( ) , def_id, args)
888
908
} else {
@@ -893,7 +913,6 @@ fn visit_fn_use<'tcx>(
893
913
} ;
894
914
visit_instance_use ( tcx, instance, is_direct_call, source, output) ;
895
915
}
896
- skip_move_size_check
897
916
}
898
917
899
918
fn visit_instance_use < ' tcx > (
@@ -1400,6 +1419,29 @@ fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) ->
1400
1419
return None ;
1401
1420
}
1402
1421
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
+
1403
1445
/// Scans the MIR in order to find function calls, closures, and drop-glue.
1404
1446
#[ instrument( skip( tcx, output) , level = "debug" ) ]
1405
1447
fn collect_used_items < ' tcx > (
@@ -1409,36 +1451,14 @@ fn collect_used_items<'tcx>(
1409
1451
) {
1410
1452
let body = tcx. instance_mir ( instance. def ) ;
1411
1453
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
1454
MirUsedCollector {
1435
1455
tcx,
1436
1456
body : & body,
1437
1457
output,
1438
1458
instance,
1439
1459
move_size_spans : vec ! [ ] ,
1440
- skip_move_size_check : false ,
1441
- skip_move_check_fns,
1460
+ visiting_call_terminator : false ,
1461
+ skip_move_check_fns : None ,
1442
1462
}
1443
1463
. visit_body ( & body) ;
1444
1464
}
0 commit comments