Skip to content

Commit 91db3bd

Browse files
committed
Auto merge of #116310 - Enselic:check_fn_args_move_size, r=oli-obk
rustc_monomorphize: Introduce check_fn_args_move_size() This is in preparation of improving diagnostics of "large moves into functions", a.k.a. passing args. Note: This PR consists of two self-contained commits that can be reviewed independently. For #83518 Also see https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2Fhelp/topic/arg.20Spans.20for.20TerminatorKind.3A.3ACall.3F r? `@oli-obk` who is E-mentor
2 parents 48e2462 + 56e4715 commit 91db3bd

File tree

1 file changed

+83
-58
lines changed

1 file changed

+83
-58
lines changed

compiler/rustc_monomorphize/src/collector.rs

+83-58
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,9 @@ 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,
596+
visiting_call_terminator: bool,
599597
/// 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>>,
601599
}
602600

603601
impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
@@ -613,7 +611,20 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
613611
)
614612
}
615613

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+
617628
let limit = Size::from_bytes(limit);
618629
let ty = operand.ty(self.body, self.tcx);
619630
let ty = self.monomorphize(ty);
@@ -651,6 +662,38 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
651662
);
652663
self.move_size_spans.push(source_info.span);
653664
}
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+
}
654697
}
655698

656699
impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
@@ -696,14 +739,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
696739
) => {
697740
let fn_ty = operand.ty(self.body, self.tcx);
698741
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);
707743
}
708744
mir::Rvalue::Cast(
709745
mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)),
@@ -775,17 +811,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
775811
};
776812

777813
match terminator.kind {
778-
mir::TerminatorKind::Call { ref func, .. } => {
814+
mir::TerminatorKind::Call { ref func, ref args, .. } => {
779815
let callee_ty = func.ty(self.body, tcx);
780816
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)
789819
}
790820
mir::TerminatorKind::Drop { ref place, .. } => {
791821
let ty = place.ty(self.body, self.tcx).ty;
@@ -797,7 +827,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
797827
match *op {
798828
mir::InlineAsmOperand::SymFn { ref value } => {
799829
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);
801831
}
802832
mir::InlineAsmOperand::SymStatic { def_id } => {
803833
let instance = Instance::mono(self.tcx, def_id);
@@ -835,16 +865,14 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
835865
push_mono_lang_item(self, reason.lang_item());
836866
}
837867

868+
self.visiting_call_terminator = matches!(terminator.kind, mir::TerminatorKind::Call { .. });
838869
self.super_terminator(terminator, location);
839-
self.skip_move_size_check = false;
870+
self.visiting_call_terminator = false;
840871
}
841872

842873
fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
843874
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);
848876
}
849877

850878
fn visit_local(
@@ -873,11 +901,8 @@ fn visit_fn_use<'tcx>(
873901
is_direct_call: bool,
874902
source: Span,
875903
output: &mut MonoItems<'tcx>,
876-
skip_move_check_fns: &[DefId],
877-
) -> bool {
878-
let mut skip_move_size_check = false;
904+
) {
879905
if let ty::FnDef(def_id, args) = *ty.kind() {
880-
skip_move_size_check = skip_move_check_fns.contains(&def_id);
881906
let instance = if is_direct_call {
882907
ty::Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args)
883908
} else {
@@ -888,7 +913,6 @@ fn visit_fn_use<'tcx>(
888913
};
889914
visit_instance_use(tcx, instance, is_direct_call, source, output);
890915
}
891-
skip_move_size_check
892916
}
893917

894918
fn visit_instance_use<'tcx>(
@@ -1395,6 +1419,29 @@ fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) ->
13951419
return None;
13961420
}
13971421

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+
13981445
/// Scans the MIR in order to find function calls, closures, and drop-glue.
13991446
#[instrument(skip(tcx, output), level = "debug")]
14001447
fn collect_used_items<'tcx>(
@@ -1404,28 +1451,6 @@ fn collect_used_items<'tcx>(
14041451
) {
14051452
let body = tcx.instance_mir(instance.def);
14061453

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-
14291454
// Here we rely on the visitor also visiting `required_consts`, so that we evaluate them
14301455
// and abort compilation if any of them errors.
14311456
MirUsedCollector {
@@ -1434,8 +1459,8 @@ fn collect_used_items<'tcx>(
14341459
output,
14351460
instance,
14361461
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,
14391464
}
14401465
.visit_body(&body);
14411466
}

0 commit comments

Comments
 (0)