Skip to content

Commit

Permalink
move all mono-time checks into their own folder, and their own query
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Nov 10, 2024
1 parent 6689597 commit 23054c5
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 106 deletions.
16 changes: 11 additions & 5 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2326,13 +2326,19 @@ rustc_queries! {
separate_provide_extern
}

/// Check the signature of this function as well as all the call expressions inside of it
/// to ensure that any target features required by the ABI are enabled.
/// Should be called on a fully monomorphized instance.
query check_feature_dependent_abi(key: ty::Instance<'tcx>) {
desc { "check for feature-dependent ABI" }
/// Perform monomorphization-time checking on this item.
/// This is used for lints/errors that can only be checked once the instance is fully
/// monomorphized.
query check_mono_item(key: ty::Instance<'tcx>) {
desc { "monomorphization-time checking" }
cache_on_disk_if { true }
}

/// Builds the set of functions that should be skipped for the move-size check.
query skip_move_check_fns(_: ()) -> &'tcx FxIndexSet<DefId> {
arena_cache
desc { "functions to skip for move-size check" }
}
}

rustc_query_append! { define_callbacks! }
Expand Down
45 changes: 7 additions & 38 deletions compiler/rustc_monomorphize/src/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,13 +205,8 @@
//! this is not implemented however: a mono item will be produced
//! regardless of whether it is actually needed or not.
mod abi_check;
mod move_check;

use std::path::PathBuf;

use move_check::MoveCheckState;
use rustc_abi::Size;
use rustc_data_structures::sync::{LRef, MTLock, par_for_each_in};
use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_hir as hir;
Expand All @@ -228,15 +223,15 @@ use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCoercion};
use rustc_middle::ty::layout::ValidityRequirement;
use rustc_middle::ty::print::{shrunk_instance_name, with_no_trimmed_paths};
use rustc_middle::ty::{
self, AssocKind, GenericArgs, GenericParamDefKind, Instance, InstanceKind, Ty, TyCtxt,
TypeFoldable, TypeVisitableExt, VtblEntry,
self, GenericArgs, GenericParamDefKind, Instance, InstanceKind, Ty, TyCtxt, TypeFoldable,
TypeVisitableExt, VtblEntry,
};
use rustc_middle::util::Providers;
use rustc_middle::{bug, span_bug};
use rustc_session::Limit;
use rustc_session::config::EntryFnType;
use rustc_span::source_map::{Spanned, dummy_spanned, respan};
use rustc_span::symbol::{Ident, sym};
use rustc_span::symbol::sym;
use rustc_span::{DUMMY_SP, Span};
use tracing::{debug, instrument, trace};

Expand Down Expand Up @@ -612,8 +607,6 @@ struct MirUsedCollector<'a, 'tcx> {
/// Note that this contains *not-monomorphized* items!
used_mentioned_items: &'a mut UnordSet<MentionedItem<'tcx>>,
instance: Instance<'tcx>,
visiting_call_terminator: bool,
move_check: move_check::MoveCheckState,
}

impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
Expand Down Expand Up @@ -760,13 +753,12 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
};

match terminator.kind {
mir::TerminatorKind::Call { ref func, ref args, ref fn_span, .. }
| mir::TerminatorKind::TailCall { ref func, ref args, ref fn_span } => {
mir::TerminatorKind::Call { ref func, .. }
| mir::TerminatorKind::TailCall { ref func, .. } => {
let callee_ty = func.ty(self.body, tcx);
// *Before* monomorphizing, record that we already handled this mention.
self.used_mentioned_items.insert(MentionedItem::Fn(callee_ty));
let callee_ty = self.monomorphize(callee_ty);
self.check_fn_args_move_size(callee_ty, args, *fn_span, location);
visit_fn_use(self.tcx, callee_ty, true, source, &mut self.used_items)
}
mir::TerminatorKind::Drop { ref place, .. } => {
Expand Down Expand Up @@ -826,14 +818,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
push_mono_lang_item(self, reason.lang_item());
}

self.visiting_call_terminator = matches!(terminator.kind, mir::TerminatorKind::Call { .. });
self.super_terminator(terminator, location);
self.visiting_call_terminator = false;
}

fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
self.super_operand(operand, location);
self.check_operand_move_size(operand, location);
}
}

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

fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) -> Option<DefId> {
for impl_def_id in tcx.inherent_impls(def_id) {
if let Some(new) = tcx.associated_items(impl_def_id).find_by_name_and_kind(
tcx,
fn_ident,
AssocKind::Fn,
def_id,
) {
return Some(new.def_id);
}
}
None
}

/// Scans the MIR in order to find function calls, closures, and drop-glue.
///
/// Anything that's found is added to `output`. Furthermore the "mentioned items" of the MIR are returned.
Expand All @@ -1208,7 +1179,8 @@ fn collect_items_of_instance<'tcx>(
mentioned_items: &mut MonoItems<'tcx>,
mode: CollectionMode,
) {
tcx.ensure().check_feature_dependent_abi(instance);
// This item is getting monomorphized, do mono-time checks.
tcx.ensure().check_mono_item(instance);

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

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

pub(crate) fn provide(providers: &mut Providers) {
providers.hooks.should_codegen_locally = should_codegen_locally;
abi_check::provide(providers);
}
2 changes: 2 additions & 0 deletions compiler/rustc_monomorphize/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use rustc_span::ErrorGuaranteed;

mod collector;
mod errors;
mod mono_checks;
mod partitioning;
mod polymorphize;
mod util;
Expand Down Expand Up @@ -47,4 +48,5 @@ fn custom_coerce_unsize_info<'tcx>(
pub fn provide(providers: &mut Providers) {
partitioning::provide(providers);
polymorphize::provide(providers);
mono_checks::provide(providers);
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
//! This module ensures that if a function's ABI requires a particular target feature,
//! that target feature is enabled both on the callee and all callers.
use rustc_hir::CRATE_HIR_ID;
use rustc_middle::mir::visit::Visitor as MirVisitor;
use rustc_middle::mir::{self, Location, traversal};
use rustc_middle::query::Providers;
use rustc_middle::mir::{self, traversal};
use rustc_middle::ty::inherent::*;
use rustc_middle::ty::{self, Instance, InstanceKind, ParamEnv, Ty, TyCtxt};
use rustc_session::lint::builtin::ABI_UNSUPPORTED_VECTOR_TYPES;
Expand Down Expand Up @@ -120,43 +118,31 @@ fn check_call_site_abi<'tcx>(
});
}

struct MirCallesAbiCheck<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
body: &'a mir::Body<'tcx>,
instance: Instance<'tcx>,
}

impl<'a, 'tcx> MirVisitor<'tcx> for MirCallesAbiCheck<'a, 'tcx> {
fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, _: Location) {
fn check_callees_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, body: &mir::Body<'tcx>) {
// Check all function call terminators.
for (bb, _data) in traversal::mono_reachable(body, tcx, instance) {
let terminator = body.basic_blocks[bb].terminator();
match terminator.kind {
mir::TerminatorKind::Call { ref func, ref fn_span, .. }
| mir::TerminatorKind::TailCall { ref func, ref fn_span, .. } => {
let callee_ty = func.ty(self.body, self.tcx);
let callee_ty = self.instance.instantiate_mir_and_normalize_erasing_regions(
self.tcx,
let callee_ty = func.ty(body, tcx);
let callee_ty = instance.instantiate_mir_and_normalize_erasing_regions(
tcx,
ty::ParamEnv::reveal_all(),
ty::EarlyBinder::bind(callee_ty),
);
check_call_site_abi(self.tcx, callee_ty, *fn_span, self.body.source.instance);
check_call_site_abi(tcx, callee_ty, *fn_span, body.source.instance);
}
_ => {}
}
}
}

fn check_callees_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
let body = tcx.instance_mir(instance.def);
let mut visitor = MirCallesAbiCheck { tcx, body, instance };
for (bb, data) in traversal::mono_reachable(body, tcx, instance) {
visitor.visit_basic_block_data(bb, data)
}
}

fn check_feature_dependent_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
pub(crate) fn check_feature_dependent_abi<'tcx>(
tcx: TyCtxt<'tcx>,
instance: Instance<'tcx>,
body: &'tcx mir::Body<'tcx>,
) {
check_instance_abi(tcx, instance);
check_callees_abi(tcx, instance);
}

pub(super) fn provide(providers: &mut Providers) {
*providers = Providers { check_feature_dependent_abi, ..*providers }
check_callees_abi(tcx, instance, body);
}
23 changes: 23 additions & 0 deletions compiler/rustc_monomorphize/src/mono_checks/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//! This implements a single query, `check_mono_fn`, that gets fired for each
//! monomorphization of all functions. This lets us implement monomorphization-time
//! checks in a way that is friendly to incremental compilation.
use rustc_middle::query::Providers;
use rustc_middle::ty::{Instance, TyCtxt};

mod abi_check;
mod move_check;

fn check_mono_item<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
let body = tcx.instance_mir(instance.def);
abi_check::check_feature_dependent_abi(tcx, instance, body);
move_check::check_moves(tcx, instance, body);
}

pub(super) fn provide(providers: &mut Providers) {
*providers = Providers {
check_mono_item,
skip_move_check_fns: move_check::skip_move_check_fns,
..*providers
}
}
Loading

0 comments on commit 23054c5

Please sign in to comment.