Skip to content
Open
49 changes: 16 additions & 33 deletions compiler/rustc_lint/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,10 @@ use self::TargetLint::*;
use crate::levels::LintLevelsBuilder;
use crate::passes::{EarlyLintPassObject, LateLintPassObject};

type EarlyLintPassFactory = dyn Fn() -> EarlyLintPassObject + sync::DynSend + sync::DynSync;
type LateLintPassFactory =
dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::DynSend + sync::DynSync;
pub type EarlyLintPassFactory =
Box<dyn Fn() -> EarlyLintPassObject + sync::DynSend + sync::DynSync>;
pub type LateLintPassFactory =
Box<dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::DynSend + sync::DynSync>;

/// Information about the registered lints.
pub struct LintStore {
Expand All @@ -55,11 +56,11 @@ pub struct LintStore {
/// interior mutability, we don't enforce this (and lints should, in theory,
/// be compatible with being constructed more than once, though not
/// necessarily in a sane manner. This is safe though.)
pub pre_expansion_passes: Vec<Box<EarlyLintPassFactory>>,
pub early_passes: Vec<Box<EarlyLintPassFactory>>,
pub late_passes: Vec<Box<LateLintPassFactory>>,
pub pre_expansion_passes: Vec<EarlyLintPassFactory>,
pub early_passes: Vec<EarlyLintPassFactory>,
pub late_passes: Vec<LateLintPassFactory>,
/// This is unique in that we construct them per-module, so not once.
pub late_module_passes: Vec<Box<LateLintPassFactory>>,
pub late_module_passes: Vec<LateLintPassFactory>,

/// Lints indexed by name.
by_name: UnordMap<String, TargetLint>,
Expand Down Expand Up @@ -165,11 +166,8 @@ impl LintStore {
self.lint_groups.keys().copied()
}

pub fn register_early_pass(
&mut self,
pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync,
) {
self.early_passes.push(Box::new(pass));
pub fn register_early_pass(&mut self, pass: EarlyLintPassFactory) {
self.early_passes.push(pass);
}

/// This lint pass is softly deprecated. It misses expanded code and has caused a few
Expand All @@ -178,31 +176,16 @@ impl LintStore {
///
/// * See [rust#69838](https://github.com/rust-lang/rust/pull/69838)
/// * See [rust-clippy#5518](https://github.com/rust-lang/rust-clippy/pull/5518)
pub fn register_pre_expansion_pass(
&mut self,
pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync,
) {
self.pre_expansion_passes.push(Box::new(pass));
pub fn register_pre_expansion_pass(&mut self, pass: EarlyLintPassFactory) {
self.pre_expansion_passes.push(pass);
}

pub fn register_late_pass(
&mut self,
pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
+ 'static
+ sync::DynSend
+ sync::DynSync,
) {
self.late_passes.push(Box::new(pass));
pub fn register_late_pass(&mut self, pass: LateLintPassFactory) {
self.late_passes.push(pass);
}

pub fn register_late_mod_pass(
&mut self,
pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
+ 'static
+ sync::DynSend
+ sync::DynSync,
) {
self.late_module_passes.push(Box::new(pass));
pub fn register_late_mod_pass(&mut self, pass: LateLintPassFactory) {
self.late_module_passes.push(pass);
}

/// Helper method for register_early/late_pass
Expand Down
14 changes: 7 additions & 7 deletions compiler/rustc_lint/src/early.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,9 @@ impl<'ast, 'ecx, T: EarlyLintPass> ast_visit::Visitor<'ast> for EarlyContextAndP
}

fn visit_where_predicate(&mut self, p: &'ast ast::WherePredicate) {
lint_callback!(self, enter_where_predicate, p);
lint_callback!(self, check_where_predicate, p);
ast_visit::walk_where_predicate(self, p);
lint_callback!(self, exit_where_predicate, p);
lint_callback!(self, check_where_predicate_post, p);
}

fn visit_poly_trait_ref(&mut self, t: &'ast ast::PolyTraitRef) {
Expand Down Expand Up @@ -246,12 +246,12 @@ impl<'ast, 'ecx, T: EarlyLintPass> ast_visit::Visitor<'ast> for EarlyContextAndP
// `check_foo` method in `$methods` within this pass simply calls `check_foo`
// once per `$pass`. Compare with `declare_combined_early_lint_pass`, which is
// similar, but combines lint passes at compile time.
struct RuntimeCombinedEarlyLintPass<'a> {
passes: &'a mut [EarlyLintPassObject],
struct RuntimeCombinedEarlyLintPass {
passes: Vec<EarlyLintPassObject>,
}

#[allow(rustc::lint_pass_impl_without_macro)]
impl LintPass for RuntimeCombinedEarlyLintPass<'_> {
impl LintPass for RuntimeCombinedEarlyLintPass {
fn name(&self) -> &'static str {
panic!()
}
Expand All @@ -262,7 +262,7 @@ impl LintPass for RuntimeCombinedEarlyLintPass<'_> {

macro_rules! impl_early_lint_pass {
([], [$($(#[$attr:meta])* fn $f:ident($($param:ident: $arg:ty),*);)*]) => (
impl EarlyLintPass for RuntimeCombinedEarlyLintPass<'_> {
impl EarlyLintPass for RuntimeCombinedEarlyLintPass {
$(fn $f(&mut self, context: &EarlyContext<'_>, $($param: $arg),*) {
for pass in self.passes.iter_mut() {
pass.$f(context, $($param),*);
Expand Down Expand Up @@ -338,7 +338,7 @@ pub fn check_ast_node<'a>(
} else {
let mut passes: Vec<_> = passes.iter().map(|mk_pass| (mk_pass)()).collect();
passes.push(Box::new(builtin_lints));
let pass = RuntimeCombinedEarlyLintPass { passes: &mut passes[..] };
let pass = RuntimeCombinedEarlyLintPass { passes };
check_ast_node_inner(sess, check_node, context, pass);
}
}
Expand Down
31 changes: 13 additions & 18 deletions compiler/rustc_lint/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::Session;
use rustc_session::lint::LintPass;
use rustc_session::lint::builtin::HardwiredLints;
use rustc_span::Span;
use tracing::debug;

Expand Down Expand Up @@ -306,12 +305,12 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
// `check_foo` method in `$methods` within this pass simply calls `check_foo`
// once per `$pass`. Compare with `declare_combined_late_lint_pass`, which is
// similar, but combines lint passes at compile time.
struct RuntimeCombinedLateLintPass<'a, 'tcx> {
passes: &'a mut [LateLintPassObject<'tcx>],
struct RuntimeCombinedLateLintPass<'tcx> {
passes: Vec<LateLintPassObject<'tcx>>,
}

#[allow(rustc::lint_pass_impl_without_macro)]
impl LintPass for RuntimeCombinedLateLintPass<'_, '_> {
impl LintPass for RuntimeCombinedLateLintPass<'_> {
fn name(&self) -> &'static str {
panic!()
}
Expand All @@ -322,7 +321,7 @@ impl LintPass for RuntimeCombinedLateLintPass<'_, '_> {

macro_rules! impl_late_lint_pass {
([], [$($(#[$attr:meta])* fn $f:ident($($param:ident: $arg:ty),*);)*]) => {
impl<'tcx> LateLintPass<'tcx> for RuntimeCombinedLateLintPass<'_, 'tcx> {
impl<'tcx> LateLintPass<'tcx> for RuntimeCombinedLateLintPass<'tcx> {
$(fn $f(&mut self, context: &LateContext<'tcx>, $($param: $arg),*) {
for pass in self.passes.iter_mut() {
pass.$f(context, $($param),*);
Expand Down Expand Up @@ -368,14 +367,14 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>(
}
} else {
let builtin_lints = Box::new(builtin_lints) as Box<dyn LateLintPass<'tcx>>;
let mut binding = store
let passes = store
.late_module_passes
.iter()
.map(|mk_pass| (mk_pass)(tcx))
.chain(std::iter::once(builtin_lints))
.collect::<Vec<_>>();

let pass = RuntimeCombinedLateLintPass { passes: binding.as_mut_slice() };
let pass = RuntimeCombinedLateLintPass { passes };
late_lint_mod_inner(tcx, module_def_id, context, pass);
}
}
Expand Down Expand Up @@ -406,7 +405,7 @@ fn late_lint_mod_inner<'tcx, T: LateLintPass<'tcx>>(

fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) {
// Note: `passes` is often empty.
let passes: Vec<_> =
let mut passes: Vec<_> =
unerased_lint_store(tcx.sess).late_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect();

if passes.is_empty() {
Expand All @@ -426,19 +425,15 @@ fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) {

let lints_that_dont_need_to_run = tcx.lints_that_dont_need_to_run(());

let mut filtered_passes: Vec<Box<dyn LateLintPass<'tcx>>> = passes
.into_iter()
.filter(|pass| {
let lints = (**pass).get_lints();
// Lintless passes are always in
lints.is_empty() ||
passes.retain(|pass| {
let lints = pass.get_lints();
// Lintless passes are always in
lints.is_empty() ||
// If the pass doesn't have a single needed lint, omit it
!lints.iter().all(|lint| lints_that_dont_need_to_run.contains(&LintId::of(lint)))
})
.collect();
});

filtered_passes.push(Box::new(HardwiredLints));
let pass = RuntimeCombinedLateLintPass { passes: &mut filtered_passes[..] };
let pass = RuntimeCombinedLateLintPass { passes };
let mut cx = LateContextAndPass { context, pass };

// Visit the whole crate.
Expand Down
58 changes: 33 additions & 25 deletions compiler/rustc_lint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,10 @@ use unused::*;

#[rustfmt::skip]
pub use builtin::{MissingDoc, SoftLints};
pub use context::{CheckLintNameResult, EarlyContext, LateContext, LintContext, LintStore};
pub use context::{
CheckLintNameResult, EarlyContext, EarlyLintPassFactory, LateContext, LateLintPassFactory,
LintContext, LintStore,
};
pub use early::diagnostics::DiagAndSess;
pub use early::{EarlyCheckNode, check_ast_node};
pub use late::{check_crate, late_lint_mod, unerased_lint_store};
Expand Down Expand Up @@ -663,30 +666,35 @@ fn register_builtins(store: &mut LintStore) {
}

fn register_internals(store: &mut LintStore) {
store.register_lints(&LintPassImpl::lint_vec());
store.register_early_pass(|| Box::new(LintPassImpl));
store.register_lints(&DefaultHashTypes::lint_vec());
store.register_late_mod_pass(|_| Box::new(DefaultHashTypes));
store.register_lints(&QueryStability::lint_vec());
store.register_late_mod_pass(|_| Box::new(QueryStability));
store.register_lints(&TyTyKind::lint_vec());
store.register_late_mod_pass(|_| Box::new(TyTyKind));
store.register_lints(&TypeIr::lint_vec());
store.register_late_mod_pass(|_| Box::new(TypeIr));
store.register_lints(&BadOptAccess::lint_vec());
store.register_late_mod_pass(|_| Box::new(BadOptAccess));
store.register_lints(&DisallowedPassByRef::lint_vec());
store.register_late_mod_pass(|_| Box::new(DisallowedPassByRef));
store.register_lints(&SpanUseEqCtxt::lint_vec());
store.register_late_mod_pass(|_| Box::new(SpanUseEqCtxt));
store.register_lints(&SymbolInternStringLiteral::lint_vec());
store.register_late_mod_pass(|_| Box::new(SymbolInternStringLiteral));
store.register_lints(&ImplicitSysrootCrateImport::lint_vec());
store.register_early_pass(|| Box::new(ImplicitSysrootCrateImport));
store.register_lints(&BadUseOfFindAttr::lint_vec());
store.register_early_pass(|| Box::new(BadUseOfFindAttr));
store.register_lints(&RustcMustMatchExhaustively::lint_vec());
store.register_late_pass(|_| Box::new(RustcMustMatchExhaustively));
macro_rules! early {
($register:ident, $lint:ident) => {
store.register_lints(&$lint::lint_vec());
store.$register(Box::new(|| Box::new($lint)));
};
}

macro_rules! late {
($register:ident, $lint:ident) => {
store.register_lints(&$lint::lint_vec());
store.$register(Box::new(|_| Box::new($lint)));
};
}

early!(register_early_pass, LintPassImpl);
early!(register_early_pass, ImplicitSysrootCrateImport);
early!(register_early_pass, BadUseOfFindAttr);

late!(register_late_mod_pass, DefaultHashTypes);
late!(register_late_mod_pass, QueryStability);
late!(register_late_mod_pass, TyTyKind);
late!(register_late_mod_pass, TypeIr);
late!(register_late_mod_pass, BadOptAccess);
late!(register_late_mod_pass, DisallowedPassByRef);
late!(register_late_mod_pass, SpanUseEqCtxt);
late!(register_late_mod_pass, SymbolInternStringLiteral);

late!(register_late_pass, RustcMustMatchExhaustively);
Comment on lines +669 to +696

@ada4a ada4a Jun 12, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the bodies of the two macros ended up being identical, and the early/late distinction is already clear from the method name used (register_early_pass vs register_late(_mod)pass), maybe use one macro instead, called something like register!?

Suggested change
macro_rules! early {
($register:ident, $lint:ident) => {
store.register_lints(&$lint::lint_vec());
store.$register(Box::new(|| Box::new($lint)));
};
}
macro_rules! late {
($register:ident, $lint:ident) => {
store.register_lints(&$lint::lint_vec());
store.$register(Box::new(|_| Box::new($lint)));
};
}
early!(register_early_pass, LintPassImpl);
early!(register_early_pass, ImplicitSysrootCrateImport);
early!(register_early_pass, BadUseOfFindAttr);
late!(register_late_mod_pass, DefaultHashTypes);
late!(register_late_mod_pass, QueryStability);
late!(register_late_mod_pass, TyTyKind);
late!(register_late_mod_pass, TypeIr);
late!(register_late_mod_pass, BadOptAccess);
late!(register_late_mod_pass, DisallowedPassByRef);
late!(register_late_mod_pass, SpanUseEqCtxt);
late!(register_late_mod_pass, SymbolInternStringLiteral);
late!(register_late_pass, RustcMustMatchExhaustively);
macro_rules! register {
($register:ident, $lint:ident) => {
store.register_lints(&$lint::lint_vec());
store.$register(Box::new(|_| Box::new($lint)));
};
}
register!(register_early_pass, LintPassImpl);
register!(register_early_pass, ImplicitSysrootCrateImport);
register!(register_early_pass, BadUseOfFindAttr);
register!(register_late_mod_pass, DefaultHashTypes);
register!(register_late_mod_pass, QueryStability);
register!(register_late_mod_pass, TyTyKind);
register!(register_late_mod_pass, TypeIr);
register!(register_late_mod_pass, BadOptAccess);
register!(register_late_mod_pass, DisallowedPassByRef);
register!(register_late_mod_pass, SpanUseEqCtxt);
register!(register_late_mod_pass, SymbolInternStringLiteral);
register!(register_late_pass, RustcMustMatchExhaustively);

View changes since the review


store.register_group(
false,
"rustc::internal",
Expand Down
24 changes: 9 additions & 15 deletions compiler/rustc_lint/src/passes.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use rustc_session::lint::LintPass;
use rustc_session::lint::builtin::HardwiredLints;

use crate::context::{EarlyContext, LateContext};

#[macro_export]
macro_rules! late_lint_methods {
($macro:path, $args:tt) => (
// `_post` methods are called *after* recursing into the node.
$macro!($args, [
fn check_body(a: &rustc_hir::Body<'tcx>);
fn check_body_post(a: &rustc_hir::Body<'tcx>);
Expand All @@ -14,8 +14,6 @@ macro_rules! late_lint_methods {
fn check_mod(a: &'tcx rustc_hir::Mod<'tcx>, b: rustc_hir::HirId);
fn check_foreign_item(a: &'tcx rustc_hir::ForeignItem<'tcx>);
fn check_item(a: &'tcx rustc_hir::Item<'tcx>);
/// This is called *after* recursing into the item
/// (in contrast to `check_item`, which is checked before).
fn check_item_post(a: &'tcx rustc_hir::Item<'tcx>);
fn check_local(a: &'tcx rustc_hir::LetStmt<'tcx>);
fn check_block(a: &'tcx rustc_hir::Block<'tcx>);
Expand Down Expand Up @@ -60,7 +58,7 @@ macro_rules! late_lint_methods {
// contains a few lint-specific methods with no equivalent in `Visitor`.
//
macro_rules! declare_late_lint_pass {
([], [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
([], [$(fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
pub trait LateLintPass<'tcx>: LintPass {
$(#[inline(always)] fn $name(&mut self, _: &LateContext<'tcx>, $(_: $arg),*) {})*
}
Expand All @@ -71,8 +69,6 @@ macro_rules! declare_late_lint_pass {
// for all the `check_*` methods.
late_lint_methods!(declare_late_lint_pass, []);

impl LateLintPass<'_> for HardwiredLints {}

#[macro_export]
macro_rules! expand_combined_late_lint_pass_method {
([$($pass:ident),*], $self: ident, $name: ident, $params:tt) => ({
Expand All @@ -82,7 +78,7 @@ macro_rules! expand_combined_late_lint_pass_method {

#[macro_export]
macro_rules! expand_combined_late_lint_pass_methods {
($passes:tt, [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
($passes:tt, [$(fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
$(fn $name(&mut self, context: &$crate::LateContext<'tcx>, $($param: $arg),*) {
$crate::expand_combined_late_lint_pass_method!($passes, self, $name, (context, $($param),*));
})*
Expand Down Expand Up @@ -135,14 +131,13 @@ macro_rules! declare_combined_late_lint_pass {
#[macro_export]
macro_rules! early_lint_methods {
($macro:path, $args:tt) => (
// `_post` methods are called *after* recursing into the node.
$macro!($args, [
fn check_param(a: &rustc_ast::Param);
fn check_ident(a: &rustc_span::Ident);
fn check_crate(a: &rustc_ast::Crate);
fn check_crate_post(a: &rustc_ast::Crate);
fn check_item(a: &rustc_ast::Item);
/// This is called *after* recursing into the item
/// (in contrast to `check_item`, which is checked before).
fn check_item_post(a: &rustc_ast::Item);
fn check_local(a: &rustc_ast::Local);
fn check_block(a: &rustc_ast::Block);
Expand Down Expand Up @@ -171,15 +166,14 @@ macro_rules! early_lint_methods {
fn check_attributes_post(a: &[rustc_ast::Attribute]);
fn check_mac_def(a: &rustc_ast::MacroDef);
fn check_mac(a: &rustc_ast::MacCall);

fn enter_where_predicate(a: &rustc_ast::WherePredicate);
fn exit_where_predicate(a: &rustc_ast::WherePredicate);
fn check_where_predicate(a: &rustc_ast::WherePredicate);
fn check_where_predicate_post(a: &rustc_ast::WherePredicate);
]);
)
}

macro_rules! declare_early_lint_pass {
([], [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
([], [$(fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
pub trait EarlyLintPass: LintPass {
$(#[inline(always)] fn $name(&mut self, _: &EarlyContext<'_>, $(_: $arg),*) {})*
}
Expand All @@ -199,7 +193,7 @@ macro_rules! expand_combined_early_lint_pass_method {

#[macro_export]
macro_rules! expand_combined_early_lint_pass_methods {
($passes:tt, [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
($passes:tt, [$(fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
$(fn $name(&mut self, context: &$crate::EarlyContext<'_>, $($param: $arg),*) {
$crate::expand_combined_early_lint_pass_method!($passes, self, $name, (context, $($param),*));
})*
Expand Down Expand Up @@ -250,5 +244,5 @@ macro_rules! declare_combined_early_lint_pass {
}

/// A lint pass boxed up as a trait object.
pub(crate) type EarlyLintPassObject = Box<dyn EarlyLintPass + 'static>;
pub(crate) type EarlyLintPassObject = Box<dyn EarlyLintPass>;
pub(crate) type LateLintPassObject<'tcx> = Box<dyn LateLintPass<'tcx> + 'tcx>;
Loading
Loading