#![feature(if_let_guard)]
#![feature(let_else)]
#![feature(nll)]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
+#![feature(adt_const_params)]
+#![allow(incomplete_features)]
+#![allow(rustc::potential_query_instability)]
#[macro_use]
extern crate rustc_macros;
pub use emitter::ColorConfig;
+use rustc_lint_defs::LintExpectationId;
use Level::*;
use emitter::{is_case_difference, Emitter, EmitterWriter};
mod styled_buffer;
pub use snippet::Style;
-pub type PResult<'a, T> = Result<T, DiagnosticBuilder<'a>>;
+pub type PResult<'a, T> = Result<T, DiagnosticBuilder<'a, ErrorReported>>;
// `PResult` is used a lot. Make sure it doesn't unintentionally get bigger.
// (See also the comment on `DiagnosticBuilder`'s `diagnostic` field.)
deduplicated_warn_count: usize,
future_breakage_diagnostics: Vec<Diagnostic>,
+
+ /// Lint [`Diagnostic`]s can be expected as described in [RFC-2383]. An
+ /// expected diagnostic will have the level `Expect` which additionally
+ /// carries the [`LintExpectationId`] of the expectation that can be
+ /// marked as fulfilled. This is a collection of all [`LintExpectationId`]s
+ /// that have been marked as fulfilled this way.
+ ///
+ /// [RFC-2383]: https://rust-lang.github.io/rfcs/2383-lint-reasons.html
+ fulfilled_expectations: FxHashSet<LintExpectationId>,
}
/// A key denoting where from a diagnostic was stashed.
emitted_diagnostics: Default::default(),
stashed_diagnostics: Default::default(),
future_breakage_diagnostics: Vec::new(),
+ fulfilled_expectations: Default::default(),
}),
}
}
}
/// Steal a previously stashed diagnostic with the given `Span` and `StashKey` as the key.
- pub fn steal_diagnostic(&self, span: Span, key: StashKey) -> Option<DiagnosticBuilder<'_>> {
+ pub fn steal_diagnostic(&self, span: Span, key: StashKey) -> Option<DiagnosticBuilder<'_, ()>> {
self.inner
.borrow_mut()
.stashed_diagnostics
/// 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(&self, span: impl Into<MultiSpan>, msg: &str) -> DiagnosticBuilder<'_> {
+ pub fn struct_span_warn(
+ &self,
+ span: impl Into<MultiSpan>,
+ msg: &str,
+ ) -> DiagnosticBuilder<'_, ()> {
let mut result = self.struct_warn(msg);
result.set_span(span);
result
&self,
span: impl Into<MultiSpan>,
msg: &str,
- ) -> DiagnosticBuilder<'_> {
+ ) -> DiagnosticBuilder<'_, ()> {
let mut result = self.struct_allow(msg);
result.set_span(span);
result
span: impl Into<MultiSpan>,
msg: &str,
code: DiagnosticId,
- ) -> DiagnosticBuilder<'_> {
+ ) -> DiagnosticBuilder<'_, ()> {
let mut result = self.struct_span_warn(span, msg);
result.code(code);
result
/// 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(&self, msg: &str) -> DiagnosticBuilder<'_> {
+ pub fn struct_warn(&self, msg: &str) -> DiagnosticBuilder<'_, ()> {
DiagnosticBuilder::new(self, Level::Warning, msg)
}
/// Construct a builder at the `Allow` level with the `msg`.
- pub fn struct_allow(&self, msg: &str) -> DiagnosticBuilder<'_> {
+ pub fn struct_allow(&self, msg: &str) -> DiagnosticBuilder<'_, ()> {
DiagnosticBuilder::new(self, Level::Allow, msg)
}
+ /// Construct a builder at the `Expect` level with the `msg`.
+ pub fn struct_expect(&self, msg: &str, id: LintExpectationId) -> DiagnosticBuilder<'_, ()> {
+ DiagnosticBuilder::new(self, Level::Expect(id), msg)
+ }
+
/// Construct a builder at the `Error` level at the given `span` and with the `msg`.
- pub fn struct_span_err(&self, span: impl Into<MultiSpan>, msg: &str) -> DiagnosticBuilder<'_> {
+ pub fn struct_span_err(
+ &self,
+ span: impl Into<MultiSpan>,
+ msg: &str,
+ ) -> DiagnosticBuilder<'_, ErrorReported> {
let mut result = self.struct_err(msg);
result.set_span(span);
result
span: impl Into<MultiSpan>,
msg: &str,
code: DiagnosticId,
- ) -> DiagnosticBuilder<'_> {
+ ) -> DiagnosticBuilder<'_, ErrorReported> {
let mut result = self.struct_span_err(span, msg);
result.code(code);
result
/// Construct a builder at the `Error` level with the `msg`.
// FIXME: This method should be removed (every error should have an associated error code).
- pub fn struct_err(&self, msg: &str) -> DiagnosticBuilder<'_> {
- DiagnosticBuilder::new(self, Level::Error { lint: false }, msg)
+ pub fn struct_err(&self, msg: &str) -> DiagnosticBuilder<'_, ErrorReported> {
+ DiagnosticBuilder::new_guaranteeing_error::<{ Level::Error { lint: false } }>(self, msg)
}
/// This should only be used by `rustc_middle::lint::struct_lint_level`. Do not use it for hard errors.
#[doc(hidden)]
- pub fn struct_err_lint(&self, msg: &str) -> DiagnosticBuilder<'_> {
+ pub fn struct_err_lint(&self, msg: &str) -> DiagnosticBuilder<'_, ()> {
DiagnosticBuilder::new(self, Level::Error { lint: true }, msg)
}
/// Construct a builder at the `Error` level with the `msg` and the `code`.
- pub fn struct_err_with_code(&self, msg: &str, code: DiagnosticId) -> DiagnosticBuilder<'_> {
+ pub fn struct_err_with_code(
+ &self,
+ msg: &str,
+ code: DiagnosticId,
+ ) -> DiagnosticBuilder<'_, ErrorReported> {
let mut result = self.struct_err(msg);
result.code(code);
result
&self,
span: impl Into<MultiSpan>,
msg: &str,
- ) -> DiagnosticBuilder<'_> {
+ ) -> DiagnosticBuilder<'_, ErrorReported> {
let mut result = self.struct_fatal(msg);
result.set_span(span);
result
span: impl Into<MultiSpan>,
msg: &str,
code: DiagnosticId,
- ) -> DiagnosticBuilder<'_> {
+ ) -> DiagnosticBuilder<'_, ErrorReported> {
let mut result = self.struct_span_fatal(span, msg);
result.code(code);
result
}
/// Construct a builder at the `Error` level with the `msg`.
- pub fn struct_fatal(&self, msg: &str) -> DiagnosticBuilder<'_> {
- DiagnosticBuilder::new(self, Level::Fatal, msg)
+ pub fn struct_fatal(&self, msg: &str) -> DiagnosticBuilder<'_, ErrorReported> {
+ DiagnosticBuilder::new_guaranteeing_error::<{ Level::Fatal }>(self, msg)
}
/// Construct a builder at the `Help` level with the `msg`.
- pub fn struct_help(&self, msg: &str) -> DiagnosticBuilder<'_> {
+ pub fn struct_help(&self, msg: &str) -> DiagnosticBuilder<'_, ()> {
DiagnosticBuilder::new(self, Level::Help, msg)
}
/// Construct a builder at the `Note` level with the `msg`.
- pub fn struct_note_without_error(&self, msg: &str) -> DiagnosticBuilder<'_> {
+ pub fn struct_note_without_error(&self, msg: &str) -> DiagnosticBuilder<'_, ()> {
DiagnosticBuilder::new(self, Level::Note, msg)
}
self.emit_diag_at_span(Diagnostic::new(Note, msg), span);
}
- pub fn span_note_diag(&self, span: Span, msg: &str) -> DiagnosticBuilder<'_> {
+ pub fn span_note_diag(&self, span: Span, msg: &str) -> DiagnosticBuilder<'_, ()> {
let mut db = DiagnosticBuilder::new(self, Note, msg);
db.set_span(span);
db
pub fn emit_unused_externs(&self, lint_level: &str, unused_externs: &[&str]) {
self.inner.borrow_mut().emit_unused_externs(lint_level, unused_externs)
}
+
+ /// This methods steals all [`LintExpectationId`]s that are stored inside
+ /// [`HandlerInner`] and indicate that the linked expectation has been fulfilled.
+ pub fn steal_fulfilled_expectation_ids(&self) -> FxHashSet<LintExpectationId> {
+ std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations)
+ }
}
impl HandlerInner {
// FIXME(eddyb) this should ideally take `diagnostic` by value.
fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) {
- if diagnostic.cancelled() {
- return;
- }
-
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`
(*TRACK_DIAGNOSTICS)(diagnostic);
- if diagnostic.level == Allow {
+ if let Level::Expect(expectation_id) = diagnostic.level {
+ self.fulfilled_expectations.insert(expectation_id);
+ return;
+ } else if diagnostic.level == Allow {
return;
}
}
}
-#[derive(Copy, PartialEq, Clone, Hash, Debug, Encodable, Decodable)]
+#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug, Encodable, Decodable)]
pub enum Level {
Bug,
DelayedBug,
Warning,
Note,
Help,
- Cancelled,
FailureNote,
Allow,
+ Expect(LintExpectationId),
}
impl fmt::Display for Level {
spec.set_fg(Some(Color::Cyan)).set_intense(true);
}
FailureNote => {}
- Allow | Cancelled => unreachable!(),
+ Allow | Expect(_) => unreachable!(),
}
spec
}
Note => "note",
Help => "help",
FailureNote => "failure-note",
- Cancelled => panic!("Shouldn't call on cancelled error"),
Allow => panic!("Shouldn't call on allowed error"),
+ Expect(_) => panic!("Shouldn't call on expected error"),
}
}