@@ -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 > {
@@ -613,7 +611,20 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
613
611
)
614
612
}
615
613
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
+
617
628
let limit = Size :: from_bytes ( limit) ;
618
629
let ty = operand. ty ( self . body , self . tcx ) ;
619
630
let ty = self . monomorphize ( ty) ;
@@ -651,6 +662,38 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
651
662
) ;
652
663
self . move_size_spans . push ( source_info. span ) ;
653
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
+ }
654
697
}
655
698
656
699
impl < ' a , ' tcx > MirVisitor < ' tcx > for MirUsedCollector < ' a , ' tcx > {
@@ -696,14 +739,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
696
739
) => {
697
740
let fn_ty = operand. ty ( self . body , self . tcx ) ;
698
741
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 ) ;
707
743
}
708
744
mir:: Rvalue :: Cast (
709
745
mir:: CastKind :: PointerCoercion ( PointerCoercion :: ClosureFnPointer ( _) ) ,
@@ -775,17 +811,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
775
811
} ;
776
812
777
813
match terminator. kind {
778
- mir:: TerminatorKind :: Call { ref func, .. } => {
814
+ mir:: TerminatorKind :: Call { ref func, ref args , .. } => {
779
815
let callee_ty = func. ty ( self . body , tcx) ;
780
816
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 )
789
819
}
790
820
mir:: TerminatorKind :: Drop { ref place, .. } => {
791
821
let ty = place. ty ( self . body , self . tcx ) . ty ;
@@ -797,7 +827,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
797
827
match * op {
798
828
mir:: InlineAsmOperand :: SymFn { ref value } => {
799
829
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 ) ;
801
831
}
802
832
mir:: InlineAsmOperand :: SymStatic { def_id } => {
803
833
let instance = Instance :: mono ( self . tcx , def_id) ;
@@ -835,16 +865,14 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
835
865
push_mono_lang_item ( self , reason. lang_item ( ) ) ;
836
866
}
837
867
868
+ self . visiting_call_terminator = matches ! ( terminator. kind, mir:: TerminatorKind :: Call { .. } ) ;
838
869
self . super_terminator ( terminator, location) ;
839
- self . skip_move_size_check = false ;
870
+ self . visiting_call_terminator = false ;
840
871
}
841
872
842
873
fn visit_operand ( & mut self , operand : & mir:: Operand < ' tcx > , location : Location ) {
843
874
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) ;
848
876
}
849
877
850
878
fn visit_local (
@@ -873,11 +901,8 @@ fn visit_fn_use<'tcx>(
873
901
is_direct_call : bool ,
874
902
source : Span ,
875
903
output : & mut MonoItems < ' tcx > ,
876
- skip_move_check_fns : & [ DefId ] ,
877
- ) -> bool {
878
- let mut skip_move_size_check = false ;
904
+ ) {
879
905
if let ty:: FnDef ( def_id, args) = * ty. kind ( ) {
880
- skip_move_size_check = skip_move_check_fns. contains ( & def_id) ;
881
906
let instance = if is_direct_call {
882
907
ty:: Instance :: expect_resolve ( tcx, ty:: ParamEnv :: reveal_all ( ) , def_id, args)
883
908
} else {
@@ -888,7 +913,6 @@ fn visit_fn_use<'tcx>(
888
913
} ;
889
914
visit_instance_use ( tcx, instance, is_direct_call, source, output) ;
890
915
}
891
- skip_move_size_check
892
916
}
893
917
894
918
fn visit_instance_use < ' tcx > (
@@ -1395,6 +1419,29 @@ fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) ->
1395
1419
return None ;
1396
1420
}
1397
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
+
1398
1445
/// Scans the MIR in order to find function calls, closures, and drop-glue.
1399
1446
#[ instrument( skip( tcx, output) , level = "debug" ) ]
1400
1447
fn collect_used_items < ' tcx > (
@@ -1404,28 +1451,6 @@ fn collect_used_items<'tcx>(
1404
1451
) {
1405
1452
let body = tcx. instance_mir ( instance. def ) ;
1406
1453
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
-
1429
1454
// Here we rely on the visitor also visiting `required_consts`, so that we evaluate them
1430
1455
// and abort compilation if any of them errors.
1431
1456
MirUsedCollector {
@@ -1434,8 +1459,8 @@ fn collect_used_items<'tcx>(
1434
1459
output,
1435
1460
instance,
1436
1461
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 ,
1439
1464
}
1440
1465
. visit_body ( & body) ;
1441
1466
}
0 commit comments