Skip to content

Commit 50e9dfe

Browse files
committed
Auto merge of rust-lang#125116 - blyxyas:ignore-allowed-lints-final, r=<try>
(Big performance change) Do not run lints that cannot emit Before this lint, adding a lint was a difficult matter because it always had some overhead involved. This was because all lints would run, no matter their default level, or if the user had `#![allow]`ed them. This PR changes that. This change would improve both the Rust lint infrastructure and Clippy, but Clippy will see the most benefit, as it has about 900 registered lints (and growing!) So yeah, with this little patch we filter all lints pre-linting, and remove any lint that is either: - Manually `#![allow]`ed in the whole crate, - Allowed in the command line, or - Not manually enabled with `#[warn]` or similar, and its default level is `Allow` As some lints **need** to run, this PR also adds **loadbearing lints**. On a lint declaration, you can use the `[loadbearing: true]` marker to label it as loadbearing. A loadbearing lint will never be filtered. **Phase 1/2** Not all lints are being filtered, I'm still working on it, but this branch still gives us about a 2% improvement, so why not merge it already. Fixes rust-lang#106983
2 parents d6c8169 + 2aaf2f2 commit 50e9dfe

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+421
-74
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -4033,6 +4033,7 @@ dependencies = [
40334033
"rustc_hir",
40344034
"rustc_hir_pretty",
40354035
"rustc_index",
4036+
"rustc_lint_defs",
40364037
"rustc_macros",
40374038
"rustc_query_system",
40384039
"rustc_serialize",

compiler/rustc_ast/src/attr/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ impl AttrItem {
223223
self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span))
224224
}
225225

226-
fn meta_item_list(&self) -> Option<ThinVec<NestedMetaItem>> {
226+
pub fn meta_item_list(&self) -> Option<ThinVec<NestedMetaItem>> {
227227
match &self.args {
228228
AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
229229
MetaItemKind::list_from_tokens(args.tokens.clone())

compiler/rustc_interface/src/passes.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -895,7 +895,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
895895
tcx.ensure().check_mod_privacy(module);
896896
});
897897
});
898-
}
898+
} // { sess.time("mir_checking", || { tcx.hir().mir_for }) }
899899
);
900900

901901
// This check has to be run after all lints are done processing. We don't

compiler/rustc_lint/src/builtin.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
//! If you define a new `LateLintPass`, you will also need to add it to the
2121
//! `late_lint_methods!` invocation in `lib.rs`.
2222
23+
use std::default::Default;
2324
use std::fmt::Write;
2425

2526
use ast::token::TokenKind;
@@ -73,6 +74,10 @@ use crate::{
7374
fluent_generated as fluent, EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level,
7475
LintContext,
7576
};
77+
// use std::fmt::Write;
78+
79+
// hardwired lints from rustc_lint_defs
80+
// pub use rustc_session::lint::builtin::*;
7681

7782
declare_lint! {
7883
/// The `while_true` lint detects `while true { }`.
@@ -242,7 +247,8 @@ declare_lint! {
242247
/// behavior.
243248
UNSAFE_CODE,
244249
Allow,
245-
"usage of `unsafe` code and other potentially unsound constructs"
250+
"usage of `unsafe` code and other potentially unsound constructs",
251+
[loadbearing: true]
246252
}
247253

248254
declare_lint_pass!(UnsafeCode => [UNSAFE_CODE]);
@@ -390,6 +396,7 @@ declare_lint! {
390396
report_in_external_macro
391397
}
392398

399+
#[derive(Default)]
393400
pub struct MissingDoc;
394401

395402
impl_lint_pass!(MissingDoc => [MISSING_DOCS]);
@@ -830,8 +837,8 @@ pub struct DeprecatedAttr {
830837

831838
impl_lint_pass!(DeprecatedAttr => []);
832839

833-
impl DeprecatedAttr {
834-
pub fn new() -> DeprecatedAttr {
840+
impl Default for DeprecatedAttr {
841+
fn default() -> Self {
835842
DeprecatedAttr { depr_attrs: deprecated_attributes() }
836843
}
837844
}

compiler/rustc_lint/src/early.rs

+3
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,9 @@ impl LintPass for RuntimeCombinedEarlyLintPass<'_> {
312312
fn name(&self) -> &'static str {
313313
panic!()
314314
}
315+
fn get_lints(&self) -> crate::LintVec {
316+
panic!()
317+
}
315318
}
316319

317320
macro_rules! impl_early_lint_pass {

compiler/rustc_lint/src/internal.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,8 @@ declare_tool_lint! {
421421
pub rustc::UNTRANSLATABLE_DIAGNOSTIC,
422422
Deny,
423423
"prevent creation of diagnostics which cannot be translated",
424-
report_in_external_macro: true
424+
report_in_external_macro: true,
425+
[loadbearing: true]
425426
}
426427

427428
declare_tool_lint! {
@@ -434,7 +435,8 @@ declare_tool_lint! {
434435
pub rustc::DIAGNOSTIC_OUTSIDE_OF_IMPL,
435436
Deny,
436437
"prevent diagnostic creation outside of `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls",
437-
report_in_external_macro: true
438+
report_in_external_macro: true,
439+
[loadbearing: true]
438440
}
439441

440442
declare_lint_pass!(Diagnostics => [UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE_OF_IMPL]);

compiler/rustc_lint/src/late.rs

+55-8
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,14 @@ use rustc_hir::def_id::{LocalDefId, LocalModDefId};
2424
use rustc_hir::{intravisit as hir_visit, HirId};
2525
use rustc_middle::hir::nested_filter;
2626
use rustc_middle::ty::{self, TyCtxt};
27+
use rustc_session::lint::builtin::HardwiredLints;
2728
use rustc_session::lint::LintPass;
2829
use rustc_session::Session;
2930
use rustc_span::Span;
3031
use tracing::debug;
3132

3233
use crate::passes::LateLintPassObject;
33-
use crate::{LateContext, LateLintPass, LintStore};
34+
use crate::{LateContext, LateLintPass, LintId, LintStore};
3435

3536
/// Extract the [`LintStore`] from [`Session`].
3637
///
@@ -327,6 +328,9 @@ impl LintPass for RuntimeCombinedLateLintPass<'_, '_> {
327328
fn name(&self) -> &'static str {
328329
panic!()
329330
}
331+
fn get_lints(&self) -> crate::LintVec {
332+
panic!()
333+
}
330334
}
331335

332336
macro_rules! impl_late_lint_pass {
@@ -362,13 +366,33 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>(
362366
// Note: `passes` is often empty. In that case, it's faster to run
363367
// `builtin_lints` directly rather than bundling it up into the
364368
// `RuntimeCombinedLateLintPass`.
365-
let late_module_passes = &unerased_lint_store(tcx.sess).late_module_passes;
366-
if late_module_passes.is_empty() {
369+
let store = unerased_lint_store(tcx.sess);
370+
371+
if store.late_module_passes.is_empty() {
367372
late_lint_mod_inner(tcx, module_def_id, context, builtin_lints);
368373
} else {
369-
let mut passes: Vec<_> = late_module_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect();
370-
passes.push(Box::new(builtin_lints));
371-
let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] };
374+
let passes: Vec<_> =
375+
store.late_module_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect();
376+
// Filter unused lints
377+
let lints_that_dont_need_to_run = tcx.lints_that_dont_need_to_run(());
378+
let mut filtered_passes: Vec<Box<dyn LateLintPass<'tcx>>> = passes
379+
.into_iter()
380+
.filter(|pass| {
381+
let lints = LintPass::get_lints(pass);
382+
if lints.is_empty() {
383+
true
384+
} else {
385+
lints
386+
.iter()
387+
.any(|lint| !lints_that_dont_need_to_run.contains(&LintId::of(lint)))
388+
}
389+
})
390+
.collect();
391+
392+
filtered_passes.push(Box::new(builtin_lints));
393+
filtered_passes.push(Box::new(HardwiredLints));
394+
395+
let pass = RuntimeCombinedLateLintPass { passes: &mut filtered_passes[..] };
372396
late_lint_mod_inner(tcx, module_def_id, context, pass);
373397
}
374398
}
@@ -399,7 +423,7 @@ fn late_lint_mod_inner<'tcx, T: LateLintPass<'tcx>>(
399423

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

405429
if passes.is_empty() {
@@ -417,7 +441,30 @@ fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) {
417441
only_module: false,
418442
};
419443

420-
let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] };
444+
let lints_that_dont_need_to_run = tcx.lints_that_dont_need_to_run(());
445+
446+
// dbg!(&lints_that_dont_need_to_run);
447+
let mut filtered_passes: Vec<Box<dyn LateLintPass<'tcx>>> = passes
448+
.into_iter()
449+
.filter(|pass| {
450+
let lints = LintPass::get_lints(pass);
451+
!lints.iter().all(|lint| lints_that_dont_need_to_run.contains(&LintId::of(lint)))
452+
})
453+
.collect();
454+
455+
filtered_passes.push(Box::new(HardwiredLints));
456+
457+
// let mut filtered_passes: Vec<Box<dyn LateLintPass<'tcx>>> = passes
458+
// .into_iter()
459+
// .filter(|pass| {
460+
// let lints = LintPass::get_lints(pass);
461+
// lints.iter()
462+
// .any(|lint|
463+
// !lints_that_dont_need_to_run.contains(&LintId::of(lint)))
464+
// }).collect();
465+
//
466+
467+
let pass = RuntimeCombinedLateLintPass { passes: &mut filtered_passes[..] };
421468
late_lint_crate_inner(tcx, context, pass);
422469
}
423470

0 commit comments

Comments
 (0)