From b4da0585959ec8b2c111bc9f8fd0e34e78c7f260 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Mon, 13 Nov 2023 14:35:37 +0100 Subject: [PATCH 1/7] Do not run lints that cannot emit Before this change, 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 --- Cargo.lock | 1 + compiler/rustc_ast/src/attr/mod.rs | 2 +- compiler/rustc_lint/src/builtin.rs | 14 +- compiler/rustc_lint/src/early.rs | 3 + compiler/rustc_lint/src/internal.rs | 6 +- compiler/rustc_lint/src/late.rs | 45 ++++++- compiler/rustc_lint/src/levels.rs | 121 +++++++++++++++++- compiler/rustc_lint/src/lib.rs | 24 ++-- compiler/rustc_lint/src/passes.rs | 10 +- compiler/rustc_lint/src/types.rs | 2 +- compiler/rustc_lint/src/unused.rs | 4 +- compiler/rustc_lint_defs/src/builtin.rs | 6 +- compiler/rustc_lint_defs/src/lib.rs | 30 ++++- compiler/rustc_middle/Cargo.toml | 1 + compiler/rustc_middle/src/lint.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 5 + src/librustdoc/lint.rs | 7 +- .../clippy/clippy_lints/src/asm_syntax.rs | 2 +- .../src/utils/{ => internal_lints}/author.rs | 11 +- .../clippy/clippy_lints/src/utils/mod.rs | 1 - .../tests/{ui => ui-internal}/author.rs | 2 + .../tests/{ui => ui-internal}/author.stdout | 0 .../{ui => ui-internal}/author/blocks.rs | 0 .../{ui => ui-internal}/author/blocks.stdout | 0 .../tests/{ui => ui-internal}/author/call.rs | 0 .../{ui => ui-internal}/author/call.stdout | 0 .../tests/{ui => ui-internal}/author/if.rs | 0 .../{ui => ui-internal}/author/if.stdout | 0 .../{ui => ui-internal}/author/issue_3849.rs | 0 .../author/issue_3849.stdout | 0 .../tests/{ui => ui-internal}/author/loop.rs | 0 .../{ui => ui-internal}/author/loop.stdout | 0 .../author/macro_in_closure.rs | 0 .../author/macro_in_closure.stdout | 0 .../author/macro_in_loop.rs | 0 .../author/macro_in_loop.stdout | 0 .../{ui => ui-internal}/author/matches.rs | 0 .../{ui => ui-internal}/author/matches.stdout | 0 .../{ui => ui-internal}/author/repeat.rs | 0 .../{ui => ui-internal}/author/repeat.stdout | 0 .../{ui => ui-internal}/author/struct.rs | 0 .../{ui => ui-internal}/author/struct.stdout | 0 src/tools/clippy/tests/ui/no_lints.rs | 3 + .../lint_pass_impl_without_macro.rs | 10 +- .../lint_pass_impl_without_macro.stderr | 2 +- 45 files changed, 264 insertions(+), 50 deletions(-) rename src/tools/clippy/clippy_lints/src/utils/{ => internal_lints}/author.rs (99%) rename src/tools/clippy/tests/{ui => ui-internal}/author.rs (72%) rename src/tools/clippy/tests/{ui => ui-internal}/author.stdout (100%) rename src/tools/clippy/tests/{ui => ui-internal}/author/blocks.rs (100%) rename src/tools/clippy/tests/{ui => ui-internal}/author/blocks.stdout (100%) rename src/tools/clippy/tests/{ui => ui-internal}/author/call.rs (100%) rename src/tools/clippy/tests/{ui => ui-internal}/author/call.stdout (100%) rename src/tools/clippy/tests/{ui => ui-internal}/author/if.rs (100%) rename src/tools/clippy/tests/{ui => ui-internal}/author/if.stdout (100%) rename src/tools/clippy/tests/{ui => ui-internal}/author/issue_3849.rs (100%) rename src/tools/clippy/tests/{ui => ui-internal}/author/issue_3849.stdout (100%) rename src/tools/clippy/tests/{ui => ui-internal}/author/loop.rs (100%) rename src/tools/clippy/tests/{ui => ui-internal}/author/loop.stdout (100%) rename src/tools/clippy/tests/{ui => ui-internal}/author/macro_in_closure.rs (100%) rename src/tools/clippy/tests/{ui => ui-internal}/author/macro_in_closure.stdout (100%) rename src/tools/clippy/tests/{ui => ui-internal}/author/macro_in_loop.rs (100%) rename src/tools/clippy/tests/{ui => ui-internal}/author/macro_in_loop.stdout (100%) rename src/tools/clippy/tests/{ui => ui-internal}/author/matches.rs (100%) rename src/tools/clippy/tests/{ui => ui-internal}/author/matches.stdout (100%) rename src/tools/clippy/tests/{ui => ui-internal}/author/repeat.rs (100%) rename src/tools/clippy/tests/{ui => ui-internal}/author/repeat.stdout (100%) rename src/tools/clippy/tests/{ui => ui-internal}/author/struct.rs (100%) rename src/tools/clippy/tests/{ui => ui-internal}/author/struct.stdout (100%) create mode 100644 src/tools/clippy/tests/ui/no_lints.rs diff --git a/Cargo.lock b/Cargo.lock index 60f2f17c3ee..8f6946e062e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4029,6 +4029,7 @@ dependencies = [ "rustc_hir", "rustc_hir_pretty", "rustc_index", + "rustc_lint_defs", "rustc_macros", "rustc_query_system", "rustc_serialize", diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index b73412a4b1d..9311af28f54 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -223,7 +223,7 @@ impl AttrItem { self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span)) } - fn meta_item_list(&self) -> Option> { + pub fn meta_item_list(&self) -> Option> { match &self.args { AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => { MetaItemKind::list_from_tokens(args.tokens.clone()) diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 8bd9c899a62..acd12f7f20d 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -74,6 +74,12 @@ use crate::{ fluent_generated as fluent, }; +use std::default::Default; +use std::fmt::Write; + +// hardwired lints from rustc_lint_defs +pub use rustc_session::lint::builtin::*; + declare_lint! { /// The `while_true` lint detects `while true { }`. /// @@ -241,7 +247,8 @@ declare_lint! { /// behavior. UNSAFE_CODE, Allow, - "usage of `unsafe` code and other potentially unsound constructs" + "usage of `unsafe` code and other potentially unsound constructs", + [loadbearing: true] } declare_lint_pass!(UnsafeCode => [UNSAFE_CODE]); @@ -389,6 +396,7 @@ declare_lint! { report_in_external_macro } +#[derive(Default)] pub struct MissingDoc; impl_lint_pass!(MissingDoc => [MISSING_DOCS]); @@ -819,8 +827,8 @@ pub struct DeprecatedAttr { impl_lint_pass!(DeprecatedAttr => []); -impl DeprecatedAttr { - pub fn new() -> DeprecatedAttr { +impl Default for DeprecatedAttr { + fn default() -> Self { DeprecatedAttr { depr_attrs: deprecated_attributes() } } } diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 2285877c9ef..a63a0833541 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -312,6 +312,9 @@ impl LintPass for RuntimeCombinedEarlyLintPass<'_> { fn name(&self) -> &'static str { panic!() } + fn get_lints(&self) -> crate::LintVec { + panic!() + } } macro_rules! impl_early_lint_pass { diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 94cc58e4956..0f4f58efd8e 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -429,7 +429,8 @@ declare_tool_lint! { pub rustc::UNTRANSLATABLE_DIAGNOSTIC, Deny, "prevent creation of diagnostics which cannot be translated", - report_in_external_macro: true + report_in_external_macro: true, + [loadbearing: true] } declare_tool_lint! { @@ -442,7 +443,8 @@ declare_tool_lint! { pub rustc::DIAGNOSTIC_OUTSIDE_OF_IMPL, Deny, "prevent diagnostic creation outside of `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls", - report_in_external_macro: true + report_in_external_macro: true, + [loadbearing: true] } declare_lint_pass!(Diagnostics => [UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE_OF_IMPL]); diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index 6d5903ac467..ccd06ba612b 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -326,6 +326,9 @@ impl LintPass for RuntimeCombinedLateLintPass<'_, '_> { fn name(&self) -> &'static str { panic!() } + fn get_lints(&self) -> crate::LintVec { + panic!() + } } macro_rules! impl_late_lint_pass { @@ -361,13 +364,38 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>( // Note: `passes` is often empty. In that case, it's faster to run // `builtin_lints` directly rather than bundling it up into the // `RuntimeCombinedLateLintPass`. - let late_module_passes = &unerased_lint_store(tcx.sess).late_module_passes; - if late_module_passes.is_empty() { + let store = unerased_lint_store(tcx.sess); + + if store.late_module_passes.is_empty() { late_lint_mod_inner(tcx, module_def_id, context, builtin_lints); } else { - let mut passes: Vec<_> = late_module_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect(); - passes.push(Box::new(builtin_lints)); - let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] }; + let passes: Vec<_> = + store.late_module_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect(); + + // Filter unused lints + let (lints_to_emit, lints_allowed) = &**tcx.lints_that_can_emit(()); + // let lints_to_emit = &lints_that_can_emit.0; + // let lints_allowed = &lints_that_can_emit.1; + + // Now, we'll filtered passes in a way that discards any lint that won't trigger. + // If any lint is a given pass is detected to be emitted, we will keep that pass. + // Otherwise, we don't + let mut filtered_passes: Vec>> = passes + .into_iter() + .filter(|pass| { + let pass = LintPass::get_lints(pass); + pass.iter().any(|&lint| { + let lint_name = name_without_tool(&lint.name.to_lowercase()).to_string(); + lints_to_emit.contains(&lint_name) + || (!lints_allowed.contains(&lint_name) + && lint.default_level != crate::Level::Allow) + }) + }) + .collect(); + + filtered_passes.push(Box::new(builtin_lints)); + + let pass = RuntimeCombinedLateLintPass { passes: &mut filtered_passes[..] }; late_lint_mod_inner(tcx, module_def_id, context, pass); } } @@ -454,3 +482,10 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>) { }, ); } + +/// Format name ignoring the name, useful for filtering non-used lints. +/// For example, 'clippy::my_lint' will turn into 'my_lint' +pub(crate) fn name_without_tool(name: &str) -> &str { + // Doing some calculations here to account for those separators + name.rsplit("::").next().unwrap_or(name) +} diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 89a67fc0d89..7ee8618bc55 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -1,6 +1,6 @@ use rustc_ast_pretty::pprust; -use rustc_data_structures::fx::FxIndexMap; -use rustc_errors::{Diag, LintDiagnostic, MultiSpan}; +use rustc_data_structures::{fx::FxIndexMap, sync::Lrc}; +use rustc_errors::{Diag, DiagMessage, LintDiagnostic, MultiSpan}; use rustc_feature::{Features, GateIssue}; use rustc_hir::HirId; use rustc_hir::intravisit::{self, Visitor}; @@ -31,7 +31,7 @@ use crate::errors::{ OverruledAttributeSub, RequestedLevel, UnknownToolInScopedLint, UnsupportedGroup, }; use crate::fluent_generated as fluent; -use crate::late::unerased_lint_store; +use crate::late::{unerased_lint_store, name_without_tool}; use crate::lints::{ DeprecatedLintName, DeprecatedLintNameFromCommandLine, IgnoredUnlessCrateSpecified, OverruledAttributeLint, RemovedLint, RemovedLintFromCommandLine, RenamedLint, @@ -115,6 +115,36 @@ impl LintLevelSets { } } +/// Walk the whole crate collecting nodes where lint levels change +/// (e.g. `#[allow]` attributes), and joins that list with the warn-by-default +/// (and not allowed in the crate) and CLI lints. The returned value is a tuple +/// of 1. The lints that will emit (or at least, should run), and 2. +/// The lints that are allowed at the crate level and will not emit. +pub fn lints_that_can_emit(tcx: TyCtxt<'_>, (): ()) -> Lrc<(Vec, Vec)> { + let mut visitor = LintLevelMinimum::new(tcx); + visitor.process_opts(); + tcx.hir().walk_attributes(&mut visitor); + + let store = unerased_lint_store(&tcx.sess); + + let lint_groups = store.get_lint_groups(); + for group in lint_groups { + let binding = group.0.to_lowercase(); + let group_name = name_without_tool(&binding).to_string(); + if visitor.lints_to_emit.contains(&group_name) { + for lint in group.1 { + visitor.lints_to_emit.push(name_without_tool(&lint.to_string()).to_string()); + } + } else if visitor.lints_allowed.contains(&group_name) { + for lint in &group.1 { + visitor.lints_allowed.push(name_without_tool(&lint.to_string()).to_string()); + } + } + } + + Lrc::new((visitor.lints_to_emit, visitor.lints_allowed)) +} + #[instrument(level = "trace", skip(tcx), ret)] fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLevelMap { let store = unerased_lint_store(tcx.sess); @@ -301,6 +331,88 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> { } } +/// Visitor with the only function of visiting every item-like in a crate and +/// computing the highest level that every lint gets put to. +/// +/// E.g., if a crate has a global #![allow(lint)] attribute, but a single item +/// uses #[warn(lint)], this visitor will set that lint level as `Warn` +struct LintLevelMinimum<'tcx> { + tcx: TyCtxt<'tcx>, + /// The actual list of detected lints. + lints_to_emit: Vec, + lints_allowed: Vec, +} + +impl<'tcx> LintLevelMinimum<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>) -> Self { + Self { + tcx, + // That magic number is the current number of lints + some more for possible future lints + lints_to_emit: Vec::with_capacity(230), + lints_allowed: Vec::with_capacity(100), + } + } + + fn process_opts(&mut self) { + for (lint, level) in &self.tcx.sess.opts.lint_opts { + if *level == Level::Allow { + self.lints_allowed.push(lint.clone()); + } else { + self.lints_to_emit.push(lint.to_string()); + } + } + } +} + +impl<'tcx> Visitor<'tcx> for LintLevelMinimum<'tcx> { + type NestedFilter = nested_filter::All; + + fn nested_visit_map(&mut self) -> Self::Map { + self.tcx.hir() + } + + fn visit_attribute(&mut self, attribute: &'tcx ast::Attribute) { + if let Some(meta) = attribute.meta() { + if [sym::warn, sym::deny, sym::forbid, sym::expect] + .iter() + .any(|kind| meta.has_name(*kind)) + { + // SAFETY: Lint attributes are always a metalist inside a + // metalist (even with just one lint). + for meta_list in meta.meta_item_list().unwrap() { + // If it's a tool lint (e.g. clippy::my_clippy_lint) + if let ast::NestedMetaItem::MetaItem(meta_item) = meta_list { + if meta_item.path.segments.len() == 1 { + self.lints_to_emit.push( + // SAFETY: Lint attributes can only have literals + meta_list.ident().unwrap().name.as_str().to_string(), + ); + } else { + self.lints_to_emit + .push(meta_item.path.segments[1].ident.name.as_str().to_string()); + } + } + } + // We handle #![allow]s differently, as these remove checking rather than adding. + } else if meta.has_name(sym::allow) + && let ast::AttrStyle::Inner = attribute.style + { + for meta_list in meta.meta_item_list().unwrap() { + // If it's a tool lint (e.g. clippy::my_clippy_lint) + if let ast::NestedMetaItem::MetaItem(meta_item) = meta_list { + if meta_item.path.segments.len() == 1 { + self.lints_allowed.push(meta_list.name_or_empty().as_str().to_string()) + } else { + self.lints_allowed + .push(meta_item.path.segments[1].ident.name.as_str().to_string()); + } + } + } + } + } + } +} + pub struct LintLevelsBuilder<'s, P> { sess: &'s Session, features: &'s Features, @@ -931,7 +1043,8 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { } pub(crate) fn provide(providers: &mut Providers) { - *providers = Providers { shallow_lint_levels_on, ..*providers }; + *providers = + Providers { shallow_lint_levels_on, lints_that_can_emit, ..*providers }; } pub(crate) fn parse_lint_and_tool_name(lint_name: &str) -> (Option, &str) { diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 81352af3d48..5984810961f 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -170,7 +170,7 @@ early_lint_methods!( [ pub BuiltinCombinedEarlyLintPass, [ - UnusedParens: UnusedParens::new(), + UnusedParens: UnusedParens::default(), UnusedBraces: UnusedBraces, UnusedImportBraces: UnusedImportBraces, UnsafeCode: UnsafeCode, @@ -178,7 +178,7 @@ early_lint_methods!( AnonymousParameters: AnonymousParameters, EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(), NonCamelCaseTypes: NonCamelCaseTypes, - DeprecatedAttr: DeprecatedAttr::new(), + DeprecatedAttr: DeprecatedAttr::default(), WhileTrue: WhileTrue, NonAsciiIdents: NonAsciiIdents, HiddenUnicodeCodepoints: HiddenUnicodeCodepoints, @@ -601,25 +601,25 @@ fn register_builtins(store: &mut LintStore) { } fn register_internals(store: &mut LintStore) { - store.register_lints(&LintPassImpl::get_lints()); + store.register_lints(&LintPassImpl::default().get_lints()); store.register_early_pass(|| Box::new(LintPassImpl)); - store.register_lints(&DefaultHashTypes::get_lints()); + store.register_lints(&DefaultHashTypes::default().get_lints()); store.register_late_mod_pass(|_| Box::new(DefaultHashTypes)); - store.register_lints(&QueryStability::get_lints()); + store.register_lints(&QueryStability::default().get_lints()); store.register_late_mod_pass(|_| Box::new(QueryStability)); - store.register_lints(&ExistingDocKeyword::get_lints()); + store.register_lints(&ExistingDocKeyword::default().get_lints()); store.register_late_mod_pass(|_| Box::new(ExistingDocKeyword)); - store.register_lints(&TyTyKind::get_lints()); + store.register_lints(&TyTyKind::default().get_lints()); store.register_late_mod_pass(|_| Box::new(TyTyKind)); - store.register_lints(&TypeIr::get_lints()); + store.register_lints(&TypeIr::default().get_lints()); store.register_late_mod_pass(|_| Box::new(TypeIr)); - store.register_lints(&Diagnostics::get_lints()); + store.register_lints(&Diagnostics::default().get_lints()); store.register_late_mod_pass(|_| Box::new(Diagnostics)); - store.register_lints(&BadOptAccess::get_lints()); + store.register_lints(&BadOptAccess::default().get_lints()); store.register_late_mod_pass(|_| Box::new(BadOptAccess)); - store.register_lints(&PassByValue::get_lints()); + store.register_lints(&PassByValue::default().get_lints()); store.register_late_mod_pass(|_| Box::new(PassByValue)); - store.register_lints(&SpanUseEqCtxt::get_lints()); + store.register_lints(&SpanUseEqCtxt::default().get_lints()); store.register_late_mod_pass(|_| Box::new(SpanUseEqCtxt)); // FIXME(davidtwco): deliberately do not include `UNTRANSLATABLE_DIAGNOSTIC` and // `DIAGNOSTIC_OUTSIDE_OF_IMPL` here because `-Wrustc::internal` is provided to every crate and diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index a1d436e0d3d..3750f90a044 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -110,7 +110,7 @@ macro_rules! declare_combined_late_lint_pass { $v fn get_lints() -> $crate::LintVec { let mut lints = Vec::new(); - $(lints.extend_from_slice(&$pass::get_lints());)* + $(lints.extend_from_slice(&$pass::default().get_lints());)* lints } } @@ -124,6 +124,9 @@ macro_rules! declare_combined_late_lint_pass { fn name(&self) -> &'static str { panic!() } + fn get_lints(&self) -> LintVec { + panic!() + } } ) } @@ -222,7 +225,7 @@ macro_rules! declare_combined_early_lint_pass { $v fn get_lints() -> $crate::LintVec { let mut lints = Vec::new(); - $(lints.extend_from_slice(&$pass::get_lints());)* + $(lints.extend_from_slice(&$pass::default().get_lints());)* lints } } @@ -236,6 +239,9 @@ macro_rules! declare_combined_early_lint_pass { fn name(&self) -> &'static str { panic!() } + fn get_lints(&self) -> LintVec { + panic!() + } } ) } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index db4413149a4..1fafa7d6bde 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -165,7 +165,7 @@ declare_lint! { "detects ambiguous wide pointer comparisons" } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Default)] pub(crate) struct TypeLimits { /// Id of the last visited negated expression negated_expr_id: Option, diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 1a007250961..a05616bf486 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1025,8 +1025,8 @@ pub(crate) struct UnusedParens { parens_in_cast_in_lt: Vec, } -impl UnusedParens { - pub(crate) fn new() -> Self { +impl Default for UnusedParens { + fpub(crate) fn default() -> Self { Self { with_self_ty_parens: false, parens_in_cast_in_lt: Vec::new() } } } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 45a5ce0ca20..5c3b1bb71f3 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -378,7 +378,8 @@ declare_lint! { /// will not overflow. pub ARITHMETIC_OVERFLOW, Deny, - "arithmetic operation overflows" + "arithmetic operation overflows", + [loadbearing: true] } declare_lint! { @@ -633,7 +634,8 @@ declare_lint! { /// is only available in a newer version. pub UNKNOWN_LINTS, Warn, - "unrecognized lint attribute" + "unrecognized lint attribute", + [loadbearing: true] } declare_lint! { diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index c01fa5c54d6..691f37f0977 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -312,6 +312,10 @@ pub struct Lint { pub feature_gate: Option, pub crate_level_only: bool, + + /// `true` if this lint should not be filtered out under any circustamces + /// (e.g. the unknown_attributes lint) + pub loadbearing: bool, } /// Extra information for a future incompatibility lint. @@ -456,6 +460,7 @@ impl Lint { future_incompatible: None, feature_gate: None, crate_level_only: false, + loadbearing: false, } } @@ -863,7 +868,7 @@ macro_rules! declare_lint { $(#[$attr])* $vis $NAME, $Level, $desc, ); ); - ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr, + ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr, $([loadbearing: $loadbearing: literal])? $(@feature_gate = $gate:ident;)? $(@future_incompatible = FutureIncompatibleInfo { reason: $reason:expr, @@ -885,6 +890,7 @@ macro_rules! declare_lint { ..$crate::FutureIncompatibleInfo::default_fields_for_macro() }),)? $(edition_lint_opts: Some(($crate::Edition::$lint_edition, $crate::$edition_level)),)? + $(loadbearing: $loadbearing,)? ..$crate::Lint::default_fields_for_macro() }; ); @@ -895,6 +901,7 @@ macro_rules! declare_tool_lint { ( $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level: ident, $desc: expr $(, @feature_gate = $gate:ident;)? + $(, [loadbearing: $loadbearing: literal])? ) => ( $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, false $(, @feature_gate = $gate;)?} ); @@ -902,6 +909,7 @@ macro_rules! declare_tool_lint { $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr, report_in_external_macro: $rep:expr $(, @feature_gate = $gate:ident;)? + $(, [loadbearing: $loadbearing: literal])? ) => ( $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, $rep $(, @feature_gate = $gate;)?} ); @@ -909,6 +917,7 @@ macro_rules! declare_tool_lint { $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr, $external:expr $(, @feature_gate = $gate:ident;)? + $(, [loadbearing: $loadbearing: literal])? ) => ( $(#[$attr])* $vis static $NAME: &$crate::Lint = &$crate::Lint { @@ -921,6 +930,7 @@ macro_rules! declare_tool_lint { is_externally_loaded: true, $(feature_gate: Some(rustc_span::symbol::sym::$gate),)? crate_level_only: false, + $(loadbearing: $loadbearing,)? ..$crate::Lint::default_fields_for_macro() }; ); @@ -930,6 +940,7 @@ pub type LintVec = Vec<&'static Lint>; pub trait LintPass { fn name(&self) -> &'static str; + fn get_lints(&self) -> LintVec; } /// Implements `LintPass for $ty` with the given list of `Lint` statics. @@ -938,9 +949,7 @@ macro_rules! impl_lint_pass { ($ty:ty => [$($lint:expr),* $(,)?]) => { impl $crate::LintPass for $ty { fn name(&self) -> &'static str { stringify!($ty) } - } - impl $ty { - pub fn get_lints() -> $crate::LintVec { vec![$($lint),*] } + fn get_lints(&self) -> $crate::LintVec { vec![$($lint),*] } } }; } @@ -950,7 +959,18 @@ macro_rules! impl_lint_pass { #[macro_export] macro_rules! declare_lint_pass { ($(#[$m:meta])* $name:ident => [$($lint:expr),* $(,)?]) => { - $(#[$m])* #[derive(Copy, Clone)] pub struct $name; + $(#[$m])* #[derive(Copy, Clone, Default)] pub struct $name; $crate::impl_lint_pass!($name => [$($lint),*]); }; } + +#[allow(rustc::lint_pass_impl_without_macro)] +impl LintPass for Box

{ + fn name(&self) -> &'static str { + (**self).name() + } + + fn get_lints(&self) -> LintVec { + (**self).get_lints() + } +} diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index 8cb602d9ea8..485d1c14df3 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -27,6 +27,7 @@ rustc_graphviz = { path = "../rustc_graphviz" } rustc_hir = { path = "../rustc_hir" } rustc_hir_pretty = { path = "../rustc_hir_pretty" } rustc_index = { path = "../rustc_index" } +rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_macros = { path = "../rustc_macros" } rustc_query_system = { path = "../rustc_query_system" } rustc_serialize = { path = "../rustc_serialize" } diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index b5862565e8e..eaec19700c8 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -117,7 +117,7 @@ impl ShallowLintLevelMap { /// This lint level is not usable for diagnostics, it needs to be corrected by /// `reveal_actual_level` beforehand. #[instrument(level = "trace", skip(self, tcx), ret)] - fn probe_for_lint_level( + pub fn probe_for_lint_level( &self, tcx: TyCtxt<'_>, id: LintId, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index f8ba606e087..e90c3a4c23d 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -422,6 +422,11 @@ rustc_queries! { desc { "computing `#[expect]`ed lints in this crate" } } + query lints_that_can_emit(_: ()) -> &'tcx Lrc<(Vec, Vec)> { + arena_cache + desc { "Computing all lints that are explicitly enabled or with a default level greater than Allow" } + } + query expn_that_defined(key: DefId) -> rustc_span::ExpnId { desc { |tcx| "getting the expansion that defined `{}`", tcx.def_path_str(key) } separate_provide_extern diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs index bdfdeeabc5a..679fc45df76 100644 --- a/src/librustdoc/lint.rs +++ b/src/librustdoc/lint.rs @@ -2,7 +2,7 @@ use std::sync::LazyLock as Lazy; use rustc_data_structures::fx::FxHashMap; use rustc_lint::LintStore; -use rustc_lint_defs::{Lint, LintId, declare_tool_lint}; +use rustc_lint_defs::{Lint, LintId, LintPass, declare_tool_lint}; use rustc_session::{Session, lint}; /// This function is used to setup the lint initialization. By default, in rustdoc, everything @@ -31,9 +31,10 @@ where allowed_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned()); let lints = || { - lint::builtin::HardwiredLints::get_lints() + lint::builtin::HardwiredLints::default() + .get_lints() .into_iter() - .chain(rustc_lint::SoftLints::get_lints()) + .chain(rustc_lint::SoftLints::default().get_lints()) }; let lint_opts = lints() diff --git a/src/tools/clippy/clippy_lints/src/asm_syntax.rs b/src/tools/clippy/clippy_lints/src/asm_syntax.rs index 69a8eb7d94e..9f3c24a9e80 100644 --- a/src/tools/clippy/clippy_lints/src/asm_syntax.rs +++ b/src/tools/clippy/clippy_lints/src/asm_syntax.rs @@ -3,7 +3,7 @@ use std::fmt; use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::ast::{Expr, ExprKind, InlineAsmOptions}; use rustc_ast::{InlineAsm, Item, ItemKind}; -use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintContext}; +use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintPass, LintContext}; use rustc_session::declare_lint_pass; use rustc_span::Span; use rustc_target::asm::InlineAsmArch; diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/author.rs similarity index 99% rename from src/tools/clippy/clippy_lints/src/utils/author.rs rename to src/tools/clippy/clippy_lints/src/utils/internal_lints/author.rs index 31f9d84f5e4..0ed606a836e 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/author.rs @@ -12,7 +12,7 @@ use rustc_span::symbol::{Ident, Symbol}; use std::cell::Cell; use std::fmt::{Display, Formatter, Write as _}; -declare_lint_pass!( +declare_clippy_lint!{ /// ### What it does /// Generates clippy code that detects the offending pattern /// @@ -44,8 +44,13 @@ declare_lint_pass!( /// // report your lint here /// } /// ``` - Author => [] -); + #[clippy::version = "1.0.0"] + pub AUTHOR, + internal, + "The author lint, see documentation at " +}; + +declare_lint_pass! { Author => [AUTHOR] } /// Writes a line of output with indentation added macro_rules! out { diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs index 13e9ead9a57..abd10ac024c 100644 --- a/src/tools/clippy/clippy_lints/src/utils/mod.rs +++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs @@ -1,4 +1,3 @@ -pub mod author; pub mod dump_hir; pub mod format_args_collector; #[cfg(feature = "internal")] diff --git a/src/tools/clippy/tests/ui/author.rs b/src/tools/clippy/tests/ui-internal/author.rs similarity index 72% rename from src/tools/clippy/tests/ui/author.rs rename to src/tools/clippy/tests/ui-internal/author.rs index 0a1be356896..eb1f3e3f870 100644 --- a/src/tools/clippy/tests/ui/author.rs +++ b/src/tools/clippy/tests/ui-internal/author.rs @@ -1,3 +1,5 @@ +#![warn(clippy::author)] + fn main() { #[clippy::author] let x: char = 0x45 as char; diff --git a/src/tools/clippy/tests/ui/author.stdout b/src/tools/clippy/tests/ui-internal/author.stdout similarity index 100% rename from src/tools/clippy/tests/ui/author.stdout rename to src/tools/clippy/tests/ui-internal/author.stdout diff --git a/src/tools/clippy/tests/ui/author/blocks.rs b/src/tools/clippy/tests/ui-internal/author/blocks.rs similarity index 100% rename from src/tools/clippy/tests/ui/author/blocks.rs rename to src/tools/clippy/tests/ui-internal/author/blocks.rs diff --git a/src/tools/clippy/tests/ui/author/blocks.stdout b/src/tools/clippy/tests/ui-internal/author/blocks.stdout similarity index 100% rename from src/tools/clippy/tests/ui/author/blocks.stdout rename to src/tools/clippy/tests/ui-internal/author/blocks.stdout diff --git a/src/tools/clippy/tests/ui/author/call.rs b/src/tools/clippy/tests/ui-internal/author/call.rs similarity index 100% rename from src/tools/clippy/tests/ui/author/call.rs rename to src/tools/clippy/tests/ui-internal/author/call.rs diff --git a/src/tools/clippy/tests/ui/author/call.stdout b/src/tools/clippy/tests/ui-internal/author/call.stdout similarity index 100% rename from src/tools/clippy/tests/ui/author/call.stdout rename to src/tools/clippy/tests/ui-internal/author/call.stdout diff --git a/src/tools/clippy/tests/ui/author/if.rs b/src/tools/clippy/tests/ui-internal/author/if.rs similarity index 100% rename from src/tools/clippy/tests/ui/author/if.rs rename to src/tools/clippy/tests/ui-internal/author/if.rs diff --git a/src/tools/clippy/tests/ui/author/if.stdout b/src/tools/clippy/tests/ui-internal/author/if.stdout similarity index 100% rename from src/tools/clippy/tests/ui/author/if.stdout rename to src/tools/clippy/tests/ui-internal/author/if.stdout diff --git a/src/tools/clippy/tests/ui/author/issue_3849.rs b/src/tools/clippy/tests/ui-internal/author/issue_3849.rs similarity index 100% rename from src/tools/clippy/tests/ui/author/issue_3849.rs rename to src/tools/clippy/tests/ui-internal/author/issue_3849.rs diff --git a/src/tools/clippy/tests/ui/author/issue_3849.stdout b/src/tools/clippy/tests/ui-internal/author/issue_3849.stdout similarity index 100% rename from src/tools/clippy/tests/ui/author/issue_3849.stdout rename to src/tools/clippy/tests/ui-internal/author/issue_3849.stdout diff --git a/src/tools/clippy/tests/ui/author/loop.rs b/src/tools/clippy/tests/ui-internal/author/loop.rs similarity index 100% rename from src/tools/clippy/tests/ui/author/loop.rs rename to src/tools/clippy/tests/ui-internal/author/loop.rs diff --git a/src/tools/clippy/tests/ui/author/loop.stdout b/src/tools/clippy/tests/ui-internal/author/loop.stdout similarity index 100% rename from src/tools/clippy/tests/ui/author/loop.stdout rename to src/tools/clippy/tests/ui-internal/author/loop.stdout diff --git a/src/tools/clippy/tests/ui/author/macro_in_closure.rs b/src/tools/clippy/tests/ui-internal/author/macro_in_closure.rs similarity index 100% rename from src/tools/clippy/tests/ui/author/macro_in_closure.rs rename to src/tools/clippy/tests/ui-internal/author/macro_in_closure.rs diff --git a/src/tools/clippy/tests/ui/author/macro_in_closure.stdout b/src/tools/clippy/tests/ui-internal/author/macro_in_closure.stdout similarity index 100% rename from src/tools/clippy/tests/ui/author/macro_in_closure.stdout rename to src/tools/clippy/tests/ui-internal/author/macro_in_closure.stdout diff --git a/src/tools/clippy/tests/ui/author/macro_in_loop.rs b/src/tools/clippy/tests/ui-internal/author/macro_in_loop.rs similarity index 100% rename from src/tools/clippy/tests/ui/author/macro_in_loop.rs rename to src/tools/clippy/tests/ui-internal/author/macro_in_loop.rs diff --git a/src/tools/clippy/tests/ui/author/macro_in_loop.stdout b/src/tools/clippy/tests/ui-internal/author/macro_in_loop.stdout similarity index 100% rename from src/tools/clippy/tests/ui/author/macro_in_loop.stdout rename to src/tools/clippy/tests/ui-internal/author/macro_in_loop.stdout diff --git a/src/tools/clippy/tests/ui/author/matches.rs b/src/tools/clippy/tests/ui-internal/author/matches.rs similarity index 100% rename from src/tools/clippy/tests/ui/author/matches.rs rename to src/tools/clippy/tests/ui-internal/author/matches.rs diff --git a/src/tools/clippy/tests/ui/author/matches.stdout b/src/tools/clippy/tests/ui-internal/author/matches.stdout similarity index 100% rename from src/tools/clippy/tests/ui/author/matches.stdout rename to src/tools/clippy/tests/ui-internal/author/matches.stdout diff --git a/src/tools/clippy/tests/ui/author/repeat.rs b/src/tools/clippy/tests/ui-internal/author/repeat.rs similarity index 100% rename from src/tools/clippy/tests/ui/author/repeat.rs rename to src/tools/clippy/tests/ui-internal/author/repeat.rs diff --git a/src/tools/clippy/tests/ui/author/repeat.stdout b/src/tools/clippy/tests/ui-internal/author/repeat.stdout similarity index 100% rename from src/tools/clippy/tests/ui/author/repeat.stdout rename to src/tools/clippy/tests/ui-internal/author/repeat.stdout diff --git a/src/tools/clippy/tests/ui/author/struct.rs b/src/tools/clippy/tests/ui-internal/author/struct.rs similarity index 100% rename from src/tools/clippy/tests/ui/author/struct.rs rename to src/tools/clippy/tests/ui-internal/author/struct.rs diff --git a/src/tools/clippy/tests/ui/author/struct.stdout b/src/tools/clippy/tests/ui-internal/author/struct.stdout similarity index 100% rename from src/tools/clippy/tests/ui/author/struct.stdout rename to src/tools/clippy/tests/ui-internal/author/struct.stdout diff --git a/src/tools/clippy/tests/ui/no_lints.rs b/src/tools/clippy/tests/ui/no_lints.rs new file mode 100644 index 00000000000..a8467bb6ef7 --- /dev/null +++ b/src/tools/clippy/tests/ui/no_lints.rs @@ -0,0 +1,3 @@ +#![deny(clippy::all)] + +fn main() {} \ No newline at end of file diff --git a/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs b/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs index c3df917ed12..6eb698c96f6 100644 --- a/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs +++ b/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs @@ -6,7 +6,7 @@ extern crate rustc_middle; extern crate rustc_session; -use rustc_session::lint::{LintPass, LintVec}; +use rustc_session::lint::{LintPass, LintVec, Lint}; use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass}; declare_lint! { @@ -21,6 +21,10 @@ impl LintPass for Foo { //~ERROR implementing `LintPass` by hand fn name(&self) -> &'static str { "Foo" } + + fn get_lints(&self) -> Vec<&'static Lint> { + vec![TEST_LINT] + } } macro_rules! custom_lint_pass_macro { @@ -31,6 +35,10 @@ macro_rules! custom_lint_pass_macro { fn name(&self) -> &'static str { "Custom" } + + fn get_lints(&self) -> Vec<&'static Lint> { + vec![TEST_LINT] + } } }; } diff --git a/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr b/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr index ad6e93334cd..824eb35424d 100644 --- a/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr +++ b/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr @@ -12,7 +12,7 @@ LL | #![deny(rustc::lint_pass_impl_without_macro)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: implementing `LintPass` by hand - --> $DIR/lint_pass_impl_without_macro.rs:30:14 + --> $DIR/lint_pass_impl_without_macro.rs:34:14 | LL | impl LintPass for Custom { | ^^^^^^^^ From edc65776274d14fc7f7f93de66ac3b2d15bbbc37 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Mon, 27 May 2024 13:58:33 +0200 Subject: [PATCH 2/7] Change lints_to_emit to lints_that_actually_run --- compiler/rustc_lint/src/late.rs | 6 +-- compiler/rustc_lint/src/levels.rs | 40 ++++++++++--------- compiler/rustc_lint/src/shadowed_into_iter.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 2 +- 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index ccd06ba612b..c7187ee1b30 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -373,8 +373,8 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>( store.late_module_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect(); // Filter unused lints - let (lints_to_emit, lints_allowed) = &**tcx.lints_that_can_emit(()); - // let lints_to_emit = &lints_that_can_emit.0; + let (lints_that_actually_run, lints_allowed) = &**tcx.lints_that_can_emit(()); + // let lints_that_actually_run = &lints_that_can_emit.0; // let lints_allowed = &lints_that_can_emit.1; // Now, we'll filtered passes in a way that discards any lint that won't trigger. @@ -386,7 +386,7 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>( let pass = LintPass::get_lints(pass); pass.iter().any(|&lint| { let lint_name = name_without_tool(&lint.name.to_lowercase()).to_string(); - lints_to_emit.contains(&lint_name) + lints_that_actually_run.contains(&lint_name) || (!lints_allowed.contains(&lint_name) && lint.default_level != crate::Level::Allow) }) diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 7ee8618bc55..527fc117351 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -1,6 +1,6 @@ use rustc_ast_pretty::pprust; -use rustc_data_structures::{fx::FxIndexMap, sync::Lrc}; -use rustc_errors::{Diag, DiagMessage, LintDiagnostic, MultiSpan}; +use rustc_data_structures::{fx::FxIndexMap, fx::FxIndexSet, sync::Lrc}; +use rustc_errors::{Diag, LintDiagnostic, MultiSpan}; use rustc_feature::{Features, GateIssue}; use rustc_hir::HirId; use rustc_hir::intravisit::{self, Visitor}; @@ -120,7 +120,7 @@ impl LintLevelSets { /// (and not allowed in the crate) and CLI lints. The returned value is a tuple /// of 1. The lints that will emit (or at least, should run), and 2. /// The lints that are allowed at the crate level and will not emit. -pub fn lints_that_can_emit(tcx: TyCtxt<'_>, (): ()) -> Lrc<(Vec, Vec)> { +pub fn lints_that_can_emit(tcx: TyCtxt<'_>, (): ()) -> Lrc<(FxIndexSet, FxIndexSet)> { let mut visitor = LintLevelMinimum::new(tcx); visitor.process_opts(); tcx.hir().walk_attributes(&mut visitor); @@ -131,18 +131,18 @@ pub fn lints_that_can_emit(tcx: TyCtxt<'_>, (): ()) -> Lrc<(Vec, Vec Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> { struct LintLevelMinimum<'tcx> { tcx: TyCtxt<'tcx>, /// The actual list of detected lints. - lints_to_emit: Vec, - lints_allowed: Vec, + lints_that_actually_run: FxIndexSet, + lints_allowed: FxIndexSet, } impl<'tcx> LintLevelMinimum<'tcx> { pub fn new(tcx: TyCtxt<'tcx>) -> Self { + let mut lints_that_actually_run = FxIndexSet::default(); + lints_that_actually_run.reserve(230); + let mut lints_allowed = FxIndexSet::default(); + lints_allowed.reserve(100); Self { tcx, // That magic number is the current number of lints + some more for possible future lints - lints_to_emit: Vec::with_capacity(230), - lints_allowed: Vec::with_capacity(100), + lints_that_actually_run, + lints_allowed, } } fn process_opts(&mut self) { for (lint, level) in &self.tcx.sess.opts.lint_opts { if *level == Level::Allow { - self.lints_allowed.push(lint.clone()); + self.lints_allowed.insert(lint.clone()); } else { - self.lints_to_emit.push(lint.to_string()); + self.lints_that_actually_run.insert(lint.to_string()); } } } @@ -383,13 +387,13 @@ impl<'tcx> Visitor<'tcx> for LintLevelMinimum<'tcx> { // If it's a tool lint (e.g. clippy::my_clippy_lint) if let ast::NestedMetaItem::MetaItem(meta_item) = meta_list { if meta_item.path.segments.len() == 1 { - self.lints_to_emit.push( + self.lints_that_actually_run.insert( // SAFETY: Lint attributes can only have literals meta_list.ident().unwrap().name.as_str().to_string(), ); } else { - self.lints_to_emit - .push(meta_item.path.segments[1].ident.name.as_str().to_string()); + self.lints_that_actually_run + .insert(meta_item.path.segments[1].ident.name.as_str().to_string()); } } } @@ -401,10 +405,10 @@ impl<'tcx> Visitor<'tcx> for LintLevelMinimum<'tcx> { // If it's a tool lint (e.g. clippy::my_clippy_lint) if let ast::NestedMetaItem::MetaItem(meta_item) = meta_list { if meta_item.path.segments.len() == 1 { - self.lints_allowed.push(meta_list.name_or_empty().as_str().to_string()) + self.lints_allowed.insert(meta_list.name_or_empty().as_str().to_string()); } else { self.lints_allowed - .push(meta_item.path.segments[1].ident.name.as_str().to_string()); + .insert(meta_item.path.segments[1].ident.name.as_str().to_string()); } } } diff --git a/compiler/rustc_lint/src/shadowed_into_iter.rs b/compiler/rustc_lint/src/shadowed_into_iter.rs index a73904cd776..33a4ae60663 100644 --- a/compiler/rustc_lint/src/shadowed_into_iter.rs +++ b/compiler/rustc_lint/src/shadowed_into_iter.rs @@ -64,7 +64,7 @@ declare_lint! { }; } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Default)] pub(crate) struct ShadowedIntoIter; impl_lint_pass!(ShadowedIntoIter => [ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER]); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index e90c3a4c23d..b6cb11a2a2c 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -422,7 +422,7 @@ rustc_queries! { desc { "computing `#[expect]`ed lints in this crate" } } - query lints_that_can_emit(_: ()) -> &'tcx Lrc<(Vec, Vec)> { + query lints_that_can_emit(_: ()) -> &'tcx Lrc<(FxIndexSet, FxIndexSet)> { arena_cache desc { "Computing all lints that are explicitly enabled or with a default level greater than Allow" } } From 71b4d108c7e71c15c0f61d737ebdc0e1cf559d3c Mon Sep 17 00:00:00 2001 From: blyxyas Date: Tue, 18 Jun 2024 22:44:28 +0200 Subject: [PATCH 3/7] Follow review comments (optimize the filtering) --- compiler/rustc_interface/src/passes.rs | 2 +- compiler/rustc_lint/src/builtin.rs | 7 +- compiler/rustc_lint/src/late.rs | 64 +++--- compiler/rustc_lint/src/levels.rs | 202 +++++++++++------- compiler/rustc_lint/src/lib.rs | 2 +- compiler/rustc_lint/src/passes.rs | 13 +- compiler/rustc_lint/src/unused.rs | 2 +- compiler/rustc_lint_defs/src/builtin.rs | 5 +- compiler/rustc_middle/src/query/mod.rs | 3 +- compiler/rustc_session/src/session.rs | 1 + .../clippy/clippy_lints/src/asm_syntax.rs | 2 +- .../clippy_lints/src/cognitive_complexity.rs | 54 +++-- src/tools/clippy/clippy_lints/src/ctfe.rs | 54 +++++ src/tools/clippy/clippy_lints/src/lib.rs | 3 + .../src/utils/{internal_lints => }/author.rs | 12 +- .../clippy/clippy_lints/src/utils/mod.rs | 1 + 16 files changed, 276 insertions(+), 151 deletions(-) create mode 100644 src/tools/clippy/clippy_lints/src/ctfe.rs rename src/tools/clippy/clippy_lints/src/utils/{internal_lints => }/author.rs (99%) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index fd850d2f39a..608d66184f0 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -972,7 +972,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { tcx.ensure().check_mod_privacy(module); }); }); - } + } // { sess.time("mir_checking", || { tcx.hir().mir_for }) } ); // This check has to be run after all lints are done processing. We don't diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index acd12f7f20d..33c87bbfb70 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -20,6 +20,7 @@ //! If you define a new `LateLintPass`, you will also need to add it to the //! `late_lint_methods!` invocation in `lib.rs`. +use std::default::Default; use std::fmt::Write; use ast::token::TokenKind; @@ -73,12 +74,10 @@ use crate::{ EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext, fluent_generated as fluent, }; - -use std::default::Default; -use std::fmt::Write; +// use std::fmt::Write; // hardwired lints from rustc_lint_defs -pub use rustc_session::lint::builtin::*; +// pub use rustc_session::lint::builtin::*; declare_lint! { /// The `while_true` lint detects `while true { }`. diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index c7187ee1b30..f8bd873cdf5 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -24,13 +24,12 @@ use rustc_hir::def_id::{LocalDefId, LocalModDefId}; use rustc_hir::{HirId, intravisit as hir_visit}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, TyCtxt}; -use rustc_session::Session; -use rustc_session::lint::LintPass; +use rustc_session::{Session, lint::{LintPass, builtin::HardwiredLints}}; use rustc_span::Span; use tracing::debug; use crate::passes::LateLintPassObject; -use crate::{LateContext, LateLintPass, LintStore}; +use crate::{LateContext, LateLintPass, LintId, LintStore}; /// Extract the [`LintStore`] from [`Session`]. /// @@ -371,29 +370,24 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>( } else { let passes: Vec<_> = store.late_module_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect(); - // Filter unused lints - let (lints_that_actually_run, lints_allowed) = &**tcx.lints_that_can_emit(()); - // let lints_that_actually_run = &lints_that_can_emit.0; - // let lints_allowed = &lints_that_can_emit.1; - - // Now, we'll filtered passes in a way that discards any lint that won't trigger. - // If any lint is a given pass is detected to be emitted, we will keep that pass. - // Otherwise, we don't + let lints_that_dont_need_to_run = tcx.lints_that_dont_need_to_run(()); let mut filtered_passes: Vec>> = passes .into_iter() .filter(|pass| { - let pass = LintPass::get_lints(pass); - pass.iter().any(|&lint| { - let lint_name = name_without_tool(&lint.name.to_lowercase()).to_string(); - lints_that_actually_run.contains(&lint_name) - || (!lints_allowed.contains(&lint_name) - && lint.default_level != crate::Level::Allow) - }) + let lints = LintPass::get_lints(pass); + if lints.is_empty() { + true + } else { + lints + .iter() + .any(|lint| !lints_that_dont_need_to_run.contains(&LintId::of(lint))) + } }) .collect(); filtered_passes.push(Box::new(builtin_lints)); + filtered_passes.push(Box::new(HardwiredLints)); let pass = RuntimeCombinedLateLintPass { passes: &mut filtered_passes[..] }; late_lint_mod_inner(tcx, module_def_id, context, pass); @@ -426,7 +420,7 @@ fn late_lint_mod_inner<'tcx, T: LateLintPass<'tcx>>( fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) { // Note: `passes` is often empty. - let mut passes: Vec<_> = + let passes: Vec<_> = unerased_lint_store(tcx.sess).late_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect(); if passes.is_empty() { @@ -444,7 +438,30 @@ fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) { only_module: false, }; - let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] }; + let lints_that_dont_need_to_run = tcx.lints_that_dont_need_to_run(()); + + // dbg!(&lints_that_dont_need_to_run); + let mut filtered_passes: Vec>> = passes + .into_iter() + .filter(|pass| { + let lints = LintPass::get_lints(pass); + !lints.iter().all(|lint| lints_that_dont_need_to_run.contains(&LintId::of(lint))) + }) + .collect(); + + filtered_passes.push(Box::new(HardwiredLints)); + + // let mut filtered_passes: Vec>> = passes + // .into_iter() + // .filter(|pass| { + // let lints = LintPass::get_lints(pass); + // lints.iter() + // .any(|lint| + // !lints_that_dont_need_to_run.contains(&LintId::of(lint))) + // }).collect(); + // + + let pass = RuntimeCombinedLateLintPass { passes: &mut filtered_passes[..] }; late_lint_crate_inner(tcx, context, pass); } @@ -482,10 +499,3 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>) { }, ); } - -/// Format name ignoring the name, useful for filtering non-used lints. -/// For example, 'clippy::my_lint' will turn into 'my_lint' -pub(crate) fn name_without_tool(name: &str) -> &str { - // Doing some calculations here to account for those separators - name.rsplit("::").next().unwrap_or(name) -} diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 527fc117351..f5323c295d0 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -1,5 +1,5 @@ use rustc_ast_pretty::pprust; -use rustc_data_structures::{fx::FxIndexMap, fx::FxIndexSet, sync::Lrc}; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::{Diag, LintDiagnostic, MultiSpan}; use rustc_feature::{Features, GateIssue}; use rustc_hir::HirId; @@ -31,7 +31,7 @@ use crate::errors::{ OverruledAttributeSub, RequestedLevel, UnknownToolInScopedLint, UnsupportedGroup, }; use crate::fluent_generated as fluent; -use crate::late::{unerased_lint_store, name_without_tool}; +use crate::late::{unerased_lint_store /*name_without_tool*/}; use crate::lints::{ DeprecatedLintName, DeprecatedLintNameFromCommandLine, IgnoredUnlessCrateSpecified, OverruledAttributeLint, RemovedLint, RemovedLintFromCommandLine, RenamedLint, @@ -115,34 +115,41 @@ impl LintLevelSets { } } -/// Walk the whole crate collecting nodes where lint levels change -/// (e.g. `#[allow]` attributes), and joins that list with the warn-by-default -/// (and not allowed in the crate) and CLI lints. The returned value is a tuple -/// of 1. The lints that will emit (or at least, should run), and 2. -/// The lints that are allowed at the crate level and will not emit. -pub fn lints_that_can_emit(tcx: TyCtxt<'_>, (): ()) -> Lrc<(FxIndexSet, FxIndexSet)> { - let mut visitor = LintLevelMinimum::new(tcx); +fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet { + let store = unerased_lint_store(&tcx.sess); + + let dont_need_to_run: FxIndexSet = store + .get_lints() + .into_iter() + .filter_map(|lint| { + if !lint.loadbearing && lint.default_level(tcx.sess.edition()) == Level::Allow { + Some(LintId::of(lint)) + } else { + None + } + }) + .collect(); + + let mut visitor = LintLevelMaximum { tcx, dont_need_to_run }; visitor.process_opts(); tcx.hir().walk_attributes(&mut visitor); - let store = unerased_lint_store(&tcx.sess); + // let lint_groups = store.get_lint_groups(); + // for group in lint_groups { + // let binding = group.0.to_lowercase(); + // let group_name = name_without_tool(&binding).to_string(); + // if visitor.lints_that_actually_run.contains(&group_name) { + // for lint in group.1 { + // visitor.lints_that_actually_run.insert(name_without_tool(&lint.to_string()).to_string()); + // } + // } else if visitor.lints_allowed.contains(&group_name) { + // for lint in &group.1 { + // visitor.lints_allowed.insert(name_without_tool(&lint.to_string()).to_string()); + // } + // } + // } - let lint_groups = store.get_lint_groups(); - for group in lint_groups { - let binding = group.0.to_lowercase(); - let group_name = name_without_tool(&binding).to_string(); - if visitor.lints_that_actually_run.contains(&group_name) { - for lint in group.1 { - visitor.lints_that_actually_run.insert(name_without_tool(&lint.to_string()).to_string()); - } - } else if visitor.lints_allowed.contains(&group_name) { - for lint in &group.1 { - visitor.lints_allowed.insert(name_without_tool(&lint.to_string()).to_string()); - } - } - } - - Lrc::new((visitor.lints_that_actually_run, visitor.lints_allowed)) + visitor.dont_need_to_run } #[instrument(level = "trace", skip(tcx), ret)] @@ -336,39 +343,29 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> { /// /// E.g., if a crate has a global #![allow(lint)] attribute, but a single item /// uses #[warn(lint)], this visitor will set that lint level as `Warn` -struct LintLevelMinimum<'tcx> { +struct LintLevelMaximum<'tcx> { tcx: TyCtxt<'tcx>, /// The actual list of detected lints. - lints_that_actually_run: FxIndexSet, - lints_allowed: FxIndexSet, + dont_need_to_run: FxIndexSet, } -impl<'tcx> LintLevelMinimum<'tcx> { - pub fn new(tcx: TyCtxt<'tcx>) -> Self { - let mut lints_that_actually_run = FxIndexSet::default(); - lints_that_actually_run.reserve(230); - let mut lints_allowed = FxIndexSet::default(); - lints_allowed.reserve(100); - Self { - tcx, - // That magic number is the current number of lints + some more for possible future lints - lints_that_actually_run, - lints_allowed, - } - } - +impl<'tcx> LintLevelMaximum<'tcx> { fn process_opts(&mut self) { - for (lint, level) in &self.tcx.sess.opts.lint_opts { - if *level == Level::Allow { - self.lints_allowed.insert(lint.clone()); - } else { - self.lints_that_actually_run.insert(lint.to_string()); + let store = unerased_lint_store(self.tcx.sess); + for (lint_group, level) in &self.tcx.sess.opts.lint_opts { + if *level != Level::Allow { + let Ok(lints) = store.find_lints(lint_group) else { + return; + }; + for lint in lints { + self.dont_need_to_run.swap_remove(&lint); + } } } } } -impl<'tcx> Visitor<'tcx> for LintLevelMinimum<'tcx> { +impl<'tcx> Visitor<'tcx> for LintLevelMaximum<'tcx> { type NestedFilter = nested_filter::All; fn nested_visit_map(&mut self) -> Self::Map { @@ -376,42 +373,82 @@ impl<'tcx> Visitor<'tcx> for LintLevelMinimum<'tcx> { } fn visit_attribute(&mut self, attribute: &'tcx ast::Attribute) { - if let Some(meta) = attribute.meta() { - if [sym::warn, sym::deny, sym::forbid, sym::expect] - .iter() - .any(|kind| meta.has_name(*kind)) - { + match Level::from_attr(attribute) { + Some( + Level::Warn + | Level::Deny + | Level::Forbid + | Level::Expect(..) + | Level::ForceWarn(..), + ) => { + let store = unerased_lint_store(self.tcx.sess); + let Some(meta) = attribute.meta() else { return }; // SAFETY: Lint attributes are always a metalist inside a // metalist (even with just one lint). - for meta_list in meta.meta_item_list().unwrap() { - // If it's a tool lint (e.g. clippy::my_clippy_lint) - if let ast::NestedMetaItem::MetaItem(meta_item) = meta_list { - if meta_item.path.segments.len() == 1 { - self.lints_that_actually_run.insert( - // SAFETY: Lint attributes can only have literals - meta_list.ident().unwrap().name.as_str().to_string(), - ); - } else { - self.lints_that_actually_run - .insert(meta_item.path.segments[1].ident.name.as_str().to_string()); - } - } - } - // We handle #![allow]s differently, as these remove checking rather than adding. - } else if meta.has_name(sym::allow) - && let ast::AttrStyle::Inner = attribute.style - { - for meta_list in meta.meta_item_list().unwrap() { - // If it's a tool lint (e.g. clippy::my_clippy_lint) - if let ast::NestedMetaItem::MetaItem(meta_item) = meta_list { - if meta_item.path.segments.len() == 1 { - self.lints_allowed.insert(meta_list.name_or_empty().as_str().to_string()); - } else { - self.lints_allowed - .insert(meta_item.path.segments[1].ident.name.as_str().to_string()); - } + let Some(meta_item_list) = meta.meta_item_list() else { return }; + + for meta_list in meta_item_list { + // Convert Path to String + let Some(meta_item) = meta_list.meta_item() else { return }; + let ident: &str = &meta_item + .path + .segments + .iter() + .map(|segment| segment.ident.as_str()) + .collect::>() + .join("::"); + let Ok(lints) = store.find_lints( + // SAFETY: Lint attributes can only have literals + ident, + ) else { + return; + }; + for lint in lints { + self.dont_need_to_run.swap_remove(&lint); } + // // If it's a tool lint (e.g. clippy::my_clippy_lint) + // if let ast::NestedMetaItem::MetaItem(meta_item) = meta_list { + // if meta_item.path.segments.len() == 1 { + // let Ok(lints) = store.find_lints( + // // SAFETY: Lint attributes can only have literals + // meta_list.ident().unwrap().name.as_str(), + // ) else { + // return; + // }; + // for lint in lints { + // dbg!("LINT REMOVED", &lint); + // self.dont_need_to_run.swap_remove(&lint); + // } + // } else { + // let Ok(lints) = store.find_lints( + // // SAFETY: Lint attributes can only have literals + // meta_item.path.segments[1].ident.name.as_str(), + // ) else { + // return; + // }; + // for lint in lints { + // dbg!("LINT REMOVED", &lint); + // self.dont_need_to_run.swap_remove(&lint); + // } + // } } + // We handle #![allow]s differently, as these remove checking rather than adding. + } // Some(Level::Allow) if ast::AttrStyle::Inner == attribute.style => { + // for meta_list in meta.meta_item_list().unwrap() { + // // If it's a tool lint (e.g. clippy::my_clippy_lint) + // if let ast::NestedMetaItem::MetaItem(meta_item) = meta_list { + // if meta_item.path.segments.len() == 1 { + // self.lints_allowed + // .insert(meta_list.name_or_empty().as_str().to_string()); + // } else { + // self.lints_allowed + // .insert(meta_item.path.segments[1].ident.name.as_str().to_string()); + // } + // } + // } + // } + _ => { + return; } } } @@ -1047,8 +1084,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { } pub(crate) fn provide(providers: &mut Providers) { - *providers = - Providers { shallow_lint_levels_on, lints_that_can_emit, ..*providers }; + *providers = Providers { shallow_lint_levels_on, lints_that_dont_need_to_run, ..*providers }; } pub(crate) fn parse_lint_and_tool_name(lint_name: &str) -> (Option, &str) { diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 5984810961f..11dd17bcd4a 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -199,7 +199,6 @@ late_lint_methods!( ForLoopsOverFallibles: ForLoopsOverFallibles, DerefIntoDynSupertrait: DerefIntoDynSupertrait, DropForgetUseless: DropForgetUseless, - HardwiredLints: HardwiredLints, ImproperCTypesDeclarations: ImproperCTypesDeclarations, ImproperCTypesDefinitions: ImproperCTypesDefinitions, InvalidFromUtf8: InvalidFromUtf8, @@ -280,6 +279,7 @@ fn register_builtins(store: &mut LintStore) { store.register_lints(&BuiltinCombinedEarlyLintPass::get_lints()); store.register_lints(&BuiltinCombinedModuleLateLintPass::get_lints()); store.register_lints(&foreign_modules::get_lints()); + store.register_lints(&HardwiredLints::default().get_lints()); add_lint_group!( "nonstandard_style", diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index 3750f90a044..6dbcdefe08d 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -70,7 +70,18 @@ macro_rules! declare_late_lint_pass { // for all the `check_*` methods. late_lint_methods!(declare_late_lint_pass, []); -impl LateLintPass<'_> for HardwiredLints {} +impl LateLintPass<'_> for HardwiredLints { + fn check_fn( + &mut self, + _: &LateContext<'_>, + _: rustc_hir::intravisit::FnKind<'_>, + _: &'_ rustc_hir::FnDecl<'_>, + _: &'_ rustc_hir::Body<'_>, + _: rustc_span::Span, + _: rustc_span::def_id::LocalDefId, + ) { + } +} #[macro_export] macro_rules! expand_combined_late_lint_pass_method { diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index a05616bf486..a7ac847c018 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1026,7 +1026,7 @@ pub(crate) struct UnusedParens { } impl Default for UnusedParens { - fpub(crate) fn default() -> Self { + fn default() -> Self { Self { with_self_ty_parens: false, parens_in_cast_in_lt: Vec::new() } } } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 5c3b1bb71f3..df86e9de22e 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -12,8 +12,6 @@ use rustc_span::edition::Edition; use crate::{FutureIncompatibilityReason, declare_lint, declare_lint_pass}; declare_lint_pass! { - /// Does nothing as a lint pass, but registers some `Lint`s - /// that are used by other parts of the compiler. HardwiredLints => [ // tidy-alphabetical-start ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, @@ -403,7 +401,8 @@ declare_lint! { /// `panic!` or `unreachable!` macro instead in case the panic is intended. pub UNCONDITIONAL_PANIC, Deny, - "operation will cause a panic at runtime" + "operation will cause a panic at runtime", + [loadbearing: true] } declare_lint! { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index b6cb11a2a2c..99e166286d2 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -29,6 +29,7 @@ use rustc_hir::def_id::{ use rustc_hir::lang_items::{LangItem, LanguageItems}; use rustc_hir::{Crate, ItemLocalId, ItemLocalMap, TraitCandidate}; use rustc_index::IndexVec; +use rustc_lint_defs::LintId; use rustc_macros::rustc_queries; use rustc_query_system::ich::StableHashingContext; use rustc_query_system::query::{QueryCache, QueryMode, QueryState, try_get_cached}; @@ -422,7 +423,7 @@ rustc_queries! { desc { "computing `#[expect]`ed lints in this crate" } } - query lints_that_can_emit(_: ()) -> &'tcx Lrc<(FxIndexSet, FxIndexSet)> { + query lints_that_dont_need_to_run(_: ()) -> &'tcx FxIndexSet { arena_cache desc { "Computing all lints that are explicitly enabled or with a default level greater than Allow" } } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 27879d817b2..c8f46226a3e 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -187,6 +187,7 @@ pub struct Session { /// errors. pub ctfe_backtrace: Lock, + // pub force_ctfe: bool, /// This tracks where `-Zunleash-the-miri-inside-of-you` was used to get around a /// const check, optionally with the relevant feature gate. We use this to /// warn about unleashing, but with a single diagnostic instead of dozens that diff --git a/src/tools/clippy/clippy_lints/src/asm_syntax.rs b/src/tools/clippy/clippy_lints/src/asm_syntax.rs index 9f3c24a9e80..69a8eb7d94e 100644 --- a/src/tools/clippy/clippy_lints/src/asm_syntax.rs +++ b/src/tools/clippy/clippy_lints/src/asm_syntax.rs @@ -3,7 +3,7 @@ use std::fmt; use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::ast::{Expr, ExprKind, InlineAsmOptions}; use rustc_ast::{InlineAsm, Item, ItemKind}; -use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintPass, LintContext}; +use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintContext}; use rustc_session::declare_lint_pass; use rustc_span::Span; use rustc_target::asm::InlineAsmArch; diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs index 495d8ce3fa7..b027c289a7f 100644 --- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs @@ -8,30 +8,44 @@ use core::ops::ControlFlow; use rustc_ast::ast::Attribute; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, Expr, ExprKind, FnDecl}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_lint::Level::Allow; +use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{Span, sym}; -declare_clippy_lint! { - /// ### What it does - /// Checks for methods with high cognitive complexity. - /// - /// ### Why is this bad? - /// Methods of high cognitive complexity tend to be hard to - /// both read and maintain. Also LLVM will tend to optimize small methods better. - /// - /// ### Known problems - /// Sometimes it's hard to find a way to reduce the - /// complexity. - /// - /// ### Example - /// You'll see it when you get the warning. - #[clippy::version = "1.35.0"] - pub COGNITIVE_COMPLEXITY, - nursery, - "functions that should be split up into multiple functions" -} +use crate::LintInfo; + +pub static COGNITIVE_COMPLEXITY: &Lint = &Lint { + name: &"clippy::COGNITIVE_COMPLEXITY", + default_level: Allow, + desc: "functions that should be split up into multiple functions", + edition_lint_opts: None, + report_in_external_macro: true, + future_incompatible: None, + is_externally_loaded: true, + crate_level_only: false, + loadbearing: true, + ..Lint::default_fields_for_macro() +}; +pub(crate) static COGNITIVE_COMPLEXITY_INFO: &'static LintInfo = &LintInfo { + lint: &COGNITIVE_COMPLEXITY, + category: crate::LintCategory::Nursery, + explanation: r"### What it does +Checks for methods with high cognitive complexity. + +### Why is this bad? +Methods of high cognitive complexity tend to be hard to both read and maintain. +Also LLVM will tend to optimize small methods better. + +### Known problems +Sometimes it's hard to find a way to reduce the complexity. + +### Example +You'll see it when you get the warning.", + version: Some("1.35.0"), + location: "#L0", +}; pub struct CognitiveComplexity { limit: LimitStack, diff --git a/src/tools/clippy/clippy_lints/src/ctfe.rs b/src/tools/clippy/clippy_lints/src/ctfe.rs new file mode 100644 index 00000000000..7b9f71810a9 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/ctfe.rs @@ -0,0 +1,54 @@ +use rustc_hir::def_id::LocalDefId; +use rustc_hir::intravisit::FnKind; +use rustc_hir::{Body, FnDecl}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::declare_lint_pass; +use rustc_span::Span; + +declare_clippy_lint! { + /// ### What it does + /// Checks for comparisons where one side of the relation is + /// either the minimum or maximum value for its type and warns if it involves a + /// case that is always true or always false. Only integer and boolean types are + /// checked. + /// + /// ### Why is this bad? + /// An expression like `min <= x` may misleadingly imply + /// that it is possible for `x` to be less than the minimum. Expressions like + /// `max < x` are probably mistakes. + /// + /// ### Known problems + /// For `usize` the size of the current compile target will + /// be assumed (e.g., 64 bits on 64 bit systems). This means code that uses such + /// a comparison to detect target pointer width will trigger this lint. One can + /// use `mem::sizeof` and compare its value or conditional compilation + /// attributes + /// like `#[cfg(target_pointer_width = "64")] ..` instead. + /// + /// ### Example + /// ```no_run + /// let vec: Vec = Vec::new(); + /// if vec.len() <= 0 {} + /// if 100 > i32::MAX {} + /// ``` + #[clippy::version = "1.82.0"] + pub CLIPPY_CTFE, + correctness, + "a comparison with a maximum or minimum value that is always true or false" +} + +declare_lint_pass! { ClippyCtfe => [CLIPPY_CTFE] } + +impl<'tcx> LateLintPass<'tcx> for ClippyCtfe { + fn check_fn( + &mut self, + cx: &LateContext<'_>, + _: FnKind<'tcx>, + _: &'tcx FnDecl<'tcx>, + _: &'tcx Body<'tcx>, + _: Span, + defid: LocalDefId, + ) { + cx.tcx.ensure().mir_drops_elaborated_and_const_checked(defid); // Lint + } +} diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 6e29dde2211..a5d2f6a4122 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -65,6 +65,7 @@ extern crate clippy_utils; #[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))] mod utils; +pub mod ctfe; // VERY important lint (rust#125116) pub mod declared_lints; pub mod deprecated_lints; @@ -605,6 +606,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { }); } + store.register_late_pass(|_| Box::new(ctfe::ClippyCtfe)); + store.register_late_pass(move |_| Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(conf))); store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir)); store.register_late_pass(|_| Box::new(utils::author::Author)); diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs similarity index 99% rename from src/tools/clippy/clippy_lints/src/utils/internal_lints/author.rs rename to src/tools/clippy/clippy_lints/src/utils/author.rs index 0ed606a836e..f4e166327af 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -12,7 +12,7 @@ use rustc_span::symbol::{Ident, Symbol}; use std::cell::Cell; use std::fmt::{Display, Formatter, Write as _}; -declare_clippy_lint!{ +declare_lint_pass!( /// ### What it does /// Generates clippy code that detects the offending pattern /// @@ -44,13 +44,8 @@ declare_clippy_lint!{ /// // report your lint here /// } /// ``` - #[clippy::version = "1.0.0"] - pub AUTHOR, - internal, - "The author lint, see documentation at " -}; - -declare_lint_pass! { Author => [AUTHOR] } + Author => [] +); /// Writes a line of output with indentation added macro_rules! out { @@ -803,3 +798,4 @@ fn path_to_string(path: &QPath<'_>) -> Result { inner(&mut s, path)?; Ok(s) } + diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs index abd10ac024c..13e9ead9a57 100644 --- a/src/tools/clippy/clippy_lints/src/utils/mod.rs +++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs @@ -1,3 +1,4 @@ +pub mod author; pub mod dump_hir; pub mod format_args_collector; #[cfg(feature = "internal")] From 637d5cc56fcc11afadd4ffaefa237c11f47cdfee Mon Sep 17 00:00:00 2001 From: blyxyas Date: Sat, 7 Sep 2024 12:13:03 +0200 Subject: [PATCH 4/7] Remove module passes filtering --- compiler/rustc_interface/src/passes.rs | 2 +- compiler/rustc_lint/src/builtin.rs | 8 +- compiler/rustc_lint/src/internal.rs | 4 +- compiler/rustc_lint/src/late.rs | 45 ++----- compiler/rustc_lint/src/levels.rs | 124 +++++------------- compiler/rustc_lint/src/lib.rs | 22 ++-- compiler/rustc_lint/src/passes.rs | 17 +-- compiler/rustc_lint_defs/src/builtin.rs | 8 +- compiler/rustc_lint_defs/src/lib.rs | 23 ++-- compiler/rustc_middle/src/lint.rs | 2 +- compiler/rustc_session/src/session.rs | 1 - src/librustdoc/lint.rs | 7 +- .../clippy_lints/src/cognitive_complexity.rs | 4 +- src/tools/clippy/clippy_lints/src/ctfe.rs | 51 +++---- src/tools/clippy/clippy_lints/src/lib.rs | 2 +- .../clippy/clippy_lints/src/utils/author.rs | 1 - 16 files changed, 109 insertions(+), 212 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 608d66184f0..fd850d2f39a 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -972,7 +972,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { tcx.ensure().check_mod_privacy(module); }); }); - } // { sess.time("mir_checking", || { tcx.hir().mir_for }) } + } ); // This check has to be run after all lints are done processing. We don't diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 33c87bbfb70..b2c7f1d3cec 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -20,7 +20,6 @@ //! If you define a new `LateLintPass`, you will also need to add it to the //! `late_lint_methods!` invocation in `lib.rs`. -use std::default::Default; use std::fmt::Write; use ast::token::TokenKind; @@ -74,11 +73,6 @@ use crate::{ EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext, fluent_generated as fluent, }; -// use std::fmt::Write; - -// hardwired lints from rustc_lint_defs -// pub use rustc_session::lint::builtin::*; - declare_lint! { /// The `while_true` lint detects `while true { }`. /// @@ -247,7 +241,7 @@ declare_lint! { UNSAFE_CODE, Allow, "usage of `unsafe` code and other potentially unsound constructs", - [loadbearing: true] + @eval_always = true } declare_lint_pass!(UnsafeCode => [UNSAFE_CODE]); diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 0f4f58efd8e..11e9e933dd9 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -430,7 +430,7 @@ declare_tool_lint! { Deny, "prevent creation of diagnostics which cannot be translated", report_in_external_macro: true, - [loadbearing: true] + eval_always: true } declare_tool_lint! { @@ -444,7 +444,7 @@ declare_tool_lint! { Deny, "prevent diagnostic creation outside of `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls", report_in_external_macro: true, - [loadbearing: true] + eval_always: true } declare_lint_pass!(Diagnostics => [UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE_OF_IMPL]); diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index f8bd873cdf5..ea7a44dd123 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -24,7 +24,9 @@ use rustc_hir::def_id::{LocalDefId, LocalModDefId}; use rustc_hir::{HirId, intravisit as hir_visit}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, TyCtxt}; -use rustc_session::{Session, lint::{LintPass, builtin::HardwiredLints}}; +use rustc_session::Session; +use rustc_session::lint::LintPass; +use rustc_session::lint::builtin::HardwiredLints; use rustc_span::Span; use tracing::debug; @@ -368,28 +370,15 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>( if store.late_module_passes.is_empty() { late_lint_mod_inner(tcx, module_def_id, context, builtin_lints); } else { - let passes: Vec<_> = - store.late_module_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect(); - // Filter unused lints - let lints_that_dont_need_to_run = tcx.lints_that_dont_need_to_run(()); - let mut filtered_passes: Vec>> = passes - .into_iter() - .filter(|pass| { - let lints = LintPass::get_lints(pass); - if lints.is_empty() { - true - } else { - lints - .iter() - .any(|lint| !lints_that_dont_need_to_run.contains(&LintId::of(lint))) - } - }) - .collect(); + let builtin_lints = Box::new(builtin_lints) as Box>; + let mut binding = store + .late_module_passes + .iter() + .map(|mk_pass| (mk_pass)(tcx)) + .chain(std::iter::once(builtin_lints)) + .collect::>(); - filtered_passes.push(Box::new(builtin_lints)); - filtered_passes.push(Box::new(HardwiredLints)); - - let pass = RuntimeCombinedLateLintPass { passes: &mut filtered_passes[..] }; + let pass = RuntimeCombinedLateLintPass { passes: binding.as_mut_slice() }; late_lint_mod_inner(tcx, module_def_id, context, pass); } } @@ -440,7 +429,6 @@ fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) { let lints_that_dont_need_to_run = tcx.lints_that_dont_need_to_run(()); - // dbg!(&lints_that_dont_need_to_run); let mut filtered_passes: Vec>> = passes .into_iter() .filter(|pass| { @@ -450,17 +438,6 @@ fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) { .collect(); filtered_passes.push(Box::new(HardwiredLints)); - - // let mut filtered_passes: Vec>> = passes - // .into_iter() - // .filter(|pass| { - // let lints = LintPass::get_lints(pass); - // lints.iter() - // .any(|lint| - // !lints_that_dont_need_to_run.contains(&LintId::of(lint))) - // }).collect(); - // - let pass = RuntimeCombinedLateLintPass { passes: &mut filtered_passes[..] }; late_lint_crate_inner(tcx, context, pass); } diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index f5323c295d0..64e1cddf248 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -31,7 +31,7 @@ use crate::errors::{ OverruledAttributeSub, RequestedLevel, UnknownToolInScopedLint, UnsupportedGroup, }; use crate::fluent_generated as fluent; -use crate::late::{unerased_lint_store /*name_without_tool*/}; +use crate::late::unerased_lint_store; use crate::lints::{ DeprecatedLintName, DeprecatedLintNameFromCommandLine, IgnoredUnlessCrateSpecified, OverruledAttributeLint, RemovedLint, RemovedLintFromCommandLine, RenamedLint, @@ -122,7 +122,7 @@ fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet { .get_lints() .into_iter() .filter_map(|lint| { - if !lint.loadbearing && lint.default_level(tcx.sess.edition()) == Level::Allow { + if !lint.eval_always && lint.default_level(tcx.sess.edition()) == Level::Allow { Some(LintId::of(lint)) } else { None @@ -134,21 +134,6 @@ fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet { visitor.process_opts(); tcx.hir().walk_attributes(&mut visitor); - // let lint_groups = store.get_lint_groups(); - // for group in lint_groups { - // let binding = group.0.to_lowercase(); - // let group_name = name_without_tool(&binding).to_string(); - // if visitor.lints_that_actually_run.contains(&group_name) { - // for lint in group.1 { - // visitor.lints_that_actually_run.insert(name_without_tool(&lint.to_string()).to_string()); - // } - // } else if visitor.lints_allowed.contains(&group_name) { - // for lint in &group.1 { - // visitor.lints_allowed.insert(name_without_tool(&lint.to_string()).to_string()); - // } - // } - // } - visitor.dont_need_to_run } @@ -372,83 +357,44 @@ impl<'tcx> Visitor<'tcx> for LintLevelMaximum<'tcx> { self.tcx.hir() } + /// FIXME(blyxyas): In a future revision, we should also graph #![allow]s, + /// but that is handled with more care fn visit_attribute(&mut self, attribute: &'tcx ast::Attribute) { - match Level::from_attr(attribute) { + if matches!( + Level::from_attr(attribute), Some( Level::Warn - | Level::Deny - | Level::Forbid - | Level::Expect(..) - | Level::ForceWarn(..), - ) => { - let store = unerased_lint_store(self.tcx.sess); - let Some(meta) = attribute.meta() else { return }; - // SAFETY: Lint attributes are always a metalist inside a - // metalist (even with just one lint). - let Some(meta_item_list) = meta.meta_item_list() else { return }; + | Level::Deny + | Level::Forbid + | Level::Expect(..) + | Level::ForceWarn(..), + ) + ) { + let store = unerased_lint_store(self.tcx.sess); + let Some(meta) = attribute.meta() else { return }; + // SAFETY: Lint attributes are always a metalist inside a + // metalist (even with just one lint). + let Some(meta_item_list) = meta.meta_item_list() else { return }; - for meta_list in meta_item_list { - // Convert Path to String - let Some(meta_item) = meta_list.meta_item() else { return }; - let ident: &str = &meta_item - .path - .segments - .iter() - .map(|segment| segment.ident.as_str()) - .collect::>() - .join("::"); - let Ok(lints) = store.find_lints( - // SAFETY: Lint attributes can only have literals - ident, - ) else { - return; - }; - for lint in lints { - self.dont_need_to_run.swap_remove(&lint); - } - // // If it's a tool lint (e.g. clippy::my_clippy_lint) - // if let ast::NestedMetaItem::MetaItem(meta_item) = meta_list { - // if meta_item.path.segments.len() == 1 { - // let Ok(lints) = store.find_lints( - // // SAFETY: Lint attributes can only have literals - // meta_list.ident().unwrap().name.as_str(), - // ) else { - // return; - // }; - // for lint in lints { - // dbg!("LINT REMOVED", &lint); - // self.dont_need_to_run.swap_remove(&lint); - // } - // } else { - // let Ok(lints) = store.find_lints( - // // SAFETY: Lint attributes can only have literals - // meta_item.path.segments[1].ident.name.as_str(), - // ) else { - // return; - // }; - // for lint in lints { - // dbg!("LINT REMOVED", &lint); - // self.dont_need_to_run.swap_remove(&lint); - // } - // } + for meta_list in meta_item_list { + // Convert Path to String + let Some(meta_item) = meta_list.meta_item() else { return }; + let ident: &str = &meta_item + .path + .segments + .iter() + .map(|segment| segment.ident.as_str()) + .collect::>() + .join("::"); + let Ok(lints) = store.find_lints( + // SAFETY: Lint attributes can only have literals + ident, + ) else { + return; + }; + for lint in lints { + self.dont_need_to_run.swap_remove(&lint); } - // We handle #![allow]s differently, as these remove checking rather than adding. - } // Some(Level::Allow) if ast::AttrStyle::Inner == attribute.style => { - // for meta_list in meta.meta_item_list().unwrap() { - // // If it's a tool lint (e.g. clippy::my_clippy_lint) - // if let ast::NestedMetaItem::MetaItem(meta_item) = meta_list { - // if meta_item.path.segments.len() == 1 { - // self.lints_allowed - // .insert(meta_list.name_or_empty().as_str().to_string()); - // } else { - // self.lints_allowed - // .insert(meta_item.path.segments[1].ident.name.as_str().to_string()); - // } - // } - // } - // } - _ => { - return; } } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 11dd17bcd4a..1607c8abfb5 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -279,7 +279,7 @@ fn register_builtins(store: &mut LintStore) { store.register_lints(&BuiltinCombinedEarlyLintPass::get_lints()); store.register_lints(&BuiltinCombinedModuleLateLintPass::get_lints()); store.register_lints(&foreign_modules::get_lints()); - store.register_lints(&HardwiredLints::default().get_lints()); + store.register_lints(&HardwiredLints::lint_vec()); add_lint_group!( "nonstandard_style", @@ -601,25 +601,25 @@ fn register_builtins(store: &mut LintStore) { } fn register_internals(store: &mut LintStore) { - store.register_lints(&LintPassImpl::default().get_lints()); + store.register_lints(&LintPassImpl::lint_vec()); store.register_early_pass(|| Box::new(LintPassImpl)); - store.register_lints(&DefaultHashTypes::default().get_lints()); + store.register_lints(&DefaultHashTypes::lint_vec()); store.register_late_mod_pass(|_| Box::new(DefaultHashTypes)); - store.register_lints(&QueryStability::default().get_lints()); + store.register_lints(&QueryStability::lint_vec()); store.register_late_mod_pass(|_| Box::new(QueryStability)); - store.register_lints(&ExistingDocKeyword::default().get_lints()); + store.register_lints(&ExistingDocKeyword::lint_vec()); store.register_late_mod_pass(|_| Box::new(ExistingDocKeyword)); - store.register_lints(&TyTyKind::default().get_lints()); + store.register_lints(&TyTyKind::lint_vec()); store.register_late_mod_pass(|_| Box::new(TyTyKind)); - store.register_lints(&TypeIr::default().get_lints()); + store.register_lints(&TypeIr::lint_vec()); store.register_late_mod_pass(|_| Box::new(TypeIr)); - store.register_lints(&Diagnostics::default().get_lints()); + store.register_lints(&Diagnostics::lint_vec()); store.register_late_mod_pass(|_| Box::new(Diagnostics)); - store.register_lints(&BadOptAccess::default().get_lints()); + store.register_lints(&BadOptAccess::lint_vec()); store.register_late_mod_pass(|_| Box::new(BadOptAccess)); - store.register_lints(&PassByValue::default().get_lints()); + store.register_lints(&PassByValue::lint_vec()); store.register_late_mod_pass(|_| Box::new(PassByValue)); - store.register_lints(&SpanUseEqCtxt::default().get_lints()); + store.register_lints(&SpanUseEqCtxt::lint_vec()); store.register_late_mod_pass(|_| Box::new(SpanUseEqCtxt)); // FIXME(davidtwco): deliberately do not include `UNTRANSLATABLE_DIAGNOSTIC` and // `DIAGNOSTIC_OUTSIDE_OF_IMPL` here because `-Wrustc::internal` is provided to every crate and diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index 6dbcdefe08d..18244b14e79 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -70,18 +70,7 @@ macro_rules! declare_late_lint_pass { // for all the `check_*` methods. late_lint_methods!(declare_late_lint_pass, []); -impl LateLintPass<'_> for HardwiredLints { - fn check_fn( - &mut self, - _: &LateContext<'_>, - _: rustc_hir::intravisit::FnKind<'_>, - _: &'_ rustc_hir::FnDecl<'_>, - _: &'_ rustc_hir::Body<'_>, - _: rustc_span::Span, - _: rustc_span::def_id::LocalDefId, - ) { - } -} +impl LateLintPass<'_> for HardwiredLints {} #[macro_export] macro_rules! expand_combined_late_lint_pass_method { @@ -121,7 +110,7 @@ macro_rules! declare_combined_late_lint_pass { $v fn get_lints() -> $crate::LintVec { let mut lints = Vec::new(); - $(lints.extend_from_slice(&$pass::default().get_lints());)* + $(lints.extend_from_slice(&$pass::lint_vec());)* lints } } @@ -236,7 +225,7 @@ macro_rules! declare_combined_early_lint_pass { $v fn get_lints() -> $crate::LintVec { let mut lints = Vec::new(); - $(lints.extend_from_slice(&$pass::default().get_lints());)* + $(lints.extend_from_slice(&$pass::lint_vec());)* lints } } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index df86e9de22e..3d8da0536bd 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -12,6 +12,8 @@ use rustc_span::edition::Edition; use crate::{FutureIncompatibilityReason, declare_lint, declare_lint_pass}; declare_lint_pass! { + /// Does nothing as a lint pass, but registers some `Lint`s + /// that are used by other parts of the compiler. HardwiredLints => [ // tidy-alphabetical-start ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, @@ -377,7 +379,7 @@ declare_lint! { pub ARITHMETIC_OVERFLOW, Deny, "arithmetic operation overflows", - [loadbearing: true] + @eval_always = true } declare_lint! { @@ -402,7 +404,7 @@ declare_lint! { pub UNCONDITIONAL_PANIC, Deny, "operation will cause a panic at runtime", - [loadbearing: true] + @eval_always = true } declare_lint! { @@ -634,7 +636,7 @@ declare_lint! { pub UNKNOWN_LINTS, Warn, "unrecognized lint attribute", - [loadbearing: true] + @eval_always = true } declare_lint! { diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 691f37f0977..da0accb0e09 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -315,7 +315,7 @@ pub struct Lint { /// `true` if this lint should not be filtered out under any circustamces /// (e.g. the unknown_attributes lint) - pub loadbearing: bool, + pub eval_always: bool, } /// Extra information for a future incompatibility lint. @@ -460,7 +460,7 @@ impl Lint { future_incompatible: None, feature_gate: None, crate_level_only: false, - loadbearing: false, + eval_always: false, } } @@ -868,7 +868,8 @@ macro_rules! declare_lint { $(#[$attr])* $vis $NAME, $Level, $desc, ); ); - ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr, $([loadbearing: $loadbearing: literal])? + ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr, + $(@eval_always = $eval_always:literal)? $(@feature_gate = $gate:ident;)? $(@future_incompatible = FutureIncompatibleInfo { reason: $reason:expr, @@ -890,7 +891,7 @@ macro_rules! declare_lint { ..$crate::FutureIncompatibleInfo::default_fields_for_macro() }),)? $(edition_lint_opts: Some(($crate::Edition::$lint_edition, $crate::$edition_level)),)? - $(loadbearing: $loadbearing,)? + $(eval_always: $eval_always,)? ..$crate::Lint::default_fields_for_macro() }; ); @@ -900,8 +901,8 @@ macro_rules! declare_lint { macro_rules! declare_tool_lint { ( $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level: ident, $desc: expr + $(, @eval_always = $eval_always:literal)? $(, @feature_gate = $gate:ident;)? - $(, [loadbearing: $loadbearing: literal])? ) => ( $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, false $(, @feature_gate = $gate;)?} ); @@ -909,15 +910,15 @@ macro_rules! declare_tool_lint { $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr, report_in_external_macro: $rep:expr $(, @feature_gate = $gate:ident;)? - $(, [loadbearing: $loadbearing: literal])? + $(, eval_always: $eval_always: literal)? ) => ( $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, $rep $(, @feature_gate = $gate;)?} ); ( $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr, $external:expr + $(, @eval_always: $eval_always: literal)? $(, @feature_gate = $gate:ident;)? - $(, [loadbearing: $loadbearing: literal])? ) => ( $(#[$attr])* $vis static $NAME: &$crate::Lint = &$crate::Lint { @@ -930,7 +931,7 @@ macro_rules! declare_tool_lint { is_externally_loaded: true, $(feature_gate: Some(rustc_span::symbol::sym::$gate),)? crate_level_only: false, - $(loadbearing: $loadbearing,)? + $(eval_always: $eval_always,)? ..$crate::Lint::default_fields_for_macro() }; ); @@ -951,6 +952,10 @@ macro_rules! impl_lint_pass { fn name(&self) -> &'static str { stringify!($ty) } fn get_lints(&self) -> $crate::LintVec { vec![$($lint),*] } } + impl $ty { + #[allow(unused)] + pub fn lint_vec() -> $crate::LintVec { vec![$($lint),*] } + } }; } @@ -959,7 +964,7 @@ macro_rules! impl_lint_pass { #[macro_export] macro_rules! declare_lint_pass { ($(#[$m:meta])* $name:ident => [$($lint:expr),* $(,)?]) => { - $(#[$m])* #[derive(Copy, Clone, Default)] pub struct $name; + $(#[$m])* #[derive(Copy, Clone)] pub struct $name; $crate::impl_lint_pass!($name => [$($lint),*]); }; } diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index eaec19700c8..b5862565e8e 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -117,7 +117,7 @@ impl ShallowLintLevelMap { /// This lint level is not usable for diagnostics, it needs to be corrected by /// `reveal_actual_level` beforehand. #[instrument(level = "trace", skip(self, tcx), ret)] - pub fn probe_for_lint_level( + fn probe_for_lint_level( &self, tcx: TyCtxt<'_>, id: LintId, diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index c8f46226a3e..27879d817b2 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -187,7 +187,6 @@ pub struct Session { /// errors. pub ctfe_backtrace: Lock, - // pub force_ctfe: bool, /// This tracks where `-Zunleash-the-miri-inside-of-you` was used to get around a /// const check, optionally with the relevant feature gate. We use this to /// warn about unleashing, but with a single diagnostic instead of dozens that diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs index 679fc45df76..2afb9e549d9 100644 --- a/src/librustdoc/lint.rs +++ b/src/librustdoc/lint.rs @@ -2,7 +2,7 @@ use std::sync::LazyLock as Lazy; use rustc_data_structures::fx::FxHashMap; use rustc_lint::LintStore; -use rustc_lint_defs::{Lint, LintId, LintPass, declare_tool_lint}; +use rustc_lint_defs::{Lint, LintId, declare_tool_lint}; use rustc_session::{Session, lint}; /// This function is used to setup the lint initialization. By default, in rustdoc, everything @@ -31,10 +31,9 @@ where allowed_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned()); let lints = || { - lint::builtin::HardwiredLints::default() - .get_lints() + lint::builtin::HardwiredLints::lint_vec() .into_iter() - .chain(rustc_lint::SoftLints::default().get_lints()) + .chain(rustc_lint::SoftLints::lint_vec()) }; let lint_opts = lints() diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs index b027c289a7f..91cb8b78ba8 100644 --- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs @@ -25,7 +25,7 @@ pub static COGNITIVE_COMPLEXITY: &Lint = &Lint { future_incompatible: None, is_externally_loaded: true, crate_level_only: false, - loadbearing: true, + eval_always: true, ..Lint::default_fields_for_macro() }; pub(crate) static COGNITIVE_COMPLEXITY_INFO: &'static LintInfo = &LintInfo { @@ -44,7 +44,7 @@ Sometimes it's hard to find a way to reduce the complexity. ### Example You'll see it when you get the warning.", version: Some("1.35.0"), - location: "#L0", + location: "clippy_lints/src/cognitive_complexity.rs#L47", }; pub struct CognitiveComplexity { diff --git a/src/tools/clippy/clippy_lints/src/ctfe.rs b/src/tools/clippy/clippy_lints/src/ctfe.rs index 7b9f71810a9..ddb4eb82165 100644 --- a/src/tools/clippy/clippy_lints/src/ctfe.rs +++ b/src/tools/clippy/clippy_lints/src/ctfe.rs @@ -1,41 +1,28 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::Level::Deny; +use rustc_lint::{LateContext, LateLintPass, Lint}; use rustc_session::declare_lint_pass; use rustc_span::Span; -declare_clippy_lint! { - /// ### What it does - /// Checks for comparisons where one side of the relation is - /// either the minimum or maximum value for its type and warns if it involves a - /// case that is always true or always false. Only integer and boolean types are - /// checked. - /// - /// ### Why is this bad? - /// An expression like `min <= x` may misleadingly imply - /// that it is possible for `x` to be less than the minimum. Expressions like - /// `max < x` are probably mistakes. - /// - /// ### Known problems - /// For `usize` the size of the current compile target will - /// be assumed (e.g., 64 bits on 64 bit systems). This means code that uses such - /// a comparison to detect target pointer width will trigger this lint. One can - /// use `mem::sizeof` and compare its value or conditional compilation - /// attributes - /// like `#[cfg(target_pointer_width = "64")] ..` instead. - /// - /// ### Example - /// ```no_run - /// let vec: Vec = Vec::new(); - /// if vec.len() <= 0 {} - /// if 100 > i32::MAX {} - /// ``` - #[clippy::version = "1.82.0"] - pub CLIPPY_CTFE, - correctness, - "a comparison with a maximum or minimum value that is always true or false" -} +/// Ensures that Constant-time Function Evaluation is being done (specifically, MIR lint passes). +/// See rust-lang/rust#125116 for more info. +#[clippy::version = "1.82.0"] +pub static CLIPPY_CTFE: &Lint = &Lint { + name: &"clippy::CLIPPY_CTFE", + default_level: Deny, + desc: "Ensure CTFE is being made", + edition_lint_opts: None, + report_in_external_macro: true, + future_incompatible: None, + is_externally_loaded: true, + crate_level_only: false, + eval_always: true, + ..Lint::default_fields_for_macro() +}; + +// No static CLIPPY_CTFE_INFO because we want this lint to be invisible declare_lint_pass! { ClippyCtfe => [CLIPPY_CTFE] } diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index a5d2f6a4122..88a227f5b6d 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -65,7 +65,7 @@ extern crate clippy_utils; #[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))] mod utils; -pub mod ctfe; // VERY important lint (rust#125116) +pub mod ctfe; // Very important lint (rust#125116) pub mod declared_lints; pub mod deprecated_lints; diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index f4e166327af..31f9d84f5e4 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -798,4 +798,3 @@ fn path_to_string(path: &QPath<'_>) -> Result { inner(&mut s, path)?; Ok(s) } - From 8a40884e1c606ac92326ed5ea444eb78d06da975 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Fri, 11 Oct 2024 00:31:17 +0200 Subject: [PATCH 5/7] Unify syntax (all to @eval_always) --- compiler/rustc_lint/src/internal.rs | 4 ++-- compiler/rustc_lint_defs/src/lib.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 11e9e933dd9..7dec6dbdc05 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -430,7 +430,7 @@ declare_tool_lint! { Deny, "prevent creation of diagnostics which cannot be translated", report_in_external_macro: true, - eval_always: true + @eval_always = true } declare_tool_lint! { @@ -444,7 +444,7 @@ declare_tool_lint! { Deny, "prevent diagnostic creation outside of `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls", report_in_external_macro: true, - eval_always: true + @eval_always = true } declare_lint_pass!(Diagnostics => [UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE_OF_IMPL]); diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index da0accb0e09..320668a5dbf 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -910,14 +910,14 @@ macro_rules! declare_tool_lint { $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr, report_in_external_macro: $rep:expr $(, @feature_gate = $gate:ident;)? - $(, eval_always: $eval_always: literal)? + $(, @eval_always = $eval_always: literal)? ) => ( $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, $rep $(, @feature_gate = $gate;)?} ); ( $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr, $external:expr - $(, @eval_always: $eval_always: literal)? + $(, @eval_always = $eval_always: literal)? $(, @feature_gate = $gate:ident;)? ) => ( $(#[$attr])* From ddad55f6c214357f48134d00050c6dbfcf1d9215 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Tue, 15 Oct 2024 22:15:07 +0200 Subject: [PATCH 6/7] Apply review comments + use `shallow_lint_levels_on` --- compiler/rustc_lint/src/late.rs | 2 +- compiler/rustc_lint/src/levels.rs | 20 +++++++++++++++----- compiler/rustc_lint_defs/src/lib.rs | 11 ----------- src/tools/clippy/clippy_lints/src/ctfe.rs | 2 +- src/tools/clippy/clippy_lints/src/lib.rs | 2 +- 5 files changed, 18 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index ea7a44dd123..9b1877599ba 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -432,7 +432,7 @@ fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) { let mut filtered_passes: Vec>> = passes .into_iter() .filter(|pass| { - let lints = LintPass::get_lints(pass); + let lints = (**pass).get_lints(); !lints.iter().all(|lint| lints_that_dont_need_to_run.contains(&LintId::of(lint))) }) .collect(); diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 64e1cddf248..2c12899fad0 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -2,8 +2,8 @@ use rustc_ast_pretty::pprust; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::{Diag, LintDiagnostic, MultiSpan}; use rustc_feature::{Features, GateIssue}; -use rustc_hir::HirId; use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::{CRATE_HIR_ID, HirId}; use rustc_index::IndexVec; use rustc_middle::bug; use rustc_middle::hir::nested_filter; @@ -118,12 +118,22 @@ impl LintLevelSets { fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet { let store = unerased_lint_store(&tcx.sess); + let map = tcx.shallow_lint_levels_on(rustc_hir::CRATE_OWNER_ID); + let dont_need_to_run: FxIndexSet = store .get_lints() .into_iter() .filter_map(|lint| { - if !lint.eval_always && lint.default_level(tcx.sess.edition()) == Level::Allow { - Some(LintId::of(lint)) + if !lint.eval_always { + let lint_level = map.lint_level_id_at_node(tcx, LintId::of(lint), CRATE_HIR_ID); + if matches!(lint_level, (Level::Allow, ..)) + || (matches!(lint_level, (.., LintLevelSource::Default))) + && lint.default_level(tcx.sess.edition()) == Level::Allow + { + Some(LintId::of(lint)) + } else { + None + } } else { None } @@ -372,7 +382,7 @@ impl<'tcx> Visitor<'tcx> for LintLevelMaximum<'tcx> { ) { let store = unerased_lint_store(self.tcx.sess); let Some(meta) = attribute.meta() else { return }; - // SAFETY: Lint attributes are always a metalist inside a + // Lint attributes are always a metalist inside a // metalist (even with just one lint). let Some(meta_item_list) = meta.meta_item_list() else { return }; @@ -387,7 +397,7 @@ impl<'tcx> Visitor<'tcx> for LintLevelMaximum<'tcx> { .collect::>() .join("::"); let Ok(lints) = store.find_lints( - // SAFETY: Lint attributes can only have literals + // Lint attributes can only have literals ident, ) else { return; diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 320668a5dbf..418caa699e2 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -968,14 +968,3 @@ macro_rules! declare_lint_pass { $crate::impl_lint_pass!($name => [$($lint),*]); }; } - -#[allow(rustc::lint_pass_impl_without_macro)] -impl LintPass for Box

{ - fn name(&self) -> &'static str { - (**self).name() - } - - fn get_lints(&self) -> LintVec { - (**self).get_lints() - } -} diff --git a/src/tools/clippy/clippy_lints/src/ctfe.rs b/src/tools/clippy/clippy_lints/src/ctfe.rs index ddb4eb82165..93d0ad789be 100644 --- a/src/tools/clippy/clippy_lints/src/ctfe.rs +++ b/src/tools/clippy/clippy_lints/src/ctfe.rs @@ -7,7 +7,7 @@ use rustc_session::declare_lint_pass; use rustc_span::Span; /// Ensures that Constant-time Function Evaluation is being done (specifically, MIR lint passes). -/// See rust-lang/rust#125116 for more info. +/// As Clippy deactivates codegen, this lint ensures that CTFE (used in hard errors) is still ran. #[clippy::version = "1.82.0"] pub static CLIPPY_CTFE: &Lint = &Lint { name: &"clippy::CLIPPY_CTFE", diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 88a227f5b6d..14110539709 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -65,7 +65,7 @@ extern crate clippy_utils; #[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))] mod utils; -pub mod ctfe; // Very important lint (rust#125116) +pub mod ctfe; // Very important lint, do not remove (rust#125116) pub mod declared_lints; pub mod deprecated_lints; From 1dcfa271443b4d3a608e656e203a987a5cb07e60 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Sat, 19 Oct 2024 17:47:16 +0200 Subject: [PATCH 7/7] Move COGNITIVE_COMPLEXITY to use macro again --- compiler/rustc_lint/src/shadowed_into_iter.rs | 2 +- compiler/rustc_lint_defs/src/lib.rs | 6 +- .../clippy_lints/src/cognitive_complexity.rs | 55 +++++++------------ src/tools/clippy/clippy_lints/src/ctfe.rs | 1 - .../clippy_lints/src/declare_clippy_lint.rs | 30 ++++++---- 5 files changed, 45 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_lint/src/shadowed_into_iter.rs b/compiler/rustc_lint/src/shadowed_into_iter.rs index 33a4ae60663..a73904cd776 100644 --- a/compiler/rustc_lint/src/shadowed_into_iter.rs +++ b/compiler/rustc_lint/src/shadowed_into_iter.rs @@ -64,7 +64,7 @@ declare_lint! { }; } -#[derive(Copy, Clone, Default)] +#[derive(Copy, Clone)] pub(crate) struct ShadowedIntoIter; impl_lint_pass!(ShadowedIntoIter => [ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER]); diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 418caa699e2..601784f9732 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -904,15 +904,15 @@ macro_rules! declare_tool_lint { $(, @eval_always = $eval_always:literal)? $(, @feature_gate = $gate:ident;)? ) => ( - $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, false $(, @feature_gate = $gate;)?} + $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, false $(, @eval_always = $eval_always)? $(, @feature_gate = $gate;)?} ); ( $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr, report_in_external_macro: $rep:expr - $(, @feature_gate = $gate:ident;)? $(, @eval_always = $eval_always: literal)? + $(, @feature_gate = $gate:ident;)? ) => ( - $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, $rep $(, @feature_gate = $gate;)?} + $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, $rep $(, @eval_always = $eval_always)? $(, @feature_gate = $gate;)?} ); ( $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr, diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs index 91cb8b78ba8..477435236a5 100644 --- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs @@ -8,44 +8,31 @@ use core::ops::ControlFlow; use rustc_ast::ast::Attribute; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, Expr, ExprKind, FnDecl}; -use rustc_lint::Level::Allow; -use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{Span, sym}; -use crate::LintInfo; - -pub static COGNITIVE_COMPLEXITY: &Lint = &Lint { - name: &"clippy::COGNITIVE_COMPLEXITY", - default_level: Allow, - desc: "functions that should be split up into multiple functions", - edition_lint_opts: None, - report_in_external_macro: true, - future_incompatible: None, - is_externally_loaded: true, - crate_level_only: false, - eval_always: true, - ..Lint::default_fields_for_macro() -}; -pub(crate) static COGNITIVE_COMPLEXITY_INFO: &'static LintInfo = &LintInfo { - lint: &COGNITIVE_COMPLEXITY, - category: crate::LintCategory::Nursery, - explanation: r"### What it does -Checks for methods with high cognitive complexity. - -### Why is this bad? -Methods of high cognitive complexity tend to be hard to both read and maintain. -Also LLVM will tend to optimize small methods better. - -### Known problems -Sometimes it's hard to find a way to reduce the complexity. - -### Example -You'll see it when you get the warning.", - version: Some("1.35.0"), - location: "clippy_lints/src/cognitive_complexity.rs#L47", -}; +declare_clippy_lint! { + /// ### What it does + /// Checks for methods with high cognitive complexity. + /// + /// ### Why is this bad? + /// Methods of high cognitive complexity tend to be hard to + /// both read and maintain. Also LLVM will tend to optimize small methods better. + /// + /// ### Known problems + /// Sometimes it's hard to find a way to reduce the + /// complexity. + /// + /// ### Example + /// You'll see it when you get the warning. + #[clippy::version = "1.35.0"] + pub COGNITIVE_COMPLEXITY, + nursery, + "functions that should be split up into multiple functions" + @eval_always = true +} pub struct CognitiveComplexity { limit: LimitStack, diff --git a/src/tools/clippy/clippy_lints/src/ctfe.rs b/src/tools/clippy/clippy_lints/src/ctfe.rs index 93d0ad789be..2fe37a64db6 100644 --- a/src/tools/clippy/clippy_lints/src/ctfe.rs +++ b/src/tools/clippy/clippy_lints/src/ctfe.rs @@ -8,7 +8,6 @@ use rustc_span::Span; /// Ensures that Constant-time Function Evaluation is being done (specifically, MIR lint passes). /// As Clippy deactivates codegen, this lint ensures that CTFE (used in hard errors) is still ran. -#[clippy::version = "1.82.0"] pub static CLIPPY_CTFE: &Lint = &Lint { name: &"clippy::CLIPPY_CTFE", default_level: Deny, diff --git a/src/tools/clippy/clippy_lints/src/declare_clippy_lint.rs b/src/tools/clippy/clippy_lints/src/declare_clippy_lint.rs index b1e39c70baa..a785a9d377c 100644 --- a/src/tools/clippy/clippy_lints/src/declare_clippy_lint.rs +++ b/src/tools/clippy/clippy_lints/src/declare_clippy_lint.rs @@ -9,6 +9,7 @@ macro_rules! declare_clippy_lint { $desc:literal, $version_expr:expr, $version_lit:literal + $(, $eval_always: literal)? ) => { rustc_session::declare_tool_lint! { $(#[doc = $lit])* @@ -17,6 +18,7 @@ macro_rules! declare_clippy_lint { $category, $desc, report_in_external_macro:true + $(, @eval_always = $eval_always)? } pub(crate) static ${concat($lint_name, _INFO)}: &'static crate::LintInfo = &crate::LintInfo { @@ -33,11 +35,12 @@ macro_rules! declare_clippy_lint { pub $lint_name:ident, restriction, $desc:literal + $(@eval_always = $eval_always: literal)? ) => { declare_clippy_lint! {@ $(#[doc = $lit])* pub $lint_name, Allow, crate::LintCategory::Restriction, $desc, - Some($version), $version + Some($version), $version $(, $eval_always)? } }; ( @@ -46,12 +49,12 @@ macro_rules! declare_clippy_lint { pub $lint_name:ident, style, $desc:literal + $(@eval_always = $eval_always: literal)? ) => { declare_clippy_lint! {@ $(#[doc = $lit])* pub $lint_name, Warn, crate::LintCategory::Style, $desc, - Some($version), $version - + Some($version), $version $(, $eval_always)? } }; ( @@ -60,11 +63,12 @@ macro_rules! declare_clippy_lint { pub $lint_name:ident, correctness, $desc:literal + $(@eval_always = $eval_always: literal)? ) => { declare_clippy_lint! {@ $(#[doc = $lit])* pub $lint_name, Deny, crate::LintCategory::Correctness, $desc, - Some($version), $version + Some($version), $version $(, $eval_always)? } }; @@ -74,11 +78,12 @@ macro_rules! declare_clippy_lint { pub $lint_name:ident, perf, $desc:literal + $(@eval_always = $eval_always: literal)? ) => { declare_clippy_lint! {@ $(#[doc = $lit])* pub $lint_name, Warn, crate::LintCategory::Perf, $desc, - Some($version), $version + Some($version), $version $(, $eval_always)? } }; ( @@ -87,11 +92,12 @@ macro_rules! declare_clippy_lint { pub $lint_name:ident, complexity, $desc:literal + $(@eval_always = $eval_always: literal)? ) => { declare_clippy_lint! {@ $(#[doc = $lit])* pub $lint_name, Warn, crate::LintCategory::Complexity, $desc, - Some($version), $version + Some($version), $version $(, $eval_always)? } }; ( @@ -100,11 +106,12 @@ macro_rules! declare_clippy_lint { pub $lint_name:ident, suspicious, $desc:literal + $(@eval_always = $eval_always: literal)? ) => { declare_clippy_lint! {@ $(#[doc = $lit])* pub $lint_name, Warn, crate::LintCategory::Suspicious, $desc, - Some($version), $version + Some($version), $version $(, $eval_always)? } }; ( @@ -113,11 +120,12 @@ macro_rules! declare_clippy_lint { pub $lint_name:ident, nursery, $desc:literal + $(@eval_always = $eval_always: literal)? ) => { declare_clippy_lint! {@ $(#[doc = $lit])* pub $lint_name, Allow, crate::LintCategory::Nursery, $desc, - Some($version), $version + Some($version), $version $(, $eval_always)? } }; ( @@ -126,11 +134,12 @@ macro_rules! declare_clippy_lint { pub $lint_name:ident, pedantic, $desc:literal + $(@eval_always = $eval_always: literal)? ) => { declare_clippy_lint! {@ $(#[doc = $lit])* pub $lint_name, Allow, crate::LintCategory::Pedantic, $desc, - Some($version), $version + Some($version), $version $(, $eval_always)? } }; ( @@ -139,11 +148,12 @@ macro_rules! declare_clippy_lint { pub $lint_name:ident, cargo, $desc:literal + $(@eval_always = $eval_always: literal)? ) => { declare_clippy_lint! {@ $(#[doc = $lit])* pub $lint_name, Allow, crate::LintCategory::Cargo, $desc, - Some($version), $version + Some($version), $version $(, $eval_always)? } };