Support lint expectations for --force-warn
lints (RFC 2383)
This commit is contained in:
parent
ec55c61305
commit
8527a3d369
19 changed files with 317 additions and 71 deletions
|
@ -658,6 +658,23 @@ impl Handler {
|
|||
result
|
||||
}
|
||||
|
||||
/// Construct a builder at the `Warning` level at the given `span` and with the `msg`.
|
||||
/// The `id` is used for lint emissions which should also fulfill a lint expectation.
|
||||
///
|
||||
/// Attempting to `.emit()` the builder will only emit if either:
|
||||
/// * `can_emit_warnings` is `true`
|
||||
/// * `is_force_warn` was set in `DiagnosticId::Lint`
|
||||
pub fn struct_span_warn_with_expectation(
|
||||
&self,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
id: LintExpectationId,
|
||||
) -> DiagnosticBuilder<'_, ()> {
|
||||
let mut result = self.struct_warn_with_expectation(msg, id);
|
||||
result.set_span(span);
|
||||
result
|
||||
}
|
||||
|
||||
/// Construct a builder at the `Allow` level at the given `span` and with the `msg`.
|
||||
pub fn struct_span_allow(
|
||||
&self,
|
||||
|
@ -688,7 +705,21 @@ impl Handler {
|
|||
/// * `can_emit_warnings` is `true`
|
||||
/// * `is_force_warn` was set in `DiagnosticId::Lint`
|
||||
pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
|
||||
DiagnosticBuilder::new(self, Level::Warning, msg)
|
||||
DiagnosticBuilder::new(self, Level::Warning(None), msg)
|
||||
}
|
||||
|
||||
/// Construct a builder at the `Warning` level with the `msg`. The `id` is used for
|
||||
/// lint emissions which should also fulfill a lint expectation.
|
||||
///
|
||||
/// Attempting to `.emit()` the builder will only emit if either:
|
||||
/// * `can_emit_warnings` is `true`
|
||||
/// * `is_force_warn` was set in `DiagnosticId::Lint`
|
||||
pub fn struct_warn_with_expectation(
|
||||
&self,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
id: LintExpectationId,
|
||||
) -> DiagnosticBuilder<'_, ()> {
|
||||
DiagnosticBuilder::new(self, Level::Warning(Some(id)), msg)
|
||||
}
|
||||
|
||||
/// Construct a builder at the `Allow` level with the `msg`.
|
||||
|
@ -842,7 +873,7 @@ impl Handler {
|
|||
}
|
||||
|
||||
pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
|
||||
self.emit_diag_at_span(Diagnostic::new(Warning, msg), span);
|
||||
self.emit_diag_at_span(Diagnostic::new(Warning(None), msg), span);
|
||||
}
|
||||
|
||||
pub fn span_warn_with_code(
|
||||
|
@ -851,7 +882,7 @@ impl Handler {
|
|||
msg: impl Into<DiagnosticMessage>,
|
||||
code: DiagnosticId,
|
||||
) {
|
||||
self.emit_diag_at_span(Diagnostic::new_with_code(Warning, Some(code), msg), span);
|
||||
self.emit_diag_at_span(Diagnostic::new_with_code(Warning(None), Some(code), msg), span);
|
||||
}
|
||||
|
||||
pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
|
||||
|
@ -905,7 +936,7 @@ impl Handler {
|
|||
}
|
||||
|
||||
pub fn warn(&self, msg: impl Into<DiagnosticMessage>) {
|
||||
let mut db = DiagnosticBuilder::new(self, Warning, msg);
|
||||
let mut db = DiagnosticBuilder::new(self, Warning(None), msg);
|
||||
db.emit();
|
||||
}
|
||||
|
||||
|
@ -1010,13 +1041,10 @@ impl Handler {
|
|||
for mut diag in diags.into_iter() {
|
||||
diag.update_unstable_expectation_id(unstable_to_stable);
|
||||
|
||||
let stable_id = diag
|
||||
.level
|
||||
.get_expectation_id()
|
||||
.expect("all diagnostics inside `unstable_expect_diagnostics` must have a `LintExpectationId`");
|
||||
inner.fulfilled_expectations.insert(stable_id);
|
||||
|
||||
(*TRACK_DIAGNOSTICS)(&diag);
|
||||
// Here the diagnostic is given back to `emit_diagnostic` where it was first
|
||||
// intercepted. Now it should be processed as usual, since the unstable expectation
|
||||
// id is now stable.
|
||||
inner.emit_diagnostic(&mut diag);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1066,6 +1094,15 @@ impl HandlerInner {
|
|||
|
||||
// FIXME(eddyb) this should ideally take `diagnostic` by value.
|
||||
fn emit_diagnostic(&mut self, diagnostic: &mut Diagnostic) -> Option<ErrorGuaranteed> {
|
||||
// The `LintExpectationId` can be stable or unstable depending on when it was created.
|
||||
// Diagnostics created before the definition of `HirId`s are unstable and can not yet
|
||||
// be stored. Instead, they are buffered until the `LintExpectationId` is replaced by
|
||||
// a stable one by the `LintLevelsBuilder`.
|
||||
if let Some(LintExpectationId::Unstable { .. }) = diagnostic.level.get_expectation_id() {
|
||||
self.unstable_expect_diagnostics.push(diagnostic.clone());
|
||||
return None;
|
||||
}
|
||||
|
||||
if diagnostic.level == Level::DelayedBug {
|
||||
// FIXME(eddyb) this should check for `has_errors` and stop pushing
|
||||
// once *any* errors were emitted (and truncate `delayed_span_bugs`
|
||||
|
@ -1082,7 +1119,12 @@ impl HandlerInner {
|
|||
self.future_breakage_diagnostics.push(diagnostic.clone());
|
||||
}
|
||||
|
||||
if diagnostic.level == Warning
|
||||
if let Some(expectation_id) = diagnostic.level.get_expectation_id() {
|
||||
self.suppressed_expected_diag = true;
|
||||
self.fulfilled_expectations.insert(expectation_id);
|
||||
}
|
||||
|
||||
if matches!(diagnostic.level, Warning(_))
|
||||
&& !self.flags.can_emit_warnings
|
||||
&& !diagnostic.is_force_warn()
|
||||
{
|
||||
|
@ -1092,22 +1134,9 @@ impl HandlerInner {
|
|||
return None;
|
||||
}
|
||||
|
||||
// The `LintExpectationId` can be stable or unstable depending on when it was created.
|
||||
// Diagnostics created before the definition of `HirId`s are unstable and can not yet
|
||||
// be stored. Instead, they are buffered until the `LintExpectationId` is replaced by
|
||||
// a stable one by the `LintLevelsBuilder`.
|
||||
if let Level::Expect(LintExpectationId::Unstable { .. }) = diagnostic.level {
|
||||
self.unstable_expect_diagnostics.push(diagnostic.clone());
|
||||
return None;
|
||||
}
|
||||
|
||||
(*TRACK_DIAGNOSTICS)(diagnostic);
|
||||
|
||||
if let Level::Expect(expectation_id) = diagnostic.level {
|
||||
self.suppressed_expected_diag = true;
|
||||
self.fulfilled_expectations.insert(expectation_id);
|
||||
return None;
|
||||
} else if diagnostic.level == Allow {
|
||||
if matches!(diagnostic.level, Level::Expect(_) | Level::Allow) {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
@ -1144,7 +1173,7 @@ impl HandlerInner {
|
|||
self.emitter.emit_diagnostic(&diagnostic);
|
||||
if diagnostic.is_error() {
|
||||
self.deduplicated_err_count += 1;
|
||||
} else if diagnostic.level == Warning {
|
||||
} else if let Warning(_) = diagnostic.level {
|
||||
self.deduplicated_warn_count += 1;
|
||||
}
|
||||
}
|
||||
|
@ -1197,7 +1226,7 @@ impl HandlerInner {
|
|||
match (errors.len(), warnings.len()) {
|
||||
(0, 0) => return,
|
||||
(0, _) => self.emitter.emit_diagnostic(&Diagnostic::new(
|
||||
Level::Warning,
|
||||
Level::Warning(None),
|
||||
DiagnosticMessage::Str(warnings),
|
||||
)),
|
||||
(_, 0) => {
|
||||
|
@ -1430,7 +1459,10 @@ pub enum Level {
|
|||
/// If this error comes from a lint, don't abort compilation even when abort_if_errors() is called.
|
||||
lint: bool,
|
||||
},
|
||||
Warning,
|
||||
/// This [`LintExpectationId`] is used for expected lint diagnostics, which should
|
||||
/// also emit a warning due to the `force-warn` flag. In all other cases this should
|
||||
/// be `None`.
|
||||
Warning(Option<LintExpectationId>),
|
||||
Note,
|
||||
/// A note that is only emitted once.
|
||||
OnceNote,
|
||||
|
@ -1453,7 +1485,7 @@ impl Level {
|
|||
Bug | DelayedBug | Fatal | Error { .. } => {
|
||||
spec.set_fg(Some(Color::Red)).set_intense(true);
|
||||
}
|
||||
Warning => {
|
||||
Warning(_) => {
|
||||
spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows));
|
||||
}
|
||||
Note | OnceNote => {
|
||||
|
@ -1472,7 +1504,7 @@ impl Level {
|
|||
match self {
|
||||
Bug | DelayedBug => "error: internal compiler error",
|
||||
Fatal | Error { .. } => "error",
|
||||
Warning => "warning",
|
||||
Warning(_) => "warning",
|
||||
Note | OnceNote => "note",
|
||||
Help => "help",
|
||||
FailureNote => "failure-note",
|
||||
|
@ -1487,7 +1519,7 @@ impl Level {
|
|||
|
||||
pub fn get_expectation_id(&self) -> Option<LintExpectationId> {
|
||||
match self {
|
||||
Level::Expect(id) => Some(*id),
|
||||
Level::Expect(id) | Level::Warning(Some(id)) => Some(*id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue