@@ -612,8 +612,8 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
612
612
}
613
613
614
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 {
615
+ let limit = self . tcx . move_size_limit ( ) ;
616
+ if limit. 0 == 0 {
617
617
return ;
618
618
}
619
619
@@ -625,48 +625,20 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
625
625
return ;
626
626
}
627
627
628
- let limit = Size :: from_bytes ( limit) ;
629
- let ty = operand. ty ( self . body , self . tcx ) ;
630
- let ty = self . monomorphize ( ty) ;
631
- let Ok ( layout) = self . tcx . layout_of ( ty:: ParamEnv :: reveal_all ( ) . and ( ty) ) else { return } ;
632
- if layout. size <= limit {
633
- return ;
634
- }
635
- debug ! ( ?layout) ;
636
628
let source_info = self . body . source_info ( location) ;
637
629
debug ! ( ?source_info) ;
638
- for span in & self . move_size_spans {
639
- if span. overlaps ( source_info. span ) {
640
- return ;
641
- }
642
- }
643
- let lint_root = source_info. scope . lint_root ( & self . body . source_scopes ) ;
644
- debug ! ( ?lint_root) ;
645
- let Some ( lint_root) = lint_root else {
646
- // This happens when the issue is in a function from a foreign crate that
647
- // we monomorphized in the current crate. We can't get a `HirId` for things
648
- // in other crates.
649
- // FIXME: Find out where to report the lint on. Maybe simply crate-level lint root
650
- // but correct span? This would make the lint at least accept crate-level lint attributes.
651
- return ;
630
+
631
+ if let Some ( too_large_size) = self . operand_size_if_too_large ( limit, operand) {
632
+ self . lint_large_assignment ( limit. 0 , too_large_size, location, source_info. span ) ;
652
633
} ;
653
- self . tcx . emit_spanned_lint (
654
- LARGE_ASSIGNMENTS ,
655
- lint_root,
656
- source_info. span ,
657
- LargeAssignmentsLint {
658
- span : source_info. span ,
659
- size : layout. size . bytes ( ) ,
660
- limit : limit. bytes ( ) ,
661
- } ,
662
- ) ;
663
- self . move_size_spans . push ( source_info. span ) ;
664
634
}
665
635
666
636
fn check_fn_args_move_size (
667
637
& mut self ,
668
638
callee_ty : Ty < ' tcx > ,
669
639
args : & [ mir:: Operand < ' tcx > ] ,
640
+ arg_spans : & [ Span ] ,
641
+ fn_span : Span ,
670
642
location : Location ,
671
643
) {
672
644
let limit = self . tcx . move_size_limit ( ) ;
@@ -678,6 +650,14 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
678
650
return ;
679
651
}
680
652
653
+ // Not exactly sure yet how these can get out of sync? Maybe has to do
654
+ // with bootstrapping and staged builds? If things are in sync, we
655
+ // should be able to expect args and arg_spans to always have the same
656
+ // length. Could also be a bug in lowering...
657
+ if args. len ( ) != arg_spans. len ( ) {
658
+ return ;
659
+ }
660
+
681
661
// Allow large moves into container types that themselves are cheap to move
682
662
let ty:: FnDef ( def_id, _) = * callee_ty. kind ( ) else {
683
663
return ;
@@ -690,10 +670,66 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
690
670
return ;
691
671
}
692
672
693
- for arg in args {
694
- self . check_operand_move_size ( arg, location) ;
673
+ debug ! ( ?def_id, ?fn_span) ;
674
+ assert_eq ! ( args. len( ) , arg_spans. len( ) ) ;
675
+
676
+ for ( idx, arg) in args. iter ( ) . enumerate ( ) {
677
+ if let Some ( too_large_size) = self . operand_size_if_too_large ( limit, arg) {
678
+ self . lint_large_assignment ( limit. 0 , too_large_size, location, arg_spans[ idx] ) ;
679
+ } ;
695
680
}
696
681
}
682
+
683
+ fn operand_size_if_too_large (
684
+ & mut self ,
685
+ limit : Limit ,
686
+ operand : & mir:: Operand < ' tcx > ,
687
+ ) -> Option < Size > {
688
+ let ty = operand. ty ( self . body , self . tcx ) ;
689
+ let ty = self . monomorphize ( ty) ;
690
+ let Ok ( layout) = self . tcx . layout_of ( ty:: ParamEnv :: reveal_all ( ) . and ( ty) ) else {
691
+ return None ;
692
+ } ;
693
+ if layout. size . bytes_usize ( ) > limit. 0 {
694
+ debug ! ( ?layout) ;
695
+ Some ( layout. size )
696
+ } else {
697
+ None
698
+ }
699
+ }
700
+
701
+ fn lint_large_assignment (
702
+ & mut self ,
703
+ limit : usize ,
704
+ too_large_size : Size ,
705
+ location : Location ,
706
+ span : Span ,
707
+ ) {
708
+ let source_info = self . body . source_info ( location) ;
709
+ debug ! ( ?source_info) ;
710
+ for reported_span in & self . move_size_spans {
711
+ if reported_span. overlaps ( span) {
712
+ return ;
713
+ }
714
+ }
715
+ let lint_root = source_info. scope . lint_root ( & self . body . source_scopes ) ;
716
+ debug ! ( ?lint_root) ;
717
+ let Some ( lint_root) = lint_root else {
718
+ // This happens when the issue is in a function from a foreign crate that
719
+ // we monomorphized in the current crate. We can't get a `HirId` for things
720
+ // in other crates.
721
+ // FIXME: Find out where to report the lint on. Maybe simply crate-level lint root
722
+ // but correct span? This would make the lint at least accept crate-level lint attributes.
723
+ return ;
724
+ } ;
725
+ self . tcx . emit_spanned_lint (
726
+ LARGE_ASSIGNMENTS ,
727
+ lint_root,
728
+ span,
729
+ LargeAssignmentsLint { span, size : too_large_size. bytes ( ) , limit : limit as u64 } ,
730
+ ) ;
731
+ self . move_size_spans . push ( span) ;
732
+ }
697
733
}
698
734
699
735
impl < ' a , ' tcx > MirVisitor < ' tcx > for MirUsedCollector < ' a , ' tcx > {
@@ -812,11 +848,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
812
848
813
849
match terminator. kind {
814
850
mir:: TerminatorKind :: Call {
815
- ref func, ref args, ..
851
+ ref func, ref args, ref arg_spans , ref fn_span , ..
816
852
} => {
817
853
let callee_ty = func. ty ( self . body , tcx) ;
818
854
let callee_ty = self . monomorphize ( callee_ty) ;
819
- self . check_fn_args_move_size ( callee_ty, args, location) ;
855
+ self . check_fn_args_move_size ( callee_ty, args, arg_spans , * fn_span , location) ;
820
856
visit_fn_use ( self . tcx , callee_ty, true , source, & mut self . output )
821
857
}
822
858
mir:: TerminatorKind :: Drop { ref place, .. } => {
0 commit comments