Skip to content

Commit f25b73b

Browse files
committed
mono_checks: merge the two traversals into one
1 parent 23054c5 commit f25b73b

File tree

3 files changed

+92
-91
lines changed

3 files changed

+92
-91
lines changed

compiler/rustc_monomorphize/src/mono_checks/abi_check.rs

+2-32
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//! This module ensures that if a function's ABI requires a particular target feature,
22
//! that target feature is enabled both on the callee and all callers.
33
use rustc_hir::CRATE_HIR_ID;
4-
use rustc_middle::mir::{self, traversal};
54
use rustc_middle::ty::inherent::*;
65
use rustc_middle::ty::{self, Instance, InstanceKind, ParamEnv, Ty, TyCtxt};
76
use rustc_session::lint::builtin::ABI_UNSUPPORTED_VECTOR_TYPES;
@@ -56,7 +55,7 @@ fn do_check_abi<'tcx>(
5655

5756
/// Checks that the ABI of a given instance of a function does not contain vector-passed arguments
5857
/// or return values for which the corresponding target feature is not enabled.
59-
fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
58+
pub(super) fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
6059
let param_env = ParamEnv::reveal_all();
6160
let Ok(abi) = tcx.fn_abi_of_instance(param_env.and((instance, ty::List::empty()))) else {
6261
// An error will be reported during codegen if we cannot determine the ABI of this
@@ -76,7 +75,7 @@ fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
7675

7776
/// Checks that a call expression does not try to pass a vector-passed argument which requires a
7877
/// target feature that the caller does not have, as doing so causes UB because of ABI mismatch.
79-
fn check_call_site_abi<'tcx>(
78+
pub(super) fn check_call_site_abi<'tcx>(
8079
tcx: TyCtxt<'tcx>,
8180
callee: Ty<'tcx>,
8281
span: Span,
@@ -117,32 +116,3 @@ fn check_call_site_abi<'tcx>(
117116
);
118117
});
119118
}
120-
121-
fn check_callees_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, body: &mir::Body<'tcx>) {
122-
// Check all function call terminators.
123-
for (bb, _data) in traversal::mono_reachable(body, tcx, instance) {
124-
let terminator = body.basic_blocks[bb].terminator();
125-
match terminator.kind {
126-
mir::TerminatorKind::Call { ref func, ref fn_span, .. }
127-
| mir::TerminatorKind::TailCall { ref func, ref fn_span, .. } => {
128-
let callee_ty = func.ty(body, tcx);
129-
let callee_ty = instance.instantiate_mir_and_normalize_erasing_regions(
130-
tcx,
131-
ty::ParamEnv::reveal_all(),
132-
ty::EarlyBinder::bind(callee_ty),
133-
);
134-
check_call_site_abi(tcx, callee_ty, *fn_span, body.source.instance);
135-
}
136-
_ => {}
137-
}
138-
}
139-
}
140-
141-
pub(crate) fn check_feature_dependent_abi<'tcx>(
142-
tcx: TyCtxt<'tcx>,
143-
instance: Instance<'tcx>,
144-
body: &'tcx mir::Body<'tcx>,
145-
) {
146-
check_instance_abi(tcx, instance);
147-
check_callees_abi(tcx, instance, body);
148-
}

compiler/rustc_monomorphize/src/mono_checks/mod.rs

+68-3
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,81 @@
22
//! monomorphization of all functions. This lets us implement monomorphization-time
33
//! checks in a way that is friendly to incremental compilation.
44
5+
use rustc_middle::mir::visit::Visitor as MirVisitor;
6+
use rustc_middle::mir::{self, Location, traversal};
57
use rustc_middle::query::Providers;
6-
use rustc_middle::ty::{Instance, TyCtxt};
8+
use rustc_middle::ty::{self, Instance, TyCtxt, TypeFoldable};
79

810
mod abi_check;
911
mod move_check;
1012

13+
struct MonoCheckVisitor<'tcx> {
14+
tcx: TyCtxt<'tcx>,
15+
instance: Instance<'tcx>,
16+
body: &'tcx mir::Body<'tcx>,
17+
move_check: move_check::State,
18+
visiting_call_terminator: bool,
19+
}
20+
21+
impl<'tcx> MirVisitor<'tcx> for MonoCheckVisitor<'tcx> {
22+
fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
23+
match terminator.kind {
24+
mir::TerminatorKind::Call { ref func, ref args, ref fn_span, .. }
25+
| mir::TerminatorKind::TailCall { ref func, ref args, ref fn_span } => {
26+
let callee_ty = func.ty(self.body, self.tcx);
27+
let callee_ty = self.monomorphize(callee_ty);
28+
29+
abi_check::check_call_site_abi(
30+
self.tcx,
31+
callee_ty,
32+
*fn_span,
33+
self.body.source.instance,
34+
);
35+
self.check_fn_args_move_size(callee_ty, args, *fn_span, location);
36+
37+
self.visiting_call_terminator = true;
38+
}
39+
_ => {
40+
debug_assert!(!self.visiting_call_terminator);
41+
}
42+
}
43+
44+
self.super_terminator(terminator, location);
45+
self.visiting_call_terminator = false;
46+
}
47+
48+
fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
49+
self.check_operand_move_size(operand, location);
50+
}
51+
}
52+
53+
impl<'tcx> MonoCheckVisitor<'tcx> {
54+
fn monomorphize<T>(&self, value: T) -> T
55+
where
56+
T: TypeFoldable<TyCtxt<'tcx>>,
57+
{
58+
self.instance.instantiate_mir_and_normalize_erasing_regions(
59+
self.tcx,
60+
ty::ParamEnv::reveal_all(),
61+
ty::EarlyBinder::bind(value),
62+
)
63+
}
64+
}
65+
1166
fn check_mono_item<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
67+
abi_check::check_instance_abi(tcx, instance);
68+
1269
let body = tcx.instance_mir(instance.def);
13-
abi_check::check_feature_dependent_abi(tcx, instance, body);
14-
move_check::check_moves(tcx, instance, body);
70+
let mut visitor = MonoCheckVisitor {
71+
tcx,
72+
instance,
73+
body,
74+
move_check: Default::default(),
75+
visiting_call_terminator: false,
76+
};
77+
for (bb, data) in traversal::mono_reachable(body, tcx, instance) {
78+
visitor.visit_basic_block_data(bb, data)
79+
}
1580
}
1681

1782
pub(super) fn provide(providers: &mut Providers) {

compiler/rustc_monomorphize/src/mono_checks/move_check.rs

+22-56
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,43 @@
11
use rustc_abi::Size;
22
use rustc_data_structures::fx::FxIndexSet;
33
use rustc_hir::def_id::DefId;
4-
use rustc_middle::mir::visit::Visitor as MirVisitor;
5-
use rustc_middle::mir::{self, Location, traversal};
6-
use rustc_middle::ty::{self, AssocKind, Instance, Ty, TyCtxt, TypeFoldable};
4+
use rustc_middle::mir::{self, Location};
5+
use rustc_middle::ty::{self, AssocKind, Ty, TyCtxt};
76
use rustc_session::Limit;
87
use rustc_session::lint::builtin::LARGE_ASSIGNMENTS;
98
use rustc_span::Span;
109
use rustc_span::source_map::Spanned;
1110
use rustc_span::symbol::{Ident, sym};
12-
use tracing::{debug, trace};
11+
use tracing::debug;
1312

13+
use super::MonoCheckVisitor;
1414
use crate::errors::LargeAssignmentsLint;
1515

16-
struct MoveCheckVisitor<'tcx> {
17-
tcx: TyCtxt<'tcx>,
18-
instance: Instance<'tcx>,
19-
body: &'tcx mir::Body<'tcx>,
16+
#[derive(Default)]
17+
pub(super) struct State {
2018
/// Spans for move size lints already emitted. Helps avoid duplicate lints.
2119
move_size_spans: Vec<Span>,
2220
}
2321

24-
pub(crate) fn check_moves<'tcx>(
25-
tcx: TyCtxt<'tcx>,
26-
instance: Instance<'tcx>,
27-
body: &'tcx mir::Body<'tcx>,
28-
) {
29-
let mut visitor = MoveCheckVisitor { tcx, instance, body, move_size_spans: vec![] };
30-
for (bb, data) in traversal::mono_reachable(body, tcx, instance) {
31-
visitor.visit_basic_block_data(bb, data)
32-
}
33-
}
34-
35-
impl<'tcx> MirVisitor<'tcx> for MoveCheckVisitor<'tcx> {
36-
fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
37-
match terminator.kind {
38-
mir::TerminatorKind::Call { ref func, ref args, ref fn_span, .. }
39-
| mir::TerminatorKind::TailCall { ref func, ref args, ref fn_span } => {
40-
let callee_ty = func.ty(self.body, self.tcx);
41-
let callee_ty = self.monomorphize(callee_ty);
42-
self.check_fn_args_move_size(callee_ty, args, *fn_span, location);
43-
}
44-
_ => {}
45-
}
46-
47-
// We deliberately do *not* visit the nested operands here, to avoid
48-
// hitting `visit_operand` for function arguments.
49-
}
50-
51-
fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
52-
self.check_operand_move_size(operand, location);
53-
}
54-
}
55-
56-
impl<'tcx> MoveCheckVisitor<'tcx> {
57-
fn monomorphize<T>(&self, value: T) -> T
58-
where
59-
T: TypeFoldable<TyCtxt<'tcx>>,
60-
{
61-
trace!("monomorphize: self.instance={:?}", self.instance);
62-
self.instance.instantiate_mir_and_normalize_erasing_regions(
63-
self.tcx,
64-
ty::ParamEnv::reveal_all(),
65-
ty::EarlyBinder::bind(value),
66-
)
67-
}
68-
69-
fn check_operand_move_size(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
22+
impl<'tcx> MonoCheckVisitor<'tcx> {
23+
pub(super) fn check_operand_move_size(
24+
&mut self,
25+
operand: &mir::Operand<'tcx>,
26+
location: Location,
27+
) {
7028
let limit = self.tcx.move_size_limit();
7129
if limit.0 == 0 {
7230
return;
7331
}
7432

33+
// This function is called by visit_operand() which visits _all_
34+
// operands, including TerminatorKind::Call operands. But if
35+
// check_fn_args_move_size() has been called, the operands have already
36+
// been visited. Do not visit them again.
37+
if self.visiting_call_terminator {
38+
return;
39+
}
40+
7541
let source_info = self.body.source_info(location);
7642
debug!(?source_info);
7743

@@ -147,7 +113,7 @@ impl<'tcx> MoveCheckVisitor<'tcx> {
147113
span: Span,
148114
) {
149115
let source_info = self.body.source_info(location);
150-
for reported_span in &self.move_size_spans {
116+
for reported_span in &self.move_check.move_size_spans {
151117
if reported_span.overlaps(span) {
152118
return;
153119
}
@@ -166,7 +132,7 @@ impl<'tcx> MoveCheckVisitor<'tcx> {
166132
size: too_large_size.bytes(),
167133
limit: limit as u64,
168134
});
169-
self.move_size_spans.push(span);
135+
self.move_check.move_size_spans.push(span);
170136
}
171137
}
172138

0 commit comments

Comments
 (0)