1
Fork 0

Auto merge of #125116 - blyxyas:ignore-allowed-lints-final, r=cjgillot

(Big performance change) 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. This change would improve both the Rust lint infrastructure and Clippy, but Clippy will see the most benefit, as it has about 900 registered lints (and growing!)

So yeah, with this little patch we filter all lints pre-linting, and remove any lint that is either:
- Manually `#![allow]`ed in the whole crate,
- Allowed in the command line, or
- Not manually enabled with `#[warn]` or similar, and its default level is `Allow`

As some lints **need** to run, this PR also adds **loadbearing lints**. On a lint declaration, you can use the ``@eval_always` = true` marker to label it as loadbearing. A loadbearing lint will never be filtered (it will always run)

Fixes #106983
This commit is contained in:
bors 2024-10-26 16:37:43 +00:00
commit 4d88de2acd
45 changed files with 291 additions and 56 deletions

View file

@ -4029,6 +4029,7 @@ dependencies = [
"rustc_hir", "rustc_hir",
"rustc_hir_pretty", "rustc_hir_pretty",
"rustc_index", "rustc_index",
"rustc_lint_defs",
"rustc_macros", "rustc_macros",
"rustc_query_system", "rustc_query_system",
"rustc_serialize", "rustc_serialize",

View file

@ -223,7 +223,7 @@ impl AttrItem {
self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span)) self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span))
} }
fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> { pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
match &self.args { match &self.args {
AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => { AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
MetaItemKind::list_from_tokens(args.tokens.clone()) MetaItemKind::list_from_tokens(args.tokens.clone())

View file

@ -73,7 +73,6 @@ use crate::{
EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext, EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext,
fluent_generated as fluent, fluent_generated as fluent,
}; };
declare_lint! { declare_lint! {
/// The `while_true` lint detects `while true { }`. /// The `while_true` lint detects `while true { }`.
/// ///
@ -241,7 +240,8 @@ declare_lint! {
/// behavior. /// behavior.
UNSAFE_CODE, UNSAFE_CODE,
Allow, 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]); declare_lint_pass!(UnsafeCode => [UNSAFE_CODE]);
@ -389,6 +389,7 @@ declare_lint! {
report_in_external_macro report_in_external_macro
} }
#[derive(Default)]
pub struct MissingDoc; pub struct MissingDoc;
impl_lint_pass!(MissingDoc => [MISSING_DOCS]); impl_lint_pass!(MissingDoc => [MISSING_DOCS]);
@ -819,8 +820,8 @@ pub struct DeprecatedAttr {
impl_lint_pass!(DeprecatedAttr => []); impl_lint_pass!(DeprecatedAttr => []);
impl DeprecatedAttr { impl Default for DeprecatedAttr {
pub fn new() -> DeprecatedAttr { fn default() -> Self {
DeprecatedAttr { depr_attrs: deprecated_attributes() } DeprecatedAttr { depr_attrs: deprecated_attributes() }
} }
} }

View file

@ -309,6 +309,9 @@ impl LintPass for RuntimeCombinedEarlyLintPass<'_> {
fn name(&self) -> &'static str { fn name(&self) -> &'static str {
panic!() panic!()
} }
fn get_lints(&self) -> crate::LintVec {
panic!()
}
} }
macro_rules! impl_early_lint_pass { macro_rules! impl_early_lint_pass {

View file

@ -429,7 +429,8 @@ declare_tool_lint! {
pub rustc::UNTRANSLATABLE_DIAGNOSTIC, pub rustc::UNTRANSLATABLE_DIAGNOSTIC,
Deny, Deny,
"prevent creation of diagnostics which cannot be translated", "prevent creation of diagnostics which cannot be translated",
report_in_external_macro: true report_in_external_macro: true,
@eval_always = true
} }
declare_tool_lint! { declare_tool_lint! {
@ -442,7 +443,8 @@ declare_tool_lint! {
pub rustc::DIAGNOSTIC_OUTSIDE_OF_IMPL, pub rustc::DIAGNOSTIC_OUTSIDE_OF_IMPL,
Deny, Deny,
"prevent diagnostic creation outside of `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls", "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]); declare_lint_pass!(Diagnostics => [UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE_OF_IMPL]);

View file

@ -26,11 +26,12 @@ use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::ty::{self, TyCtxt};
use rustc_session::Session; use rustc_session::Session;
use rustc_session::lint::LintPass; use rustc_session::lint::LintPass;
use rustc_session::lint::builtin::HardwiredLints;
use rustc_span::Span; use rustc_span::Span;
use tracing::debug; use tracing::debug;
use crate::passes::LateLintPassObject; use crate::passes::LateLintPassObject;
use crate::{LateContext, LateLintPass, LintStore}; use crate::{LateContext, LateLintPass, LintId, LintStore};
/// Extract the [`LintStore`] from [`Session`]. /// Extract the [`LintStore`] from [`Session`].
/// ///
@ -326,6 +327,9 @@ impl LintPass for RuntimeCombinedLateLintPass<'_, '_> {
fn name(&self) -> &'static str { fn name(&self) -> &'static str {
panic!() panic!()
} }
fn get_lints(&self) -> crate::LintVec {
panic!()
}
} }
macro_rules! impl_late_lint_pass { 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 // Note: `passes` is often empty. In that case, it's faster to run
// `builtin_lints` directly rather than bundling it up into the // `builtin_lints` directly rather than bundling it up into the
// `RuntimeCombinedLateLintPass`. // `RuntimeCombinedLateLintPass`.
let late_module_passes = &unerased_lint_store(tcx.sess).late_module_passes; let store = unerased_lint_store(tcx.sess);
if late_module_passes.is_empty() {
if store.late_module_passes.is_empty() {
late_lint_mod_inner(tcx, module_def_id, context, builtin_lints); late_lint_mod_inner(tcx, module_def_id, context, builtin_lints);
} else { } else {
let mut passes: Vec<_> = late_module_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect(); let builtin_lints = Box::new(builtin_lints) as Box<dyn LateLintPass<'tcx>>;
passes.push(Box::new(builtin_lints)); let mut binding = store
let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] }; .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); 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>) { fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) {
// Note: `passes` is often empty. // 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(); unerased_lint_store(tcx.sess).late_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect();
if passes.is_empty() { if passes.is_empty() {
@ -416,7 +427,18 @@ fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) {
only_module: false, 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); late_lint_crate_inner(tcx, context, pass);
} }

View file

@ -1,9 +1,9 @@
use rustc_ast_pretty::pprust; 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_errors::{Diag, LintDiagnostic, MultiSpan};
use rustc_feature::{Features, GateIssue}; use rustc_feature::{Features, GateIssue};
use rustc_hir::HirId;
use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{CRATE_HIR_ID, HirId};
use rustc_index::IndexVec; use rustc_index::IndexVec;
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::hir::nested_filter; 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)] #[instrument(level = "trace", skip(tcx), ret)]
fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLevelMap { fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLevelMap {
let store = unerased_lint_store(tcx.sess); 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> { pub struct LintLevelsBuilder<'s, P> {
sess: &'s Session, sess: &'s Session,
features: &'s Features, features: &'s Features,
@ -934,7 +1043,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
} }
pub(crate) fn provide(providers: &mut Providers) { 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) { pub(crate) fn parse_lint_and_tool_name(lint_name: &str) -> (Option<Symbol>, &str) {

View file

@ -170,7 +170,7 @@ early_lint_methods!(
[ [
pub BuiltinCombinedEarlyLintPass, pub BuiltinCombinedEarlyLintPass,
[ [
UnusedParens: UnusedParens::new(), UnusedParens: UnusedParens::default(),
UnusedBraces: UnusedBraces, UnusedBraces: UnusedBraces,
UnusedImportBraces: UnusedImportBraces, UnusedImportBraces: UnusedImportBraces,
UnsafeCode: UnsafeCode, UnsafeCode: UnsafeCode,
@ -178,7 +178,7 @@ early_lint_methods!(
AnonymousParameters: AnonymousParameters, AnonymousParameters: AnonymousParameters,
EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(), EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(),
NonCamelCaseTypes: NonCamelCaseTypes, NonCamelCaseTypes: NonCamelCaseTypes,
DeprecatedAttr: DeprecatedAttr::new(), DeprecatedAttr: DeprecatedAttr::default(),
WhileTrue: WhileTrue, WhileTrue: WhileTrue,
NonAsciiIdents: NonAsciiIdents, NonAsciiIdents: NonAsciiIdents,
HiddenUnicodeCodepoints: HiddenUnicodeCodepoints, HiddenUnicodeCodepoints: HiddenUnicodeCodepoints,
@ -199,7 +199,6 @@ late_lint_methods!(
ForLoopsOverFallibles: ForLoopsOverFallibles, ForLoopsOverFallibles: ForLoopsOverFallibles,
DerefIntoDynSupertrait: DerefIntoDynSupertrait, DerefIntoDynSupertrait: DerefIntoDynSupertrait,
DropForgetUseless: DropForgetUseless, DropForgetUseless: DropForgetUseless,
HardwiredLints: HardwiredLints,
ImproperCTypesDeclarations: ImproperCTypesDeclarations, ImproperCTypesDeclarations: ImproperCTypesDeclarations,
ImproperCTypesDefinitions: ImproperCTypesDefinitions, ImproperCTypesDefinitions: ImproperCTypesDefinitions,
InvalidFromUtf8: InvalidFromUtf8, InvalidFromUtf8: InvalidFromUtf8,
@ -280,6 +279,7 @@ fn register_builtins(store: &mut LintStore) {
store.register_lints(&BuiltinCombinedEarlyLintPass::get_lints()); store.register_lints(&BuiltinCombinedEarlyLintPass::get_lints());
store.register_lints(&BuiltinCombinedModuleLateLintPass::get_lints()); store.register_lints(&BuiltinCombinedModuleLateLintPass::get_lints());
store.register_lints(&foreign_modules::get_lints()); store.register_lints(&foreign_modules::get_lints());
store.register_lints(&HardwiredLints::lint_vec());
add_lint_group!( add_lint_group!(
"nonstandard_style", "nonstandard_style",
@ -602,25 +602,25 @@ fn register_builtins(store: &mut LintStore) {
} }
fn register_internals(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_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_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_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_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_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_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_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_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_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)); store.register_late_mod_pass(|_| Box::new(SpanUseEqCtxt));
// FIXME(davidtwco): deliberately do not include `UNTRANSLATABLE_DIAGNOSTIC` and // FIXME(davidtwco): deliberately do not include `UNTRANSLATABLE_DIAGNOSTIC` and
// `DIAGNOSTIC_OUTSIDE_OF_IMPL` here because `-Wrustc::internal` is provided to every crate and // `DIAGNOSTIC_OUTSIDE_OF_IMPL` here because `-Wrustc::internal` is provided to every crate and

View file

@ -110,7 +110,7 @@ macro_rules! declare_combined_late_lint_pass {
$v fn get_lints() -> $crate::LintVec { $v fn get_lints() -> $crate::LintVec {
let mut lints = Vec::new(); let mut lints = Vec::new();
$(lints.extend_from_slice(&$pass::get_lints());)* $(lints.extend_from_slice(&$pass::lint_vec());)*
lints lints
} }
} }
@ -124,6 +124,9 @@ macro_rules! declare_combined_late_lint_pass {
fn name(&self) -> &'static str { fn name(&self) -> &'static str {
panic!() panic!()
} }
fn get_lints(&self) -> LintVec {
panic!()
}
} }
) )
} }
@ -222,7 +225,7 @@ macro_rules! declare_combined_early_lint_pass {
$v fn get_lints() -> $crate::LintVec { $v fn get_lints() -> $crate::LintVec {
let mut lints = Vec::new(); let mut lints = Vec::new();
$(lints.extend_from_slice(&$pass::get_lints());)* $(lints.extend_from_slice(&$pass::lint_vec());)*
lints lints
} }
} }
@ -236,6 +239,9 @@ macro_rules! declare_combined_early_lint_pass {
fn name(&self) -> &'static str { fn name(&self) -> &'static str {
panic!() panic!()
} }
fn get_lints(&self) -> LintVec {
panic!()
}
} }
) )
} }

View file

@ -167,7 +167,7 @@ declare_lint! {
"detects ambiguous wide pointer comparisons" "detects ambiguous wide pointer comparisons"
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone, Default)]
pub(crate) struct TypeLimits { pub(crate) struct TypeLimits {
/// Id of the last visited negated expression /// Id of the last visited negated expression
negated_expr_id: Option<hir::HirId>, negated_expr_id: Option<hir::HirId>,

View file

@ -1025,8 +1025,8 @@ pub(crate) struct UnusedParens {
parens_in_cast_in_lt: Vec<ast::NodeId>, parens_in_cast_in_lt: Vec<ast::NodeId>,
} }
impl UnusedParens { impl Default for UnusedParens {
pub(crate) fn new() -> Self { fn default() -> Self {
Self { with_self_ty_parens: false, parens_in_cast_in_lt: Vec::new() } Self { with_self_ty_parens: false, parens_in_cast_in_lt: Vec::new() }
} }
} }

View file

@ -377,7 +377,8 @@ declare_lint! {
/// will not overflow. /// will not overflow.
pub ARITHMETIC_OVERFLOW, pub ARITHMETIC_OVERFLOW,
Deny, Deny,
"arithmetic operation overflows" "arithmetic operation overflows",
@eval_always = true
} }
declare_lint! { declare_lint! {
@ -401,7 +402,8 @@ declare_lint! {
/// `panic!` or `unreachable!` macro instead in case the panic is intended. /// `panic!` or `unreachable!` macro instead in case the panic is intended.
pub UNCONDITIONAL_PANIC, pub UNCONDITIONAL_PANIC,
Deny, Deny,
"operation will cause a panic at runtime" "operation will cause a panic at runtime",
@eval_always = true
} }
declare_lint! { declare_lint! {
@ -632,7 +634,8 @@ declare_lint! {
/// is only available in a newer version. /// is only available in a newer version.
pub UNKNOWN_LINTS, pub UNKNOWN_LINTS,
Warn, Warn,
"unrecognized lint attribute" "unrecognized lint attribute",
@eval_always = true
} }
declare_lint! { declare_lint! {

View file

@ -312,6 +312,10 @@ pub struct Lint {
pub feature_gate: Option<Symbol>, pub feature_gate: Option<Symbol>,
pub crate_level_only: bool, pub crate_level_only: bool,
/// `true` if this lint should not be filtered out under any circustamces
/// (e.g. the unknown_attributes lint)
pub eval_always: bool,
} }
/// Extra information for a future incompatibility lint. /// Extra information for a future incompatibility lint.
@ -456,6 +460,7 @@ impl Lint {
future_incompatible: None, future_incompatible: None,
feature_gate: None, feature_gate: None,
crate_level_only: false, crate_level_only: false,
eval_always: false,
} }
} }
@ -864,6 +869,7 @@ macro_rules! declare_lint {
); );
); );
($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr, ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr,
$(@eval_always = $eval_always:literal)?
$(@feature_gate = $gate:ident;)? $(@feature_gate = $gate:ident;)?
$(@future_incompatible = FutureIncompatibleInfo { $(@future_incompatible = FutureIncompatibleInfo {
reason: $reason:expr, reason: $reason:expr,
@ -885,6 +891,7 @@ macro_rules! declare_lint {
..$crate::FutureIncompatibleInfo::default_fields_for_macro() ..$crate::FutureIncompatibleInfo::default_fields_for_macro()
}),)? }),)?
$(edition_lint_opts: Some(($crate::Edition::$lint_edition, $crate::$edition_level)),)? $(edition_lint_opts: Some(($crate::Edition::$lint_edition, $crate::$edition_level)),)?
$(eval_always: $eval_always,)?
..$crate::Lint::default_fields_for_macro() ..$crate::Lint::default_fields_for_macro()
}; };
); );
@ -894,20 +901,23 @@ macro_rules! declare_lint {
macro_rules! declare_tool_lint { macro_rules! declare_tool_lint {
( (
$(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level: ident, $desc: expr $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level: ident, $desc: expr
$(, @eval_always = $eval_always:literal)?
$(, @feature_gate = $gate:ident;)? $(, @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, $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr,
report_in_external_macro: $rep:expr report_in_external_macro: $rep:expr
$(, @eval_always = $eval_always: literal)?
$(, @feature_gate = $gate:ident;)? $(, @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, $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr,
$external:expr $external:expr
$(, @eval_always = $eval_always: literal)?
$(, @feature_gate = $gate:ident;)? $(, @feature_gate = $gate:ident;)?
) => ( ) => (
$(#[$attr])* $(#[$attr])*
@ -921,6 +931,7 @@ macro_rules! declare_tool_lint {
is_externally_loaded: true, is_externally_loaded: true,
$(feature_gate: Some(rustc_span::symbol::sym::$gate),)? $(feature_gate: Some(rustc_span::symbol::sym::$gate),)?
crate_level_only: false, crate_level_only: false,
$(eval_always: $eval_always,)?
..$crate::Lint::default_fields_for_macro() ..$crate::Lint::default_fields_for_macro()
}; };
); );
@ -930,6 +941,7 @@ pub type LintVec = Vec<&'static Lint>;
pub trait LintPass { pub trait LintPass {
fn name(&self) -> &'static str; fn name(&self) -> &'static str;
fn get_lints(&self) -> LintVec;
} }
/// Implements `LintPass for $ty` with the given list of `Lint` statics. /// Implements `LintPass for $ty` with the given list of `Lint` statics.
@ -938,9 +950,11 @@ macro_rules! impl_lint_pass {
($ty:ty => [$($lint:expr),* $(,)?]) => { ($ty:ty => [$($lint:expr),* $(,)?]) => {
impl $crate::LintPass for $ty { impl $crate::LintPass for $ty {
fn name(&self) -> &'static str { stringify!($ty) } fn name(&self) -> &'static str { stringify!($ty) }
fn get_lints(&self) -> $crate::LintVec { vec![$($lint),*] }
} }
impl $ty { impl $ty {
pub fn get_lints() -> $crate::LintVec { vec![$($lint),*] } #[allow(unused)]
pub fn lint_vec() -> $crate::LintVec { vec![$($lint),*] }
} }
}; };
} }

View file

@ -27,6 +27,7 @@ rustc_graphviz = { path = "../rustc_graphviz" }
rustc_hir = { path = "../rustc_hir" } rustc_hir = { path = "../rustc_hir" }
rustc_hir_pretty = { path = "../rustc_hir_pretty" } rustc_hir_pretty = { path = "../rustc_hir_pretty" }
rustc_index = { path = "../rustc_index" } rustc_index = { path = "../rustc_index" }
rustc_lint_defs = { path = "../rustc_lint_defs" }
rustc_macros = { path = "../rustc_macros" } rustc_macros = { path = "../rustc_macros" }
rustc_query_system = { path = "../rustc_query_system" } rustc_query_system = { path = "../rustc_query_system" }
rustc_serialize = { path = "../rustc_serialize" } rustc_serialize = { path = "../rustc_serialize" }

View file

@ -29,6 +29,7 @@ use rustc_hir::def_id::{
use rustc_hir::lang_items::{LangItem, LanguageItems}; use rustc_hir::lang_items::{LangItem, LanguageItems};
use rustc_hir::{Crate, ItemLocalId, ItemLocalMap, TraitCandidate}; use rustc_hir::{Crate, ItemLocalId, ItemLocalMap, TraitCandidate};
use rustc_index::IndexVec; use rustc_index::IndexVec;
use rustc_lint_defs::LintId;
use rustc_macros::rustc_queries; use rustc_macros::rustc_queries;
use rustc_query_system::ich::StableHashingContext; use rustc_query_system::ich::StableHashingContext;
use rustc_query_system::query::{QueryCache, QueryMode, QueryState, try_get_cached}; use rustc_query_system::query::{QueryCache, QueryMode, QueryState, try_get_cached};
@ -422,6 +423,11 @@ rustc_queries! {
desc { "computing `#[expect]`ed lints in this crate" } desc { "computing `#[expect]`ed lints in this crate" }
} }
query lints_that_dont_need_to_run(_: ()) -> &'tcx FxIndexSet<LintId> {
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 { query expn_that_defined(key: DefId) -> rustc_span::ExpnId {
desc { |tcx| "getting the expansion that defined `{}`", tcx.def_path_str(key) } desc { |tcx| "getting the expansion that defined `{}`", tcx.def_path_str(key) }
separate_provide_extern separate_provide_extern

View file

@ -31,9 +31,9 @@ where
allowed_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned()); allowed_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned());
let lints = || { let lints = || {
lint::builtin::HardwiredLints::get_lints() lint::builtin::HardwiredLints::lint_vec()
.into_iter() .into_iter()
.chain(rustc_lint::SoftLints::get_lints()) .chain(rustc_lint::SoftLints::lint_vec())
}; };
let lint_opts = lints() let lint_opts = lints()

View file

@ -31,6 +31,7 @@ declare_clippy_lint! {
pub COGNITIVE_COMPLEXITY, pub COGNITIVE_COMPLEXITY,
nursery, nursery,
"functions that should be split up into multiple functions" "functions that should be split up into multiple functions"
@eval_always = true
} }
pub struct CognitiveComplexity { pub struct CognitiveComplexity {

View file

@ -0,0 +1,40 @@
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, FnDecl};
use rustc_lint::Level::Deny;
use rustc_lint::{LateContext, LateLintPass, Lint};
use rustc_session::declare_lint_pass;
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.
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] }
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
}
}

View file

@ -9,6 +9,7 @@ macro_rules! declare_clippy_lint {
$desc:literal, $desc:literal,
$version_expr:expr, $version_expr:expr,
$version_lit:literal $version_lit:literal
$(, $eval_always: literal)?
) => { ) => {
rustc_session::declare_tool_lint! { rustc_session::declare_tool_lint! {
$(#[doc = $lit])* $(#[doc = $lit])*
@ -17,6 +18,7 @@ macro_rules! declare_clippy_lint {
$category, $category,
$desc, $desc,
report_in_external_macro:true report_in_external_macro:true
$(, @eval_always = $eval_always)?
} }
pub(crate) static ${concat($lint_name, _INFO)}: &'static crate::LintInfo = &crate::LintInfo { 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, pub $lint_name:ident,
restriction, restriction,
$desc:literal $desc:literal
$(@eval_always = $eval_always: literal)?
) => { ) => {
declare_clippy_lint! {@ declare_clippy_lint! {@
$(#[doc = $lit])* $(#[doc = $lit])*
pub $lint_name, Allow, crate::LintCategory::Restriction, $desc, 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, pub $lint_name:ident,
style, style,
$desc:literal $desc:literal
$(@eval_always = $eval_always: literal)?
) => { ) => {
declare_clippy_lint! {@ declare_clippy_lint! {@
$(#[doc = $lit])* $(#[doc = $lit])*
pub $lint_name, Warn, crate::LintCategory::Style, $desc, 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, pub $lint_name:ident,
correctness, correctness,
$desc:literal $desc:literal
$(@eval_always = $eval_always: literal)?
) => { ) => {
declare_clippy_lint! {@ declare_clippy_lint! {@
$(#[doc = $lit])* $(#[doc = $lit])*
pub $lint_name, Deny, crate::LintCategory::Correctness, $desc, 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, pub $lint_name:ident,
perf, perf,
$desc:literal $desc:literal
$(@eval_always = $eval_always: literal)?
) => { ) => {
declare_clippy_lint! {@ declare_clippy_lint! {@
$(#[doc = $lit])* $(#[doc = $lit])*
pub $lint_name, Warn, crate::LintCategory::Perf, $desc, 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, pub $lint_name:ident,
complexity, complexity,
$desc:literal $desc:literal
$(@eval_always = $eval_always: literal)?
) => { ) => {
declare_clippy_lint! {@ declare_clippy_lint! {@
$(#[doc = $lit])* $(#[doc = $lit])*
pub $lint_name, Warn, crate::LintCategory::Complexity, $desc, 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, pub $lint_name:ident,
suspicious, suspicious,
$desc:literal $desc:literal
$(@eval_always = $eval_always: literal)?
) => { ) => {
declare_clippy_lint! {@ declare_clippy_lint! {@
$(#[doc = $lit])* $(#[doc = $lit])*
pub $lint_name, Warn, crate::LintCategory::Suspicious, $desc, 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, pub $lint_name:ident,
nursery, nursery,
$desc:literal $desc:literal
$(@eval_always = $eval_always: literal)?
) => { ) => {
declare_clippy_lint! {@ declare_clippy_lint! {@
$(#[doc = $lit])* $(#[doc = $lit])*
pub $lint_name, Allow, crate::LintCategory::Nursery, $desc, 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, pub $lint_name:ident,
pedantic, pedantic,
$desc:literal $desc:literal
$(@eval_always = $eval_always: literal)?
) => { ) => {
declare_clippy_lint! {@ declare_clippy_lint! {@
$(#[doc = $lit])* $(#[doc = $lit])*
pub $lint_name, Allow, crate::LintCategory::Pedantic, $desc, 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, pub $lint_name:ident,
cargo, cargo,
$desc:literal $desc:literal
$(@eval_always = $eval_always: literal)?
) => { ) => {
declare_clippy_lint! {@ declare_clippy_lint! {@
$(#[doc = $lit])* $(#[doc = $lit])*
pub $lint_name, Allow, crate::LintCategory::Cargo, $desc, pub $lint_name, Allow, crate::LintCategory::Cargo, $desc,
Some($version), $version Some($version), $version $(, $eval_always)?
} }
}; };

View file

@ -65,6 +65,7 @@ extern crate clippy_utils;
#[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))] #[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))]
mod utils; mod utils;
pub mod ctfe; // Very important lint, do not remove (rust#125116)
pub mod declared_lints; pub mod declared_lints;
pub mod deprecated_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(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::dump_hir::DumpHir));
store.register_late_pass(|_| Box::new(utils::author::Author)); store.register_late_pass(|_| Box::new(utils::author::Author));

View file

@ -1,3 +1,5 @@
#![warn(clippy::author)]
fn main() { fn main() {
#[clippy::author] #[clippy::author]
let x: char = 0x45 as char; let x: char = 0x45 as char;

View file

@ -0,0 +1,3 @@
#![deny(clippy::all)]
fn main() {}

View file

@ -6,7 +6,7 @@
extern crate rustc_middle; extern crate rustc_middle;
extern crate rustc_session; 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}; use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};
declare_lint! { declare_lint! {
@ -21,6 +21,10 @@ impl LintPass for Foo { //~ERROR implementing `LintPass` by hand
fn name(&self) -> &'static str { fn name(&self) -> &'static str {
"Foo" "Foo"
} }
fn get_lints(&self) -> Vec<&'static Lint> {
vec![TEST_LINT]
}
} }
macro_rules! custom_lint_pass_macro { macro_rules! custom_lint_pass_macro {
@ -31,6 +35,10 @@ macro_rules! custom_lint_pass_macro {
fn name(&self) -> &'static str { fn name(&self) -> &'static str {
"Custom" "Custom"
} }
fn get_lints(&self) -> Vec<&'static Lint> {
vec![TEST_LINT]
}
} }
}; };
} }

View file

@ -12,7 +12,7 @@ LL | #![deny(rustc::lint_pass_impl_without_macro)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: implementing `LintPass` by hand 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 { LL | impl LintPass for Custom {
| ^^^^^^^^ | ^^^^^^^^