mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
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:
commit
4d88de2acd
@ -4029,6 +4029,7 @@ dependencies = [
|
||||
"rustc_hir",
|
||||
"rustc_hir_pretty",
|
||||
"rustc_index",
|
||||
"rustc_lint_defs",
|
||||
"rustc_macros",
|
||||
"rustc_query_system",
|
||||
"rustc_serialize",
|
||||
|
@ -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<ThinVec<MetaItemInner>> {
|
||||
pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
|
||||
match &self.args {
|
||||
AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
|
||||
MetaItemKind::list_from_tokens(args.tokens.clone())
|
||||
|
@ -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() }
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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]);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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!()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -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>,
|
||||
|
@ -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() }
|
||||
}
|
||||
}
|
||||
|
@ -377,7 +377,8 @@ declare_lint! {
|
||||
/// will not overflow.
|
||||
pub ARITHMETIC_OVERFLOW,
|
||||
Deny,
|
||||
"arithmetic operation overflows"
|
||||
"arithmetic operation overflows",
|
||||
@eval_always = true
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
@ -401,7 +402,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",
|
||||
@eval_always = true
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
@ -632,7 +634,8 @@ declare_lint! {
|
||||
/// is only available in a newer version.
|
||||
pub UNKNOWN_LINTS,
|
||||
Warn,
|
||||
"unrecognized lint attribute"
|
||||
"unrecognized lint attribute",
|
||||
@eval_always = true
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
|
@ -312,6 +312,10 @@ pub struct Lint {
|
||||
pub feature_gate: Option<Symbol>,
|
||||
|
||||
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.
|
||||
@ -456,6 +460,7 @@ impl Lint {
|
||||
future_incompatible: None,
|
||||
feature_gate: None,
|
||||
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,
|
||||
$(@eval_always = $eval_always:literal)?
|
||||
$(@feature_gate = $gate:ident;)?
|
||||
$(@future_incompatible = FutureIncompatibleInfo {
|
||||
reason: $reason:expr,
|
||||
@ -885,6 +891,7 @@ macro_rules! declare_lint {
|
||||
..$crate::FutureIncompatibleInfo::default_fields_for_macro()
|
||||
}),)?
|
||||
$(edition_lint_opts: Some(($crate::Edition::$lint_edition, $crate::$edition_level)),)?
|
||||
$(eval_always: $eval_always,)?
|
||||
..$crate::Lint::default_fields_for_macro()
|
||||
};
|
||||
);
|
||||
@ -894,20 +901,23 @@ 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;)?
|
||||
) => (
|
||||
$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
|
||||
$(, @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,
|
||||
$external:expr
|
||||
$(, @eval_always = $eval_always: literal)?
|
||||
$(, @feature_gate = $gate:ident;)?
|
||||
) => (
|
||||
$(#[$attr])*
|
||||
@ -921,6 +931,7 @@ macro_rules! declare_tool_lint {
|
||||
is_externally_loaded: true,
|
||||
$(feature_gate: Some(rustc_span::symbol::sym::$gate),)?
|
||||
crate_level_only: false,
|
||||
$(eval_always: $eval_always,)?
|
||||
..$crate::Lint::default_fields_for_macro()
|
||||
};
|
||||
);
|
||||
@ -930,6 +941,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 +950,11 @@ macro_rules! impl_lint_pass {
|
||||
($ty:ty => [$($lint:expr),* $(,)?]) => {
|
||||
impl $crate::LintPass for $ty {
|
||||
fn name(&self) -> &'static str { stringify!($ty) }
|
||||
fn get_lints(&self) -> $crate::LintVec { vec![$($lint),*] }
|
||||
}
|
||||
impl $ty {
|
||||
pub fn get_lints() -> $crate::LintVec { vec![$($lint),*] }
|
||||
#[allow(unused)]
|
||||
pub fn lint_vec() -> $crate::LintVec { vec![$($lint),*] }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -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" }
|
||||
|
@ -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,6 +423,11 @@ rustc_queries! {
|
||||
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 {
|
||||
desc { |tcx| "getting the expansion that defined `{}`", tcx.def_path_str(key) }
|
||||
separate_provide_extern
|
||||
|
@ -31,9 +31,9 @@ where
|
||||
allowed_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned());
|
||||
|
||||
let lints = || {
|
||||
lint::builtin::HardwiredLints::get_lints()
|
||||
lint::builtin::HardwiredLints::lint_vec()
|
||||
.into_iter()
|
||||
.chain(rustc_lint::SoftLints::get_lints())
|
||||
.chain(rustc_lint::SoftLints::lint_vec())
|
||||
};
|
||||
|
||||
let lint_opts = lints()
|
||||
|
@ -31,6 +31,7 @@ declare_clippy_lint! {
|
||||
pub COGNITIVE_COMPLEXITY,
|
||||
nursery,
|
||||
"functions that should be split up into multiple functions"
|
||||
@eval_always = true
|
||||
}
|
||||
|
||||
pub struct CognitiveComplexity {
|
||||
|
40
src/tools/clippy/clippy_lints/src/ctfe.rs
Normal file
40
src/tools/clippy/clippy_lints/src/ctfe.rs
Normal 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
|
||||
}
|
||||
}
|
@ -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)?
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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, do not remove (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));
|
||||
|
@ -1,3 +1,5 @@
|
||||
#![warn(clippy::author)]
|
||||
|
||||
fn main() {
|
||||
#[clippy::author]
|
||||
let x: char = 0x45 as char;
|
3
src/tools/clippy/tests/ui/no_lints.rs
Normal file
3
src/tools/clippy/tests/ui/no_lints.rs
Normal file
@ -0,0 +1,3 @@
|
||||
#![deny(clippy::all)]
|
||||
|
||||
fn main() {}
|
@ -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]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -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 {
|
||||
| ^^^^^^^^
|
||||
|
Loading…
Reference in New Issue
Block a user