From 44cb8fa482abaa567119ceab125498cfeef1171b Mon Sep 17 00:00:00 2001 From: xFrednet Date: Fri, 6 Aug 2021 23:36:33 +0200 Subject: [PATCH] Check lint expectations and emit lint if unfulfilled (RFC-2383) --- compiler/rustc_lint/src/expect.rs | 48 +++++++++++++++++++++++++++++++ compiler/rustc_lint/src/late.rs | 3 ++ compiler/rustc_lint/src/lib.rs | 1 + 3 files changed, 52 insertions(+) create mode 100644 compiler/rustc_lint/src/expect.rs diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs new file mode 100644 index 000000000000..a0c8b3501cd5 --- /dev/null +++ b/compiler/rustc_lint/src/expect.rs @@ -0,0 +1,48 @@ +use crate::builtin; +use rustc_data_structures::fx::FxHashMap; +use rustc_middle::lint::struct_lint_level; +use rustc_middle::{lint::LintExpectation, ty::TyCtxt}; +use rustc_session::lint::LintExpectationId; +use rustc_span::symbol::sym; +use rustc_span::MultiSpan; + +pub fn check_expectations(tcx: TyCtxt<'_>) { + if !tcx.sess.features_untracked().enabled(sym::lint_reasons) { + return; + } + + let fulfilled_expectations = tcx.sess.diagnostic().steal_fulfilled_expectation_ids(); + let lint_expectations: &FxHashMap = + &tcx.lint_levels(()).lint_expectations; + + for (id, expectation) in lint_expectations { + if fulfilled_expectations.contains(id) { + continue; + } + + emit_unfulfilled_expectation_lint(tcx, expectation); + } +} + +fn emit_unfulfilled_expectation_lint(tcx: TyCtxt<'_>, expectation: &LintExpectation) { + // FIXME The current implementation doesn't cover cases where the + // `unfulfilled_lint_expectations` is actually expected by another lint + // expectation. This can be added here as we have the lint level of this + // expectation, and we can also mark the lint expectation it would fulfill + // as such. This is currently not implemented to get some early feedback + // before diving deeper into this. + struct_lint_level( + tcx.sess, + builtin::UNFULFILLED_LINT_EXPECTATIONS, + expectation.emission_level, + expectation.emission_level_source, + Some(MultiSpan::from_span(expectation.emission_span)), + |diag| { + let mut diag = diag.build("this lint expectation is unfulfilled"); + if let Some(rationale) = expectation.reason { + diag.note(&rationale.as_str()); + } + diag.emit(); + }, + ); +} diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index 0ce760b64d9c..0ac636b878e0 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -503,4 +503,7 @@ 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)); } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 72e1671449f1..2dc6e9807227 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -52,6 +52,7 @@ mod context; mod early; mod enum_intrinsics_non_enums; pub mod hidden_unicode_codepoints; +mod expect; mod internal; mod late; mod levels;