Skip to content

Commit 583b25d

Browse files
committed
Auto merge of #132843 - RalfJung:mono-time-checks, r=lcnr
move all mono-time checks into their own folder, and their own query The mono item collector currently also drives two mono-time checks: the lint for "large moves", and the check whether function calls are done with all the required target features. Instead of doing this "inside" the collector, this PR refactors things so that we have a new `rustc_monomorphize::mono_checks` module providing a per-instance query that does these checks. We already have a per-instance query for the ABI checks, so this should be "free" for incremental builds. Non-incremental builds might do a bit more work now since we now have two separate MIR visits (in the collector and the mono-time checks) -- but one of them is cached in case the MIR doesn't change, which is nice. This slightly changes behavior of the large-move check since the "move_size_spans" deduplication logic now only works per-instance, not globally across the entire collector. Cc `@saethlin` since you're also doing some work related to queries and caching and monomorphization, though I don't know if there's any interaction here.
2 parents 5700240 + 23054c5 commit 583b25d

File tree

6 files changed

+135
-106
lines changed

6 files changed

+135
-106
lines changed

compiler/rustc_middle/src/query/mod.rs

+11-5
Original file line numberDiff line numberDiff line change
@@ -2326,13 +2326,19 @@ rustc_queries! {
23262326
separate_provide_extern
23272327
}
23282328

2329-
/// Check the signature of this function as well as all the call expressions inside of it
2330-
/// to ensure that any target features required by the ABI are enabled.
2331-
/// Should be called on a fully monomorphized instance.
2332-
query check_feature_dependent_abi(key: ty::Instance<'tcx>) {
2333-
desc { "check for feature-dependent ABI" }
2329+
/// Perform monomorphization-time checking on this item.
2330+
/// This is used for lints/errors that can only be checked once the instance is fully
2331+
/// monomorphized.
2332+
query check_mono_item(key: ty::Instance<'tcx>) {
2333+
desc { "monomorphization-time checking" }
23342334
cache_on_disk_if { true }
23352335
}
2336+
2337+
/// Builds the set of functions that should be skipped for the move-size check.
2338+
query skip_move_check_fns(_: ()) -> &'tcx FxIndexSet<DefId> {
2339+
arena_cache
2340+
desc { "functions to skip for move-size check" }
2341+
}
23362342
}
23372343

23382344
rustc_query_append! { define_callbacks! }

compiler/rustc_monomorphize/src/collector.rs

+7-38
Original file line numberDiff line numberDiff line change
@@ -205,13 +205,8 @@
205205
//! this is not implemented however: a mono item will be produced
206206
//! regardless of whether it is actually needed or not.
207207
208-
mod abi_check;
209-
mod move_check;
210-
211208
use std::path::PathBuf;
212209

213-
use move_check::MoveCheckState;
214-
use rustc_abi::Size;
215210
use rustc_data_structures::sync::{LRef, MTLock, par_for_each_in};
216211
use rustc_data_structures::unord::{UnordMap, UnordSet};
217212
use rustc_hir as hir;
@@ -228,15 +223,15 @@ use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCoercion};
228223
use rustc_middle::ty::layout::ValidityRequirement;
229224
use rustc_middle::ty::print::{shrunk_instance_name, with_no_trimmed_paths};
230225
use rustc_middle::ty::{
231-
self, AssocKind, GenericArgs, GenericParamDefKind, Instance, InstanceKind, Ty, TyCtxt,
232-
TypeFoldable, TypeVisitableExt, VtblEntry,
226+
self, GenericArgs, GenericParamDefKind, Instance, InstanceKind, Ty, TyCtxt, TypeFoldable,
227+
TypeVisitableExt, VtblEntry,
233228
};
234229
use rustc_middle::util::Providers;
235230
use rustc_middle::{bug, span_bug};
236231
use rustc_session::Limit;
237232
use rustc_session::config::EntryFnType;
238233
use rustc_span::source_map::{Spanned, dummy_spanned, respan};
239-
use rustc_span::symbol::{Ident, sym};
234+
use rustc_span::symbol::sym;
240235
use rustc_span::{DUMMY_SP, Span};
241236
use tracing::{debug, instrument, trace};
242237

@@ -612,8 +607,6 @@ struct MirUsedCollector<'a, 'tcx> {
612607
/// Note that this contains *not-monomorphized* items!
613608
used_mentioned_items: &'a mut UnordSet<MentionedItem<'tcx>>,
614609
instance: Instance<'tcx>,
615-
visiting_call_terminator: bool,
616-
move_check: move_check::MoveCheckState,
617610
}
618611

619612
impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
@@ -760,13 +753,12 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
760753
};
761754

762755
match terminator.kind {
763-
mir::TerminatorKind::Call { ref func, ref args, ref fn_span, .. }
764-
| mir::TerminatorKind::TailCall { ref func, ref args, ref fn_span } => {
756+
mir::TerminatorKind::Call { ref func, .. }
757+
| mir::TerminatorKind::TailCall { ref func, .. } => {
765758
let callee_ty = func.ty(self.body, tcx);
766759
// *Before* monomorphizing, record that we already handled this mention.
767760
self.used_mentioned_items.insert(MentionedItem::Fn(callee_ty));
768761
let callee_ty = self.monomorphize(callee_ty);
769-
self.check_fn_args_move_size(callee_ty, args, *fn_span, location);
770762
visit_fn_use(self.tcx, callee_ty, true, source, &mut self.used_items)
771763
}
772764
mir::TerminatorKind::Drop { ref place, .. } => {
@@ -826,14 +818,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
826818
push_mono_lang_item(self, reason.lang_item());
827819
}
828820

829-
self.visiting_call_terminator = matches!(terminator.kind, mir::TerminatorKind::Call { .. });
830821
self.super_terminator(terminator, location);
831-
self.visiting_call_terminator = false;
832-
}
833-
834-
fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
835-
self.super_operand(operand, location);
836-
self.check_operand_move_size(operand, location);
837822
}
838823
}
839824

@@ -1183,20 +1168,6 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt
11831168
}
11841169
}
11851170

1186-
fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) -> Option<DefId> {
1187-
for impl_def_id in tcx.inherent_impls(def_id) {
1188-
if let Some(new) = tcx.associated_items(impl_def_id).find_by_name_and_kind(
1189-
tcx,
1190-
fn_ident,
1191-
AssocKind::Fn,
1192-
def_id,
1193-
) {
1194-
return Some(new.def_id);
1195-
}
1196-
}
1197-
None
1198-
}
1199-
12001171
/// Scans the MIR in order to find function calls, closures, and drop-glue.
12011172
///
12021173
/// Anything that's found is added to `output`. Furthermore the "mentioned items" of the MIR are returned.
@@ -1208,7 +1179,8 @@ fn collect_items_of_instance<'tcx>(
12081179
mentioned_items: &mut MonoItems<'tcx>,
12091180
mode: CollectionMode,
12101181
) {
1211-
tcx.ensure().check_feature_dependent_abi(instance);
1182+
// This item is getting monomorphized, do mono-time checks.
1183+
tcx.ensure().check_mono_item(instance);
12121184

12131185
let body = tcx.instance_mir(instance.def);
12141186
// Naively, in "used" collection mode, all functions get added to *both* `used_items` and
@@ -1228,8 +1200,6 @@ fn collect_items_of_instance<'tcx>(
12281200
used_items,
12291201
used_mentioned_items: &mut used_mentioned_items,
12301202
instance,
1231-
visiting_call_terminator: false,
1232-
move_check: MoveCheckState::new(),
12331203
};
12341204

12351205
if mode == CollectionMode::UsedItems {
@@ -1626,5 +1596,4 @@ pub(crate) fn collect_crate_mono_items<'tcx>(
16261596

16271597
pub(crate) fn provide(providers: &mut Providers) {
16281598
providers.hooks.should_codegen_locally = should_codegen_locally;
1629-
abi_check::provide(providers);
16301599
}

compiler/rustc_monomorphize/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use rustc_span::ErrorGuaranteed;
1616

1717
mod collector;
1818
mod errors;
19+
mod mono_checks;
1920
mod partitioning;
2021
mod polymorphize;
2122
mod util;
@@ -47,4 +48,5 @@ fn custom_coerce_unsize_info<'tcx>(
4748
pub fn provide(providers: &mut Providers) {
4849
partitioning::provide(providers);
4950
polymorphize::provide(providers);
51+
mono_checks::provide(providers);
5052
}

compiler/rustc_monomorphize/src/collector/abi_check.rs renamed to compiler/rustc_monomorphize/src/mono_checks/abi_check.rs

+15-29
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
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::visit::Visitor as MirVisitor;
5-
use rustc_middle::mir::{self, Location, traversal};
6-
use rustc_middle::query::Providers;
4+
use rustc_middle::mir::{self, traversal};
75
use rustc_middle::ty::inherent::*;
86
use rustc_middle::ty::{self, Instance, InstanceKind, ParamEnv, Ty, TyCtxt};
97
use rustc_session::lint::builtin::ABI_UNSUPPORTED_VECTOR_TYPES;
@@ -120,43 +118,31 @@ fn check_call_site_abi<'tcx>(
120118
});
121119
}
122120

123-
struct MirCallesAbiCheck<'a, 'tcx> {
124-
tcx: TyCtxt<'tcx>,
125-
body: &'a mir::Body<'tcx>,
126-
instance: Instance<'tcx>,
127-
}
128-
129-
impl<'a, 'tcx> MirVisitor<'tcx> for MirCallesAbiCheck<'a, 'tcx> {
130-
fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, _: Location) {
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();
131125
match terminator.kind {
132126
mir::TerminatorKind::Call { ref func, ref fn_span, .. }
133127
| mir::TerminatorKind::TailCall { ref func, ref fn_span, .. } => {
134-
let callee_ty = func.ty(self.body, self.tcx);
135-
let callee_ty = self.instance.instantiate_mir_and_normalize_erasing_regions(
136-
self.tcx,
128+
let callee_ty = func.ty(body, tcx);
129+
let callee_ty = instance.instantiate_mir_and_normalize_erasing_regions(
130+
tcx,
137131
ty::ParamEnv::reveal_all(),
138132
ty::EarlyBinder::bind(callee_ty),
139133
);
140-
check_call_site_abi(self.tcx, callee_ty, *fn_span, self.body.source.instance);
134+
check_call_site_abi(tcx, callee_ty, *fn_span, body.source.instance);
141135
}
142136
_ => {}
143137
}
144138
}
145139
}
146140

147-
fn check_callees_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
148-
let body = tcx.instance_mir(instance.def);
149-
let mut visitor = MirCallesAbiCheck { tcx, body, instance };
150-
for (bb, data) in traversal::mono_reachable(body, tcx, instance) {
151-
visitor.visit_basic_block_data(bb, data)
152-
}
153-
}
154-
155-
fn check_feature_dependent_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
141+
pub(crate) fn check_feature_dependent_abi<'tcx>(
142+
tcx: TyCtxt<'tcx>,
143+
instance: Instance<'tcx>,
144+
body: &'tcx mir::Body<'tcx>,
145+
) {
156146
check_instance_abi(tcx, instance);
157-
check_callees_abi(tcx, instance);
158-
}
159-
160-
pub(super) fn provide(providers: &mut Providers) {
161-
*providers = Providers { check_feature_dependent_abi, ..*providers }
147+
check_callees_abi(tcx, instance, body);
162148
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//! This implements a single query, `check_mono_fn`, that gets fired for each
2+
//! monomorphization of all functions. This lets us implement monomorphization-time
3+
//! checks in a way that is friendly to incremental compilation.
4+
5+
use rustc_middle::query::Providers;
6+
use rustc_middle::ty::{Instance, TyCtxt};
7+
8+
mod abi_check;
9+
mod move_check;
10+
11+
fn check_mono_item<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
12+
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);
15+
}
16+
17+
pub(super) fn provide(providers: &mut Providers) {
18+
*providers = Providers {
19+
check_mono_item,
20+
skip_move_check_fns: move_check::skip_move_check_fns,
21+
..*providers
22+
}
23+
}

0 commit comments

Comments
 (0)