Skip to content

Warn about invalid mir-enable-passes pass names #132901

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compiler/rustc_mir_transform/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,5 @@ mir_transform_undefined_transmute = pointers cannot be transmuted to integers du
.note = at compile-time, pointers do not have an integer value
.note2 = avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
.help = for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html

mir_transform_unknown_pass_name = MIR pass `{$name}` is unknown and will be ignored
6 changes: 6 additions & 0 deletions compiler/rustc_mir_transform/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ pub(crate) struct UnalignedPackedRef {
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(mir_transform_unknown_pass_name)]
pub(crate) struct UnknownPassName<'a> {
pub(crate) name: &'a str,
}

pub(crate) struct AssertLint<P> {
pub span: Span,
pub assert_kind: AssertKind<P>,
Expand Down
203 changes: 142 additions & 61 deletions compiler/rustc_mir_transform/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,77 +40,158 @@ use tracing::{debug, trace};
#[macro_use]
mod pass_manager;

use std::sync::LazyLock;

use pass_manager::{self as pm, Lint, MirLint, MirPass, WithMinOptLevel};

mod abort_unwinding_calls;
mod add_call_guards;
mod add_moves_for_packed_drops;
mod add_retag;
mod add_subtyping_projections;
mod check_alignment;
mod check_const_item_mutation;
mod check_packed_ref;
mod check_undefined_transmutes;
// This pass is public to allow external drivers to perform MIR cleanup
pub mod cleanup_post_borrowck;
mod copy_prop;
mod coroutine;
mod cost_checker;
mod coverage;
mod cross_crate_inline;
mod ctfe_limit;
mod dataflow_const_prop;
mod dead_store_elimination;
mod deduce_param_attrs;
mod deduplicate_blocks;
mod deref_separator;
mod dest_prop;
pub mod dump_mir;
mod early_otherwise_branch;
mod elaborate_box_derefs;
mod elaborate_drops;
mod errors;
mod ffi_unwind_calls;
mod function_item_references;
mod gvn;
// Made public so that `mir_drops_elaborated_and_const_checked` can be overridden
// by custom rustc drivers, running all the steps by themselves. See #114628.
pub mod inline;
mod instsimplify;
mod jump_threading;
mod known_panics_lint;
mod large_enums;
mod lint;
mod lower_intrinsics;
mod lower_slice_len;
mod match_branches;
mod mentioned_items;
mod multiple_return_terminators;
mod nrvo;
mod post_drop_elaboration;
mod prettify;
mod promote_consts;
mod ref_prop;
mod remove_noop_landing_pads;
mod remove_place_mention;
mod remove_storage_markers;
mod remove_uninit_drops;
mod remove_unneeded_drops;
mod remove_zsts;
mod required_consts;
mod reveal_all;
mod sanity_check;
mod shim;
mod ssa;
// This pass is public to allow external drivers to perform MIR cleanup
pub mod simplify;
mod simplify_branches;
mod simplify_comparison_integral;
mod single_use_consts;
mod sroa;
mod unreachable_enum_branching;
mod unreachable_prop;
mod validate;

/// We import passes via this macro so that we can have a static list of pass names
/// (used to verify CLI arguments). It takes a list of modules, followed by the passes
/// declared within them.
/// ```ignore,macro-test
/// declare_passes! {
/// // Declare a single pass from the module `abort_unwinding_calls`
/// mod abort_unwinding_calls : AbortUnwindingCalls;
/// // When passes are grouped together as an enum, declare the two constituent passes
/// mod add_call_guards : AddCallGuards {
/// AllCallEdges,
/// CriticalCallEdges
/// };
/// // Declares multiple pass groups, each containing their own constituent passes
/// mod simplify : SimplifyCfg {
/// Initial,
/// /* omitted */
/// }, SimplifyLocals {
/// BeforeConstProp,
/// /* omitted */
/// };
/// }
/// ```
macro_rules! declare_passes {
(
$(
$vis:vis mod $mod_name:ident : $($pass_name:ident $( { $($ident:ident),* } )?),+ $(,)?;
)*
) => {
$(
$vis mod $mod_name;
$(
// Make sure the type name is correct
#[allow(unused_imports)]
use $mod_name::$pass_name as _;
)+
)*

static PASS_NAMES: LazyLock<FxIndexSet<&str>> = LazyLock::new(|| [
// Fake marker pass
"PreCodegen",
$(
$(
stringify!($pass_name),
$(
$(
$mod_name::$pass_name::$ident.name(),
)*
)?
)+
)*
].into_iter().collect());
};
}

declare_passes! {
mod abort_unwinding_calls : AbortUnwindingCalls;
mod add_call_guards : AddCallGuards { AllCallEdges, CriticalCallEdges };
mod add_moves_for_packed_drops : AddMovesForPackedDrops;
mod add_retag : AddRetag;
mod add_subtyping_projections : Subtyper;
mod check_alignment : CheckAlignment;
mod check_const_item_mutation : CheckConstItemMutation;
mod check_packed_ref : CheckPackedRef;
mod check_undefined_transmutes : CheckUndefinedTransmutes;
// This pass is public to allow external drivers to perform MIR cleanup
pub mod cleanup_post_borrowck : CleanupPostBorrowck;

mod copy_prop : CopyProp;
mod coroutine : StateTransform;
mod coverage : InstrumentCoverage;
mod ctfe_limit : CtfeLimit;
mod dataflow_const_prop : DataflowConstProp;
mod dead_store_elimination : DeadStoreElimination {
Initial,
Final
};
mod deduplicate_blocks : DeduplicateBlocks;
mod deref_separator : Derefer;
mod dest_prop : DestinationPropagation;
pub mod dump_mir : Marker;
mod early_otherwise_branch : EarlyOtherwiseBranch;
mod elaborate_box_derefs : ElaborateBoxDerefs;
mod elaborate_drops : ElaborateDrops;
mod function_item_references : FunctionItemReferences;
mod gvn : GVN;
// Made public so that `mir_drops_elaborated_and_const_checked` can be overridden
// by custom rustc drivers, running all the steps by themselves. See #114628.
pub mod inline : Inline;
mod instsimplify : InstSimplify { BeforeInline, AfterSimplifyCfg };
mod jump_threading : JumpThreading;
mod known_panics_lint : KnownPanicsLint;
mod large_enums : EnumSizeOpt;
mod lower_intrinsics : LowerIntrinsics;
mod lower_slice_len : LowerSliceLenCalls;
mod match_branches : MatchBranchSimplification;
mod mentioned_items : MentionedItems;
mod multiple_return_terminators : MultipleReturnTerminators;
mod nrvo : RenameReturnPlace;
mod post_drop_elaboration : CheckLiveDrops;
mod prettify : ReorderBasicBlocks, ReorderLocals;
mod promote_consts : PromoteTemps;
mod ref_prop : ReferencePropagation;
mod remove_noop_landing_pads : RemoveNoopLandingPads;
mod remove_place_mention : RemovePlaceMention;
mod remove_storage_markers : RemoveStorageMarkers;
mod remove_uninit_drops : RemoveUninitDrops;
mod remove_unneeded_drops : RemoveUnneededDrops;
mod remove_zsts : RemoveZsts;
mod required_consts : RequiredConstsVisitor;
mod reveal_all : RevealAll;
mod sanity_check : SanityCheck;
// This pass is public to allow external drivers to perform MIR cleanup
pub mod simplify :
SimplifyCfg {
Initial,
PromoteConsts,
RemoveFalseEdges,
PostAnalysis,
PreOptimizations,
Final,
MakeShim,
AfterUnreachableEnumBranching
},
SimplifyLocals {
BeforeConstProp,
AfterGVN,
Final
};
mod simplify_branches : SimplifyConstCondition {
AfterConstProp,
Final
};
mod simplify_comparison_integral : SimplifyComparisonIntegral;
mod single_use_consts : SingleUseConsts;
mod sroa : ScalarReplacementOfAggregates;
mod unreachable_enum_branching : UnreachableEnumBranching;
mod unreachable_prop : UnreachablePropagation;
mod validate : Validator;
}

rustc_fluent_macro::fluent_messages! { "../messages.ftl" }

Expand Down
34 changes: 30 additions & 4 deletions compiler/rustc_mir_transform/src/pass_manager.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
use std::cell::RefCell;
use std::collections::hash_map::Entry;

use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_middle::mir::{self, Body, MirPhase, RuntimePhase};
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
use tracing::trace;

use crate::lint::lint_body;
use crate::validate;
use crate::{errors, validate};

thread_local! {
static PASS_NAMES: RefCell<FxHashMap<&'static str, &'static str>> = {
/// Maps MIR pass names to a snake case form to match profiling naming style
static PASS_TO_PROFILER_NAMES: RefCell<FxHashMap<&'static str, &'static str>> = {
RefCell::new(FxHashMap::default())
};
}

/// Converts a MIR pass name into a snake case form to match the profiling naming style.
fn to_profiler_name(type_name: &'static str) -> &'static str {
PASS_NAMES.with(|names| match names.borrow_mut().entry(type_name) {
PASS_TO_PROFILER_NAMES.with(|names| match names.borrow_mut().entry(type_name) {
Entry::Occupied(e) => *e.get(),
Entry::Vacant(e) => {
let snake_case: String = type_name
Expand Down Expand Up @@ -198,6 +199,31 @@ fn run_passes_inner<'tcx>(
let overridden_passes = &tcx.sess.opts.unstable_opts.mir_enable_passes;
trace!(?overridden_passes);

let named_passes: FxIndexSet<_> =
overridden_passes.iter().map(|(name, _)| name.as_str()).collect();

for &name in named_passes.difference(&*crate::PASS_NAMES) {
tcx.dcx().emit_warn(errors::UnknownPassName { name });
}

// Verify that no passes are missing from the `declare_passes` invocation
#[cfg(debug_assertions)]
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)]
{
let used_passes: FxIndexSet<_> = passes.iter().map(|p| p.name()).collect();

let undeclared = used_passes.difference(&*crate::PASS_NAMES).collect::<Vec<_>>();
if let Some((name, rest)) = undeclared.split_first() {
let mut err =
tcx.dcx().struct_bug(format!("pass `{name}` is not declared in `PASS_NAMES`"));
for name in rest {
err.note(format!("pass `{name}` is also not declared in `PASS_NAMES`"));
}
err.emit();
}
}

let prof_arg = tcx.sess.prof.enabled().then(|| format!("{:?}", body.source.def_id()));

if !body.should_skip() {
Expand Down
14 changes: 14 additions & 0 deletions tests/ui/mir/enable_passes_validation.all_unknown.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
warning: MIR pass `ThisPass` is unknown and will be ignored

warning: MIR pass `DoesNotExist` is unknown and will be ignored

warning: MIR pass `ThisPass` is unknown and will be ignored
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

warning: MIR pass `DoesNotExist` is unknown and will be ignored
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

warning: 4 warnings emitted

2 changes: 2 additions & 0 deletions tests/ui/mir/enable_passes_validation.empty.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: incorrect value `` for unstable option `mir-enable-passes` - a comma-separated list of strings, with elements beginning with + or - was expected

8 changes: 8 additions & 0 deletions tests/ui/mir/enable_passes_validation.mixed.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
warning: MIR pass `ThisPassDoesNotExist` is unknown and will be ignored

warning: MIR pass `ThisPassDoesNotExist` is unknown and will be ignored
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

warning: 2 warnings emitted

21 changes: 21 additions & 0 deletions tests/ui/mir/enable_passes_validation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//@ revisions: empty unprefixed all_unknown all_known mixed

//@[empty] compile-flags: -Zmir-enable-passes=
//@[empty] error-pattern error: incorrect value `` for unstable option `mir-enable-passes` - a comma-separated list of strings, with elements beginning with + or - was expected

//@[unprefixed] compile-flags: -Zmir-enable-passes=CheckAlignment
//@[unprefixed] error-pattern error: incorrect value `CheckAlignment` for unstable option `mir-enable-passes` - a comma-separated list of strings, with elements beginning with + or - was expected

//@[all_unknown] check-pass
//@[all_unknown] compile-flags: -Zmir-enable-passes=+ThisPass,-DoesNotExist
//@[all_unknown] error-pattern: warning: MIR pass `ThisPass` is unknown and will be ignored
//@[all_unknown] error-pattern: warning: MIR pass `DoesNotExist` is unknown and will be ignored

//@[all_known] check-pass
//@[all_known] compile-flags: -Zmir-enable-passes=+CheckAlignment,+LowerIntrinsics

//@[mixed] check-pass
//@[mixed] compile-flags: -Zmir-enable-passes=+ThisPassDoesNotExist,+CheckAlignment
//@[mixed] error-pattern: warning: MIR pass `ThisPassDoesNotExist` is unknown and will be ignored

fn main() {}
2 changes: 2 additions & 0 deletions tests/ui/mir/enable_passes_validation.unprefixed.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: incorrect value `CheckAlignment` for unstable option `mir-enable-passes` - a comma-separated list of strings, with elements beginning with + or - was expected

Loading