Skip to content

Commit 494b75a

Browse files
committed
rustc_monomorphize: Introduce check_fn_args_move_size()
So that we later can improve the accuracy of diagnostics.
1 parent 21da1e6 commit 494b75a

File tree

1 file changed

+72
-57
lines changed

1 file changed

+72
-57
lines changed

compiler/rustc_monomorphize/src/collector.rs

+72-57
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ fn collect_items_rec<'tcx>(
432432
hir::InlineAsmOperand::SymFn { anon_const } => {
433433
let fn_ty =
434434
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);
436436
}
437437
hir::InlineAsmOperand::SymStatic { path: _, def_id } => {
438438
let instance = Instance::mono(tcx, *def_id);
@@ -593,11 +593,7 @@ struct MirUsedCollector<'a, 'tcx> {
593593
instance: Instance<'tcx>,
594594
/// Spans for move size lints already emitted. Helps avoid duplicate lints.
595595
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,
601597
}
602598

603599
impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
@@ -614,14 +610,19 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
614610
}
615611

616612
fn check_operand_move_size(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
617-
if self.skip_move_size_check {
618-
return;
619-
}
620613
let limit = self.tcx.move_size_limit().0;
621614
if limit == 0 {
622615
return;
623616
}
624617

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+
625626
let limit = Size::from_bytes(limit);
626627
let ty = operand.ty(self.body, self.tcx);
627628
let ty = self.monomorphize(ty);
@@ -659,6 +660,59 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
659660
);
660661
self.move_size_spans.push(source_info.span);
661662
}
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+
}
662716
}
663717

664718
impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
@@ -704,14 +758,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
704758
) => {
705759
let fn_ty = operand.ty(self.body, self.tcx);
706760
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);
715762
}
716763
mir::Rvalue::Cast(
717764
mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)),
@@ -783,17 +830,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
783830
};
784831

785832
match terminator.kind {
786-
mir::TerminatorKind::Call { ref func, .. } => {
833+
mir::TerminatorKind::Call { ref func, ref args, .. } => {
787834
let callee_ty = func.ty(self.body, tcx);
788835
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)
797838
}
798839
mir::TerminatorKind::Drop { ref place, .. } => {
799840
let ty = place.ty(self.body, self.tcx).ty;
@@ -805,7 +846,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
805846
match *op {
806847
mir::InlineAsmOperand::SymFn { ref value } => {
807848
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);
809850
}
810851
mir::InlineAsmOperand::SymStatic { def_id } => {
811852
let instance = Instance::mono(self.tcx, def_id);
@@ -843,8 +884,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
843884
push_mono_lang_item(self, reason.lang_item());
844885
}
845886

887+
self.visiting_call_terminator = matches!(terminator.kind, mir::TerminatorKind::Call { .. });
846888
self.super_terminator(terminator, location);
847-
self.skip_move_size_check = false;
889+
self.visiting_call_terminator = false;
848890
}
849891

850892
fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
@@ -878,11 +920,8 @@ fn visit_fn_use<'tcx>(
878920
is_direct_call: bool,
879921
source: Span,
880922
output: &mut MonoItems<'tcx>,
881-
skip_move_check_fns: &[DefId],
882-
) -> bool {
883-
let mut skip_move_size_check = false;
923+
) {
884924
if let ty::FnDef(def_id, args) = *ty.kind() {
885-
skip_move_size_check = skip_move_check_fns.contains(&def_id);
886925
let instance = if is_direct_call {
887926
ty::Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args)
888927
} else {
@@ -893,7 +932,6 @@ fn visit_fn_use<'tcx>(
893932
};
894933
visit_instance_use(tcx, instance, is_direct_call, source, output);
895934
}
896-
skip_move_size_check
897935
}
898936

899937
fn visit_instance_use<'tcx>(
@@ -1409,36 +1447,13 @@ fn collect_used_items<'tcx>(
14091447
) {
14101448
let body = tcx.instance_mir(instance.def);
14111449

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-
14341450
MirUsedCollector {
14351451
tcx,
14361452
body: &body,
14371453
output,
14381454
instance,
14391455
move_size_spans: vec![],
1440-
skip_move_size_check: false,
1441-
skip_move_check_fns,
1456+
visiting_call_terminator: false,
14421457
}
14431458
.visit_body(&body);
14441459
}

0 commit comments

Comments
 (0)