diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 348f1f55d3215..e992f1ed385e7 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -46,21 +46,39 @@ type LateLintPassFactory = Box Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::DynSend + sync::DynSync>; /// Information about the registered lints. +// +// About the pass factories: these should only be called once, but since we +// want to avoid locks or interior mutability, we don't enforce this. Lints +// should, in theory, be compatible with being constructed more than once, +// though not necessarily in a sane manner. This is safe though. pub struct LintStore { /// Registered lints. lints: Vec<&'static Lint>, - /// Constructor functions for each variety of lint pass. + /// This lint pass kind is softly deprecated. It misses expanded code and has caused a few + /// errors in the past. Currently, it is only used in Clippy. New implementations + /// should avoid using this interface, as it might be removed in the future. + /// + /// * 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(crate) pre_expansion_lint_passes: Vec, + + /// These lint passes run on AST nodes. + pub(crate) early_lint_passes: Vec, + + /// These lint passes run on HIR nodes. Each one processes an entire crate. They don't benefit + /// from incremental compilation. `late_lint_mod_passes` should be used in preference where + /// possible; only use `late_lint_passes` for lints that implement `check_crate` and/or + /// `check_crate_post` and accumulate cross-module state. /// - /// These should only be called once, but since we want to avoid locks or - /// 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, - pub early_passes: Vec, - pub late_passes: Vec, - /// This is unique in that we construct them per-module, so not once. - pub late_module_passes: Vec, + /// The exception is Clippy, which uses `late_lint_passes` for all late lint passes. It needs + /// `check_crate`/`check_crate_post` for some of its lints and uses late lint passes throughout + /// for consistency. This is ok because Clippy isn't wired for incremental compilation. + pub(crate) late_lint_passes: Vec, + + /// These lint passes run on HIR nodes, and are constructed per-module (i.e. multiple times). + /// They benefit from incremental compilation. + pub(crate) late_lint_mod_passes: Vec, /// Lints indexed by name. by_name: UnordMap, @@ -136,10 +154,10 @@ impl LintStore { pub fn new() -> LintStore { LintStore { lints: vec![], - pre_expansion_passes: vec![], - early_passes: vec![], - late_passes: vec![], - late_module_passes: vec![], + pre_expansion_lint_passes: vec![], + early_lint_passes: vec![], + late_lint_passes: vec![], + late_lint_mod_passes: vec![], by_name: Default::default(), lint_groups: Default::default(), } @@ -166,26 +184,24 @@ impl LintStore { self.lint_groups.keys().copied() } - pub fn register_early_pass(&mut self, pass: EarlyLintPassFactory) { - self.early_passes.push(pass); + /// See the comment on `LintStore::pre_expansion_lint_passes`. + pub fn register_pre_expansion_lint_pass(&mut self, pass: EarlyLintPassFactory) { + self.pre_expansion_lint_passes.push(pass); } - /// This lint pass is softly deprecated. It misses expanded code and has caused a few - /// errors in the past. Currently, it is only used in Clippy. New implementations - /// should avoid using this interface, as it might be removed in the future. - /// - /// * 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: EarlyLintPassFactory) { - self.pre_expansion_passes.push(pass); + /// See the comment on `LintStore::early_lint_passes`. + pub fn register_early_lint_pass(&mut self, pass: EarlyLintPassFactory) { + self.early_lint_passes.push(pass); } - pub fn register_late_pass(&mut self, pass: LateLintPassFactory) { - self.late_passes.push(pass); + /// See the comment on `LintStore::late_lint_passes`. + pub fn register_late_lint_pass(&mut self, pass: LateLintPassFactory) { + self.late_lint_passes.push(pass); } - pub fn register_late_mod_pass(&mut self, pass: LateLintPassFactory) { - self.late_module_passes.push(pass); + /// See the comment on `LintStore::late_lint_mod_passes`. + pub fn register_late_lint_mod_pass(&mut self, pass: LateLintPassFactory) { + self.late_lint_mod_passes.push(pass); } /// Helper method for register_early/late_pass diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 93d150c79d0df..9c123f67abd5f 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -329,11 +329,11 @@ pub fn check_ast_node<'a>( let context = if pre_expansion { let builtin_lints = crate::BuiltinCombinedPreExpansionLintPass::new(); - let passes = &lint_store.pre_expansion_passes; + let passes = &lint_store.pre_expansion_lint_passes; run_passes(check_node, context, builtin_lints, passes) } else { let builtin_lints = crate::BuiltinCombinedEarlyLintPass::new(); - let passes = &lint_store.early_passes; + let passes = &lint_store.early_lint_passes; run_passes(check_node, context, builtin_lints, passes) }; diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index fea6b2ab2f9bd..c17fe6f2e510f 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -355,7 +355,7 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>( // `builtin_lints` directly rather than bundling it up into the // `RuntimeCombinedLateLintPass`. let mut passes: Vec<_> = unerased_lint_store(tcx.sess) - .late_module_passes + .late_lint_mod_passes .iter() .map(|mk_pass| mk_pass(tcx)) .filter(|pass| is_lint_pass_required(skippable_lints, &pass.get_lints())) @@ -403,7 +403,7 @@ fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) { // Note: `passes` is often empty after filtering. let passes: Vec<_> = unerased_lint_store(tcx.sess) - .late_passes + .late_lint_passes .iter() .map(|mk_pass| mk_pass(tcx)) .filter(|pass| is_lint_pass_required(skippable_lints, &pass.get_lints())) diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 9b87da79ee155..72c9ba0e5afbf 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -154,7 +154,7 @@ pub fn provide(providers: &mut Providers) { } fn lint_mod(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { - late_lint_mod(tcx, module_def_id, BuiltinCombinedModuleLateLintPass::new()); + late_lint_mod(tcx, module_def_id, BuiltinCombinedLateLintModPass::new()); } early_lint_methods!( @@ -207,7 +207,7 @@ early_lint_methods!( late_lint_methods!( declare_combined_late_lint_pass, [ - BuiltinCombinedModuleLateLintPass, + BuiltinCombinedLateLintModPass, [ ForLoopsOverFallibles: ForLoopsOverFallibles, DefaultCouldBeDerived: DefaultCouldBeDerived, @@ -279,7 +279,7 @@ late_lint_methods!( late_lint_methods!( declare_combined_late_lint_pass, [ - InternalCombinedModuleLateLintPass, + InternalCombinedLateLintModPass, [ DefaultHashTypes: DefaultHashTypes, QueryStability: QueryStability, @@ -317,7 +317,7 @@ fn register_builtins(store: &mut LintStore) { store.register_lints(&BuiltinCombinedPreExpansionLintPass::lint_vec()); store.register_lints(&BuiltinCombinedEarlyLintPass::lint_vec()); - store.register_lints(&BuiltinCombinedModuleLateLintPass::lint_vec()); + store.register_lints(&BuiltinCombinedLateLintModPass::lint_vec()); store.register_lints(&foreign_modules::lint_vec()); store.register_lints(&hardwired::lint_vec()); @@ -698,10 +698,12 @@ fn register_builtins(store: &mut LintStore) { fn register_internals(store: &mut LintStore) { store.register_lints(&InternalCombinedEarlyLintPass::lint_vec()); - store.register_early_pass(Box::new(|| Box::new(InternalCombinedEarlyLintPass::new()))); + store.register_early_lint_pass(Box::new(|| Box::new(InternalCombinedEarlyLintPass::new()))); - store.register_lints(&InternalCombinedModuleLateLintPass::lint_vec()); - store.register_late_mod_pass(Box::new(|_| Box::new(InternalCombinedModuleLateLintPass::new()))); + store.register_lints(&InternalCombinedLateLintModPass::lint_vec()); + store.register_late_lint_mod_pass(Box::new(|_| { + Box::new(InternalCombinedLateLintModPass::new()) + })); store.register_group( false, diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index 5c101048b8010..12cf58907566d 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -203,7 +203,7 @@ macro_rules! expand_combined_early_lint_pass_methods { /// Combines multiple lints passes into a single lint pass, at compile time, /// for maximum speed. Each `check_foo` method in `$methods` within this pass /// simply calls `check_foo` once per `$pass`. Compare with -/// `EarlyLintPassObjects`, which is similar, but combines lint passes at +/// `RuntimeCombinedEarlyLintPass`, which is similar, but combines lint passes at /// runtime. #[macro_export] macro_rules! declare_combined_early_lint_pass { diff --git a/src/doc/rustc-dev-guide/src/diagnostics/lintstore.md b/src/doc/rustc-dev-guide/src/diagnostics/lintstore.md index 11a7a573f38b6..baae63e96bdc7 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/lintstore.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/lintstore.md @@ -97,7 +97,7 @@ The best way for drivers to get access to this is by overriding the Within the compiler, for performance reasons, we usually do not register dozens of lint passes. Instead, we have a single lint pass of each variety (e.g., -`BuiltinCombinedModuleLateLintPass`) which will internally call all of the +`BuiltinCombinedLateLintModPass`) which will internally call all of the individual lint passes; this is because then we get the benefits of static over dynamic dispatch for each of the (often empty) trait methods. diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index d002df267027d..a65b27f550995 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -454,7 +454,9 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co // NOTE: Do not add any more pre-expansion passes. These should be removed eventually. // Due to the architecture of the compiler, currently `cfg_attr` attributes on crate // level (i.e `#![cfg_attr(...)]`) will still be expanded even when using a pre-expansion pass. - store.register_pre_expansion_pass(Box::new(move || Box::new(attrs::EarlyAttributes::new(conf)))); + store.register_pre_expansion_lint_pass( + Box::new(move || Box::new(attrs::EarlyAttributes::new(conf))) + ); let format_args_storage = FormatArgsStorage::default(); let attr_storage = AttrStorage::default(); @@ -462,12 +464,12 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co { let format_args = format_args_storage.clone(); let attrs = attr_storage.clone(); - store.early_passes.push(Box::new(move || { + store.register_early_lint_pass(Box::new(move || { Box::new(CombinedEarlyLintPass::new(conf, format_args.clone(), attrs.clone())) })); } - store.late_passes.push(Box::new(move |tcx: TyCtxt<'_>| { + store.register_late_lint_pass(Box::new(move |tcx: TyCtxt<'_>| { let skippable_lints = tcx.skippable_lints(()); let is_active = |lints: &rustc_lint::LintVec| is_lint_pass_required(skippable_lints, lints); Box::new(CombinedLateLintPass::new(