Skip to content

Commit e86daa3

Browse files
committed
Auto merge of #133781 - cjgillot:shallow-allowed-lints, r=<try>
Do not visit whole crate to compute `lints_that_dont_need_to_run`. r? `@ghost`
2 parents 946aea0 + 4e79e39 commit e86daa3

File tree

2 files changed

+25
-98
lines changed

2 files changed

+25
-98
lines changed

compiler/rustc_lint/src/levels.rs

+24-97
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
use rustc_ast::attr::AttributeExt;
22
use rustc_ast_pretty::pprust;
3-
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
3+
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
4+
use rustc_data_structures::unord::UnordSet;
45
use rustc_errors::{Diag, LintDiagnostic, MultiSpan};
56
use rustc_feature::{Features, GateIssue};
7+
use rustc_hir::HirId;
68
use rustc_hir::intravisit::{self, Visitor};
7-
use rustc_hir::{CRATE_HIR_ID, HirId};
89
use rustc_index::IndexVec;
910
use rustc_middle::bug;
1011
use rustc_middle::hir::nested_filter;
@@ -115,12 +116,10 @@ impl LintLevelSets {
115116
}
116117
}
117118

118-
fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LintId> {
119+
fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> UnordSet<LintId> {
119120
let store = unerased_lint_store(&tcx.sess);
120121

121-
let map = tcx.shallow_lint_levels_on(rustc_hir::CRATE_OWNER_ID);
122-
123-
let dont_need_to_run: FxIndexSet<LintId> = store
122+
let mut dont_need_to_run: FxHashSet<LintId> = store
124123
.get_lints()
125124
.into_iter()
126125
.filter(|lint| {
@@ -129,24 +128,28 @@ fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LintId> {
129128
lint.future_incompatible.is_some_and(|fut| fut.reason.has_future_breakage());
130129
!has_future_breakage && !lint.eval_always
131130
})
132-
.filter_map(|lint| {
133-
let lint_level = map.lint_level_id_at_node(tcx, LintId::of(lint), CRATE_HIR_ID);
134-
if matches!(lint_level, (Level::Allow, ..))
135-
|| (matches!(lint_level, (.., LintLevelSource::Default)))
136-
&& lint.default_level(tcx.sess.edition()) == Level::Allow
137-
{
138-
Some(LintId::of(lint))
139-
} else {
140-
None
141-
}
142-
})
131+
.map(|lint| LintId::of(*lint))
143132
.collect();
144133

145-
let mut visitor = LintLevelMaximum { tcx, dont_need_to_run };
146-
visitor.process_opts();
147-
tcx.hir_walk_attributes(&mut visitor);
134+
let mut remove_non_allow_lints_from_owner = |owner| {
135+
let map = tcx.shallow_lint_levels_on(owner);
148136

149-
visitor.dont_need_to_run
137+
// All lints that appear with a non-allow level must be run.
138+
for (_, specs) in map.specs.iter() {
139+
for (lint, (level, _)) in specs.iter() {
140+
if !matches!(level, Level::Allow) {
141+
dont_need_to_run.remove(lint);
142+
}
143+
}
144+
}
145+
};
146+
147+
remove_non_allow_lints_from_owner(rustc_hir::CRATE_OWNER_ID);
148+
for owner in tcx.hir_crate_items(()).owners() {
149+
remove_non_allow_lints_from_owner(owner);
150+
}
151+
152+
dont_need_to_run.into()
150153
}
151154

152155
#[instrument(level = "trace", skip(tcx), ret)]
@@ -340,82 +343,6 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> {
340343
}
341344
}
342345

343-
/// Visitor with the only function of visiting every item-like in a crate and
344-
/// computing the highest level that every lint gets put to.
345-
///
346-
/// E.g., if a crate has a global #![allow(lint)] attribute, but a single item
347-
/// uses #[warn(lint)], this visitor will set that lint level as `Warn`
348-
struct LintLevelMaximum<'tcx> {
349-
tcx: TyCtxt<'tcx>,
350-
/// The actual list of detected lints.
351-
dont_need_to_run: FxIndexSet<LintId>,
352-
}
353-
354-
impl<'tcx> LintLevelMaximum<'tcx> {
355-
fn process_opts(&mut self) {
356-
let store = unerased_lint_store(self.tcx.sess);
357-
for (lint_group, level) in &self.tcx.sess.opts.lint_opts {
358-
if *level != Level::Allow {
359-
let Ok(lints) = store.find_lints(lint_group) else {
360-
return;
361-
};
362-
for lint in lints {
363-
self.dont_need_to_run.swap_remove(&lint);
364-
}
365-
}
366-
}
367-
}
368-
}
369-
370-
impl<'tcx> Visitor<'tcx> for LintLevelMaximum<'tcx> {
371-
type NestedFilter = nested_filter::All;
372-
373-
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
374-
self.tcx
375-
}
376-
377-
/// FIXME(blyxyas): In a future revision, we should also graph #![allow]s,
378-
/// but that is handled with more care
379-
fn visit_attribute(&mut self, attribute: &'tcx hir::Attribute) {
380-
if matches!(
381-
Level::from_attr(attribute),
382-
Some(
383-
Level::Warn
384-
| Level::Deny
385-
| Level::Forbid
386-
| Level::Expect(..)
387-
| Level::ForceWarn(..),
388-
)
389-
) {
390-
let store = unerased_lint_store(self.tcx.sess);
391-
// Lint attributes are always a metalist inside a
392-
// metalist (even with just one lint).
393-
let Some(meta_item_list) = attribute.meta_item_list() else { return };
394-
395-
for meta_list in meta_item_list {
396-
// Convert Path to String
397-
let Some(meta_item) = meta_list.meta_item() else { return };
398-
let ident: &str = &meta_item
399-
.path
400-
.segments
401-
.iter()
402-
.map(|segment| segment.ident.as_str())
403-
.collect::<Vec<&str>>()
404-
.join("::");
405-
let Ok(lints) = store.find_lints(
406-
// Lint attributes can only have literals
407-
ident,
408-
) else {
409-
return;
410-
};
411-
for lint in lints {
412-
self.dont_need_to_run.swap_remove(&lint);
413-
}
414-
}
415-
}
416-
}
417-
}
418-
419346
pub struct LintLevelsBuilder<'s, P> {
420347
sess: &'s Session,
421348
features: &'s Features,

compiler/rustc_middle/src/query/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,7 @@ rustc_queries! {
476476
desc { "computing `#[expect]`ed lints in this crate" }
477477
}
478478

479-
query lints_that_dont_need_to_run(_: ()) -> &'tcx FxIndexSet<LintId> {
479+
query lints_that_dont_need_to_run(_: ()) -> &'tcx UnordSet<LintId> {
480480
arena_cache
481481
desc { "Computing all lints that are explicitly enabled or with a default level greater than Allow" }
482482
}

0 commit comments

Comments
 (0)