diff options
Diffstat (limited to 'compiler/rustc_lint/src')
| -rw-r--r-- | compiler/rustc_lint/src/builtin.rs | 9 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/early.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/internal.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/late.rs | 38 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/levels.rs | 115 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/lib.rs | 26 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/passes.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/types.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/unused.rs | 4 |
9 files changed, 178 insertions, 35 deletions
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 70d51c92750..3ee4980a948 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -73,7 +73,6 @@ use crate::{ EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext, fluent_generated as fluent, }; - declare_lint! { /// The `while_true` lint detects `while true { }`. /// @@ -241,7 +240,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", + @eval_always = true } declare_lint_pass!(UnsafeCode => [UNSAFE_CODE]); @@ -389,6 +389,7 @@ declare_lint! { report_in_external_macro } +#[derive(Default)] pub struct MissingDoc; impl_lint_pass!(MissingDoc => [MISSING_DOCS]); @@ -819,8 +820,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 a6210aa520f..e2247d3a1f6 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -309,6 +309,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..7dec6dbdc05 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, + @eval_always = 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, + @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 6d5903ac467..9b1877599ba 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -26,11 +26,12 @@ use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::Session; use rustc_session::lint::LintPass; +use rustc_session::lint::builtin::HardwiredLints; use rustc_span::Span; use tracing::debug; use crate::passes::LateLintPassObject; -use crate::{LateContext, LateLintPass, LintStore}; +use crate::{LateContext, LateLintPass, LintId, LintStore}; /// Extract the [`LintStore`] from [`Session`]. /// @@ -326,6 +327,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 +365,20 @@ 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 builtin_lints = Box::new(builtin_lints) as Box<dyn LateLintPass<'tcx>>; + let mut binding = store + .late_module_passes + .iter() + .map(|mk_pass| (mk_pass)(tcx)) + .chain(std::iter::once(builtin_lints)) + .collect::<Vec<_>>(); + + let pass = RuntimeCombinedLateLintPass { passes: binding.as_mut_slice() }; late_lint_mod_inner(tcx, module_def_id, context, pass); } } @@ -398,7 +409,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() { @@ -416,7 +427,18 @@ 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(()); + + let mut filtered_passes: Vec<Box<dyn LateLintPass<'tcx>>> = passes + .into_iter() + .filter(|pass| { + let lints = (**pass).get_lints(); + !lints.iter().all(|lint| lints_that_dont_need_to_run.contains(&LintId::of(lint))) + }) + .collect(); + + filtered_passes.push(Box::new(HardwiredLints)); + let pass = RuntimeCombinedLateLintPass { passes: &mut filtered_passes[..] }; late_lint_crate_inner(tcx, context, pass); } diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index ff2ae69e1db..97a95787422 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -1,9 +1,9 @@ use rustc_ast_pretty::pprust; -use rustc_data_structures::fx::FxIndexMap; +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; @@ -115,6 +115,38 @@ impl LintLevelSets { } } +fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LintId> { + 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<LintId> = store + .get_lints() + .into_iter() + .filter_map(|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 + } + }) + .collect(); + + let mut visitor = LintLevelMaximum { tcx, dont_need_to_run }; + visitor.process_opts(); + tcx.hir().walk_attributes(&mut visitor); + + visitor.dont_need_to_run +} + #[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 +333,83 @@ 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 LintLevelMaximum<'tcx> { + tcx: TyCtxt<'tcx>, + /// The actual list of detected lints. + dont_need_to_run: FxIndexSet<LintId>, +} + +impl<'tcx> LintLevelMaximum<'tcx> { + fn process_opts(&mut self) { + 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 LintLevelMaximum<'tcx> { + type NestedFilter = nested_filter::All; + + fn nested_visit_map(&mut self) -> Self::Map { + 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) { + 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 }; + // 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::<Vec<&str>>() + .join("::"); + let Ok(lints) = store.find_lints( + // Lint attributes can only have literals + ident, + ) else { + return; + }; + for lint in lints { + self.dont_need_to_run.swap_remove(&lint); + } + } + } + } +} + pub struct LintLevelsBuilder<'s, P> { sess: &'s Session, features: &'s Features, @@ -934,7 +1043,7 @@ 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_dont_need_to_run, ..*providers }; } pub(crate) fn parse_lint_and_tool_name(lint_name: &str) -> (Option<Symbol>, &str) { diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index a7faab0868d..5389860e23b 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, @@ -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::lint_vec()); add_lint_group!( "nonstandard_style", @@ -602,25 +602,25 @@ fn register_builtins(store: &mut LintStore) { } fn register_internals(store: &mut LintStore) { - store.register_lints(&LintPassImpl::get_lints()); + store.register_lints(&LintPassImpl::lint_vec()); store.register_early_pass(|| Box::new(LintPassImpl)); - store.register_lints(&DefaultHashTypes::get_lints()); + store.register_lints(&DefaultHashTypes::lint_vec()); store.register_late_mod_pass(|_| Box::new(DefaultHashTypes)); - store.register_lints(&QueryStability::get_lints()); + store.register_lints(&QueryStability::lint_vec()); store.register_late_mod_pass(|_| Box::new(QueryStability)); - store.register_lints(&ExistingDocKeyword::get_lints()); + store.register_lints(&ExistingDocKeyword::lint_vec()); store.register_late_mod_pass(|_| Box::new(ExistingDocKeyword)); - store.register_lints(&TyTyKind::get_lints()); + store.register_lints(&TyTyKind::lint_vec()); store.register_late_mod_pass(|_| Box::new(TyTyKind)); - store.register_lints(&TypeIr::get_lints()); + store.register_lints(&TypeIr::lint_vec()); store.register_late_mod_pass(|_| Box::new(TypeIr)); - store.register_lints(&Diagnostics::get_lints()); + store.register_lints(&Diagnostics::lint_vec()); store.register_late_mod_pass(|_| Box::new(Diagnostics)); - store.register_lints(&BadOptAccess::get_lints()); + store.register_lints(&BadOptAccess::lint_vec()); store.register_late_mod_pass(|_| Box::new(BadOptAccess)); - store.register_lints(&PassByValue::get_lints()); + store.register_lints(&PassByValue::lint_vec()); store.register_late_mod_pass(|_| Box::new(PassByValue)); - store.register_lints(&SpanUseEqCtxt::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 75ae994a86b..9d84d36e779 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::lint_vec());)* 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::lint_vec());)* 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 60ff925b40e..0751d35cb9c 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -167,7 +167,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<hir::HirId>, diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index ddc18c755a8..bbb290c9459 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<ast::NodeId>, } -impl UnusedParens { - pub(crate) fn new() -> Self { +impl Default for UnusedParens { + fn default() -> Self { Self { with_self_ty_parens: false, parens_in_cast_in_lt: Vec::new() } } } |
