Skip to content

Commit c6c1796

Browse files
committed
Auto merge of rust-lang#133781 - cjgillot:shallow-allowed-lints, r=petrochenkov
Do not visit whole crate to compute `lints_that_dont_need_to_run`. This allows to reuse the computed lint levels instead of re-visiting the whole crate.
2 parents e643f59 + 280a1d8 commit c6c1796

10 files changed

+79
-95
lines changed

Diff for: compiler/rustc_lint/src/levels.rs

+27-90
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,11 @@ 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);
121+
let root_map = tcx.shallow_lint_levels_on(hir::CRATE_OWNER_ID);
120122

121-
let map = tcx.shallow_lint_levels_on(rustc_hir::CRATE_OWNER_ID);
122-
123-
let dont_need_to_run: FxIndexSet<LintId> = store
123+
let mut dont_need_to_run: FxHashSet<LintId> = store
124124
.get_lints()
125125
.into_iter()
126126
.filter(|lint| {
@@ -129,24 +129,31 @@ fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LintId> {
129129
lint.future_incompatible.is_some_and(|fut| fut.reason.has_future_breakage());
130130
!has_future_breakage && !lint.eval_always
131131
})
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, Level::Allow)
135-
|| (matches!(lint_level.src, LintLevelSource::Default))
136-
&& lint.default_level(tcx.sess.edition()) == Level::Allow
137-
{
138-
Some(LintId::of(lint))
139-
} else {
140-
None
141-
}
132+
.filter(|lint| {
133+
let lint_level =
134+
root_map.lint_level_id_at_node(tcx, LintId::of(lint), hir::CRATE_HIR_ID);
135+
// Only include lints that are allowed at crate root or by default.
136+
matches!(lint_level.level, Level::Allow)
137+
|| (matches!(lint_level.src, LintLevelSource::Default)
138+
&& lint.default_level(tcx.sess.edition()) == Level::Allow)
142139
})
140+
.map(|lint| LintId::of(*lint))
143141
.collect();
144142

145-
let mut visitor = LintLevelMaximum { tcx, dont_need_to_run };
146-
visitor.process_opts();
147-
tcx.hir_walk_attributes(&mut visitor);
143+
for owner in tcx.hir_crate_items(()).owners() {
144+
let map = tcx.shallow_lint_levels_on(owner);
145+
146+
// All lints that appear with a non-allow level must be run.
147+
for (_, specs) in map.specs.iter() {
148+
for (lint, level_and_source) in specs.iter() {
149+
if !matches!(level_and_source.level, Level::Allow) {
150+
dont_need_to_run.remove(lint);
151+
}
152+
}
153+
}
154+
}
148155

149-
visitor.dont_need_to_run
156+
dont_need_to_run.into()
150157
}
151158

152159
#[instrument(level = "trace", skip(tcx), ret)]
@@ -340,76 +347,6 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> {
340347
}
341348
}
342349

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((Level::Warn | Level::Deny | Level::Forbid | Level::Expect | Level::ForceWarn, _))
383-
) {
384-
let store = unerased_lint_store(self.tcx.sess);
385-
// Lint attributes are always a metalist inside a
386-
// metalist (even with just one lint).
387-
let Some(meta_item_list) = attribute.meta_item_list() else { return };
388-
389-
for meta_list in meta_item_list {
390-
// Convert Path to String
391-
let Some(meta_item) = meta_list.meta_item() else { return };
392-
let ident: &str = &meta_item
393-
.path
394-
.segments
395-
.iter()
396-
.map(|segment| segment.ident.as_str())
397-
.collect::<Vec<&str>>()
398-
.join("::");
399-
let Ok(lints) = store.find_lints(
400-
// Lint attributes can only have literals
401-
ident,
402-
) else {
403-
return;
404-
};
405-
for lint in lints {
406-
self.dont_need_to_run.swap_remove(&lint);
407-
}
408-
}
409-
}
410-
}
411-
}
412-
413350
pub struct LintLevelsBuilder<'s, P> {
414351
sess: &'s Session,
415352
features: &'s Features,

Diff for: compiler/rustc_middle/src/query/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,7 @@ rustc_queries! {
484484
desc { "computing `#[expect]`ed lints in this crate" }
485485
}
486486

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

Diff for: tests/ui/attributes/unsafe/proc-unsafe-attributes.rs

+2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ pub fn e() {}
3030
//~| ERROR: expected identifier, found keyword `unsafe`
3131
//~| ERROR: malformed lint attribute input
3232
//~| ERROR: malformed lint attribute input
33+
//~| ERROR: malformed lint attribute input
34+
//~| ERROR: malformed lint attribute input
3335
pub fn f() {}
3436

3537
fn main() {}

Diff for: tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr

+17-1
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,22 @@ LL | #[unsafe(allow(unsafe(dead_code)))]
114114
|
115115
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
116116

117-
error: aborting due to 15 previous errors
117+
error[E0452]: malformed lint attribute input
118+
--> $DIR/proc-unsafe-attributes.rs:26:16
119+
|
120+
LL | #[unsafe(allow(unsafe(dead_code)))]
121+
| ^^^^^^^^^^^^^^^^^ bad attribute argument
122+
|
123+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
124+
125+
error[E0452]: malformed lint attribute input
126+
--> $DIR/proc-unsafe-attributes.rs:26:16
127+
|
128+
LL | #[unsafe(allow(unsafe(dead_code)))]
129+
| ^^^^^^^^^^^^^^^^^ bad attribute argument
130+
|
131+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
132+
133+
error: aborting due to 17 previous errors
118134

119135
For more information about this error, try `rustc --explain E0452`.

Diff for: tests/ui/deduplicate-diagnostics.duplicate.stderr

+9-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ LL | #[deny("literal")]
2626
|
2727
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
2828

29-
error: aborting due to 4 previous errors
29+
error[E0452]: malformed lint attribute input
30+
--> $DIR/deduplicate-diagnostics.rs:8:8
31+
|
32+
LL | #[deny("literal")]
33+
| ^^^^^^^^^ bad attribute argument
34+
|
35+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
36+
37+
error: aborting due to 5 previous errors
3038

3139
For more information about this error, try `rustc --explain E0452`.

Diff for: tests/ui/deduplicate-diagnostics.rs

+1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ struct S;
77

88
#[deny("literal")] //~ ERROR malformed lint attribute input
99
//[duplicate]~| ERROR malformed lint attribute input
10+
//[duplicate]~| ERROR malformed lint attribute input
1011
fn main() {}

Diff for: tests/ui/tool-attributes/tool_lints.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#[warn(foo::bar)]
22
//~^ ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
33
//~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
4+
//~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
45
fn main() {}

Diff for: tests/ui/tool-attributes/tool_lints.stderr

+10-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@ LL | #[warn(foo::bar)]
1515
= help: add `#![register_tool(foo)]` to the crate root
1616
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
1717

18-
error: aborting due to 2 previous errors
18+
error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar`
19+
--> $DIR/tool_lints.rs:1:8
20+
|
21+
LL | #[warn(foo::bar)]
22+
| ^^^
23+
|
24+
= help: add `#![register_tool(foo)]` to the crate root
25+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
26+
27+
error: aborting due to 3 previous errors
1928

2029
For more information about this error, try `rustc --explain E0710`.

Diff for: tests/ui/tool-attributes/unknown-lint-tool-name.rs

+1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@
44

55
#[allow(foo::bar)] //~ ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
66
//~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
7+
//~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
78
fn main() {}

Diff for: tests/ui/tool-attributes/unknown-lint-tool-name.stderr

+10-1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ LL | #![deny(foo::bar)]
4141
= help: add `#![register_tool(foo)]` to the crate root
4242
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
4343

44-
error: aborting due to 5 previous errors
44+
error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar`
45+
--> $DIR/unknown-lint-tool-name.rs:5:9
46+
|
47+
LL | #[allow(foo::bar)]
48+
| ^^^
49+
|
50+
= help: add `#![register_tool(foo)]` to the crate root
51+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
52+
53+
error: aborting due to 6 previous errors
4554

4655
For more information about this error, try `rustc --explain E0710`.

0 commit comments

Comments
 (0)