@@ -612,8 +612,8 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
612612 }
613613
614614 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 {
617617 return ;
618618 }
619619
@@ -625,48 +625,20 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
625625 return ;
626626 }
627627
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) ;
636628 let source_info = self . body . source_info ( location) ;
637629 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 ) ;
652633 } ;
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 ) ;
664634 }
665635
666636 fn check_fn_args_move_size (
667637 & mut self ,
668638 callee_ty : Ty < ' tcx > ,
669639 args : & [ mir:: Operand < ' tcx > ] ,
640+ arg_spans : & [ Span ] ,
641+ fn_span : Span ,
670642 location : Location ,
671643 ) {
672644 let limit = self . tcx . move_size_limit ( ) ;
@@ -678,6 +650,14 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
678650 return ;
679651 }
680652
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+
681661 // Allow large moves into container types that themselves are cheap to move
682662 let ty:: FnDef ( def_id, _) = * callee_ty. kind ( ) else {
683663 return ;
@@ -690,10 +670,66 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
690670 return ;
691671 }
692672
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+ } ;
695680 }
696681 }
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+ }
697733}
698734
699735impl < ' a , ' tcx > MirVisitor < ' tcx > for MirUsedCollector < ' a , ' tcx > {
@@ -812,11 +848,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
812848
813849 match terminator. kind {
814850 mir:: TerminatorKind :: Call {
815- ref func, ref args, ..
851+ ref func, ref args, ref arg_spans , ref fn_span , ..
816852 } => {
817853 let callee_ty = func. ty ( self . body , tcx) ;
818854 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) ;
820856 visit_fn_use ( self . tcx , callee_ty, true , source, & mut self . output )
821857 }
822858 mir:: TerminatorKind :: Drop { ref place, .. } => {
0 commit comments