1
Fork 0

Auto merge of #95542 - xFrednet:rfc-2383-expect-query, r=wesleywiser

Support tool lints with the `#[expect]` attribute (RFC 2383)

This PR fixes the ICE https://github.com/rust-lang/rust/issues/94953 by making the assert for converted expectation IDs conditional.

Additionally, it moves the lint expectation check into a separate query to support rustdoc and other tools. On the way, I've also added some tests to ensure that the attribute works for Clippy and rustdoc lints.

The number of changes comes from the long test file. This may look like a monster PR, this may smell like a monster PR and this may be a monster PR, but it's a harmless monster. 🦕

---

Closes: https://github.com/rust-lang/rust/issues/94953

cc: https://github.com/rust-lang/rust/issues/85549

r? `@wesleywiser`

cc: `@rust-lang/rustdoc`
This commit is contained in:
bors 2022-05-09 00:02:55 +00:00
commit a57117982a
18 changed files with 663 additions and 19 deletions

View file

@ -1,10 +1,16 @@
use crate::builtin;
use rustc_hir::HirId;
use rustc_middle::ty::query::Providers;
use rustc_middle::{lint::LintExpectation, ty::TyCtxt};
use rustc_session::lint::LintExpectationId;
use rustc_span::symbol::sym;
use rustc_span::Symbol;
pub fn check_expectations(tcx: TyCtxt<'_>) {
pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers { check_expectations, ..*providers };
}
fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
if !tcx.sess.features_untracked().enabled(sym::lint_reasons) {
return;
}
@ -13,7 +19,9 @@ pub fn check_expectations(tcx: TyCtxt<'_>) {
let lint_expectations = &tcx.lint_levels(()).lint_expectations;
for (id, expectation) in lint_expectations {
if !fulfilled_expectations.contains(id) {
if !fulfilled_expectations.contains(id)
&& tool_filter.map_or(true, |filter| expectation.lint_tool == Some(filter))
{
// This check will always be true, since `lint_expectations` only
// holds stable ids
if let LintExpectationId::Stable { hir_id, .. } = id {

View file

@ -503,7 +503,4 @@ pub fn check_crate<'tcx, T: LateLintPass<'tcx>>(
});
},
);
// This check has to be run after all lints are done processing for this crate
tcx.sess.time("check_lint_expectations", || crate::expect::check_expectations(tcx));
}

View file

@ -371,7 +371,12 @@ impl<'s> LintLevelsBuilder<'s> {
};
self.lint_expectations.push((
expect_id,
LintExpectation::new(reason, sp, is_unfulfilled_lint_expectations),
LintExpectation::new(
reason,
sp,
is_unfulfilled_lint_expectations,
tool_name,
),
));
}
let src = LintLevelSource::Node(
@ -400,8 +405,10 @@ impl<'s> LintLevelsBuilder<'s> {
self.insert_spec(*id, (level, src));
}
if let Level::Expect(expect_id) = level {
self.lint_expectations
.push((expect_id, LintExpectation::new(reason, sp, false)));
self.lint_expectations.push((
expect_id,
LintExpectation::new(reason, sp, false, tool_name),
));
}
}
Err((Some(ids), ref new_lint_name)) => {
@ -444,8 +451,10 @@ impl<'s> LintLevelsBuilder<'s> {
self.insert_spec(*id, (level, src));
}
if let Level::Expect(expect_id) = level {
self.lint_expectations
.push((expect_id, LintExpectation::new(reason, sp, false)));
self.lint_expectations.push((
expect_id,
LintExpectation::new(reason, sp, false, tool_name),
));
}
}
Err((None, _)) => {
@ -550,8 +559,10 @@ impl<'s> LintLevelsBuilder<'s> {
}
}
if let Level::Expect(expect_id) = level {
self.lint_expectations
.push((expect_id, LintExpectation::new(reason, sp, false)));
self.lint_expectations.push((
expect_id,
LintExpectation::new(reason, sp, false, tool_name),
));
}
} else {
panic!("renamed lint does not exist: {}", new_name);

View file

@ -109,6 +109,7 @@ pub use rustc_session::lint::{LintArray, LintPass};
pub fn provide(providers: &mut Providers) {
levels::provide(providers);
expect::provide(providers);
*providers = Providers { lint_mod, ..*providers };
}