Rollup merge of #118587 - nnethercote:cleanup-error-handlers-2, r=compiler-errors

Cleanup error handlers some more

A sequel to #118470.

r? ```@compiler-errors```
This commit is contained in:
Michael Goulet 2023-12-05 14:52:44 -05:00 committed by GitHub
commit e8133700a2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 251 additions and 466 deletions

View file

@ -1,5 +1,5 @@
use rustc_errors::{
AddToDiagnostic, DiagnosticBuilder, EmissionGuarantee, Handler, IntoDiagnostic, MultiSpan,
AddToDiagnostic, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic, MultiSpan,
SingleLabelManySpans,
};
use rustc_macros::{Diagnostic, Subdiagnostic};
@ -446,9 +446,9 @@ pub(crate) struct EnvNotDefinedWithUserMessage {
}
// Hand-written implementation to support custom user messages.
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for EnvNotDefinedWithUserMessage {
impl<'a> IntoDiagnostic<'a> for EnvNotDefinedWithUserMessage {
#[track_caller]
fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, G> {
fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
#[expect(
rustc::untranslatable_diagnostic,
reason = "cannot translate user-provided messages"
@ -801,8 +801,8 @@ pub(crate) struct AsmClobberNoReg {
pub(crate) clobbers: Vec<Span>,
}
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for AsmClobberNoReg {
fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, G> {
impl<'a> IntoDiagnostic<'a> for AsmClobberNoReg {
fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
let mut diag =
handler.struct_diagnostic(crate::fluent_generated::builtin_macros_asm_clobber_no_reg);
diag.set_span(self.spans.clone());

View file

@ -64,7 +64,7 @@ impl ConcurrencyLimiter {
// Make sure to drop the mutex guard first to prevent poisoning the mutex.
drop(state);
if let Some(err) = err {
handler.fatal(err).raise();
handler.fatal(err);
} else {
// The error was already emitted, but compilation continued. Raise a silent
// fatal error.

View file

@ -111,8 +111,8 @@ pub(crate) struct TargetFeatureDisableOrEnable<'a> {
pub(crate) struct MissingFeatures;
impl IntoDiagnostic<'_, ErrorGuaranteed> for TargetFeatureDisableOrEnable<'_> {
fn into_diagnostic(self, sess: &'_ Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
let mut diag = sess.struct_err(fluent::codegen_gcc_target_feature_disable_or_enable);
fn into_diagnostic(self, handler: &'_ Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
let mut diag = handler.struct_err(fluent::codegen_gcc_target_feature_disable_or_enable);
if let Some(span) = self.span {
diag.set_span(span);
};

View file

@ -5,7 +5,7 @@ use std::path::Path;
use crate::fluent_generated as fluent;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_errors::{
DiagnosticBuilder, EmissionGuarantee, ErrorGuaranteed, Handler, IntoDiagnostic,
DiagnosticBuilder, EmissionGuarantee, ErrorGuaranteed, FatalError, Handler, IntoDiagnostic,
};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::Span;
@ -101,13 +101,13 @@ pub(crate) struct DynamicLinkingWithLTO;
pub(crate) struct ParseTargetMachineConfig<'a>(pub LlvmError<'a>);
impl<EM: EmissionGuarantee> IntoDiagnostic<'_, EM> for ParseTargetMachineConfig<'_> {
fn into_diagnostic(self, sess: &'_ Handler) -> DiagnosticBuilder<'_, EM> {
let diag: DiagnosticBuilder<'_, EM> = self.0.into_diagnostic(sess);
impl IntoDiagnostic<'_, FatalError> for ParseTargetMachineConfig<'_> {
fn into_diagnostic(self, handler: &'_ Handler) -> DiagnosticBuilder<'_, FatalError> {
let diag: DiagnosticBuilder<'_, FatalError> = self.0.into_diagnostic(handler);
let (message, _) = diag.styled_message().first().expect("`LlvmError` with no message");
let message = sess.eagerly_translate_to_string(message.clone(), diag.args());
let message = handler.eagerly_translate_to_string(message.clone(), diag.args());
let mut diag = sess.struct_diagnostic(fluent::codegen_llvm_parse_target_machine_config);
let mut diag = handler.struct_diagnostic(fluent::codegen_llvm_parse_target_machine_config);
diag.set_arg("error", message);
diag
}
@ -124,8 +124,8 @@ pub(crate) struct TargetFeatureDisableOrEnable<'a> {
pub(crate) struct MissingFeatures;
impl IntoDiagnostic<'_, ErrorGuaranteed> for TargetFeatureDisableOrEnable<'_> {
fn into_diagnostic(self, sess: &'_ Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
let mut diag = sess.struct_err(fluent::codegen_llvm_target_feature_disable_or_enable);
fn into_diagnostic(self, handler: &'_ Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
let mut diag = handler.struct_err(fluent::codegen_llvm_target_feature_disable_or_enable);
if let Some(span) = self.span {
diag.set_span(span);
};
@ -183,8 +183,8 @@ pub enum LlvmError<'a> {
pub(crate) struct WithLlvmError<'a>(pub LlvmError<'a>, pub String);
impl<EM: EmissionGuarantee> IntoDiagnostic<'_, EM> for WithLlvmError<'_> {
fn into_diagnostic(self, sess: &'_ Handler) -> DiagnosticBuilder<'_, EM> {
impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for WithLlvmError<'_> {
fn into_diagnostic(self, handler: &'_ Handler) -> DiagnosticBuilder<'_, G> {
use LlvmError::*;
let msg_with_llvm_err = match &self.0 {
WriteOutput { .. } => fluent::codegen_llvm_write_output_with_llvm_err,
@ -201,7 +201,7 @@ impl<EM: EmissionGuarantee> IntoDiagnostic<'_, EM> for WithLlvmError<'_> {
PrepareThinLtoModule => fluent::codegen_llvm_prepare_thin_lto_module_with_llvm_err,
ParseBitcode => fluent::codegen_llvm_parse_bitcode_with_llvm_err,
};
let mut diag = self.0.into_diagnostic(sess);
let mut diag = self.0.into_diagnostic(handler);
diag.set_primary_message(msg_with_llvm_err);
diag.set_arg("llvm_err", self.1);
diag

View file

@ -239,7 +239,7 @@ impl Diagnostic {
}
#[track_caller]
pub fn new_with_code<M: Into<DiagnosticMessage>>(
pub(crate) fn new_with_code<M: Into<DiagnosticMessage>>(
level: Level,
code: Option<DiagnosticId>,
message: M,
@ -281,7 +281,7 @@ impl Diagnostic {
}
}
pub fn update_unstable_expectation_id(
pub(crate) fn update_unstable_expectation_id(
&mut self,
unstable_to_stable: &FxHashMap<LintExpectationId, LintExpectationId>,
) {
@ -307,14 +307,14 @@ impl Diagnostic {
}
/// Indicates whether this diagnostic should show up in cargo's future breakage report.
pub fn has_future_breakage(&self) -> bool {
pub(crate) fn has_future_breakage(&self) -> bool {
match self.code {
Some(DiagnosticId::Lint { has_future_breakage, .. }) => has_future_breakage,
_ => false,
}
}
pub fn is_force_warn(&self) -> bool {
pub(crate) fn is_force_warn(&self) -> bool {
match self.code {
Some(DiagnosticId::Lint { is_force_warn, .. }) => is_force_warn,
_ => false,
@ -391,29 +391,6 @@ impl Diagnostic {
self.note_expected_found_extra(expected_label, expected, found_label, found, &"", &"")
}
pub fn note_unsuccessful_coercion(
&mut self,
expected: DiagnosticStyledString,
found: DiagnosticStyledString,
) -> &mut Self {
let mut msg: Vec<_> =
vec![(Cow::from("required when trying to coerce from type `"), Style::NoStyle)];
msg.extend(expected.0.iter().map(|x| match *x {
StringPart::Normal(ref s) => (Cow::from(s.clone()), Style::NoStyle),
StringPart::Highlighted(ref s) => (Cow::from(s.clone()), Style::Highlight),
}));
msg.push((Cow::from("` to type '"), Style::NoStyle));
msg.extend(found.0.iter().map(|x| match *x {
StringPart::Normal(ref s) => (Cow::from(s.clone()), Style::NoStyle),
StringPart::Highlighted(ref s) => (Cow::from(s.clone()), Style::Highlight),
}));
msg.push((Cow::from("`"), Style::NoStyle));
// For now, just attach these as notes
self.highlighted_note(msg);
self
}
pub fn note_expected_found_extra(
&mut self,
expected_label: &dyn fmt::Display,
@ -475,7 +452,7 @@ impl Diagnostic {
self
}
pub fn highlighted_note<M: Into<SubdiagnosticMessage>>(
fn highlighted_note<M: Into<SubdiagnosticMessage>>(
&mut self,
msg: Vec<(M, Style)>,
) -> &mut Self {
@ -572,14 +549,6 @@ impl Diagnostic {
self
}
/// Clear any existing suggestions.
pub fn clear_suggestions(&mut self) -> &mut Self {
if let Ok(suggestions) = &mut self.suggestions {
suggestions.clear();
}
self
}
/// Helper for pushing to `self.suggestions`, if available (not disable).
fn push_suggestion(&mut self, suggestion: CodeSuggestion) {
if let Ok(suggestions) = &mut self.suggestions {
@ -992,7 +961,7 @@ impl Diagnostic {
/// Helper function that takes a `SubdiagnosticMessage` and returns a `DiagnosticMessage` by
/// combining it with the primary message of the diagnostic (if translatable, otherwise it just
/// passes the user's string along).
pub(crate) fn subdiagnostic_message_to_diagnostic_message(
fn subdiagnostic_message_to_diagnostic_message(
&self,
attr: impl Into<SubdiagnosticMessage>,
) -> DiagnosticMessage {

View file

@ -18,18 +18,18 @@ use std::thread::panicking;
/// Trait implemented by error types. This should not be implemented manually. Instead, use
/// `#[derive(Diagnostic)]` -- see [rustc_macros::Diagnostic].
#[rustc_diagnostic_item = "IntoDiagnostic"]
pub trait IntoDiagnostic<'a, T: EmissionGuarantee = ErrorGuaranteed> {
pub trait IntoDiagnostic<'a, G: EmissionGuarantee = ErrorGuaranteed> {
/// Write out as a diagnostic out of `Handler`.
#[must_use]
fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, T>;
fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, G>;
}
impl<'a, T, E> IntoDiagnostic<'a, E> for Spanned<T>
impl<'a, T, G> IntoDiagnostic<'a, G> for Spanned<T>
where
T: IntoDiagnostic<'a, E>,
E: EmissionGuarantee,
T: IntoDiagnostic<'a, G>,
G: EmissionGuarantee,
{
fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, E> {
fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, G> {
let mut diag = self.node.into_diagnostic(handler);
diag.set_span(self.span);
diag
@ -116,26 +116,6 @@ pub trait EmissionGuarantee: Sized {
}
impl<'a> DiagnosticBuilder<'a, ErrorGuaranteed> {
/// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`Handler`].
#[track_caller]
pub(crate) fn new_guaranteeing_error<M: Into<DiagnosticMessage>>(
handler: &'a Handler,
message: M,
) -> Self {
Self {
inner: DiagnosticBuilderInner {
state: DiagnosticBuilderState::Emittable(handler),
diagnostic: Box::new(Diagnostic::new_with_code(
Level::Error { lint: false },
None,
message,
)),
},
_marker: PhantomData,
}
}
/// Discard the guarantee `.emit()` would return, in favor of having the
/// type `DiagnosticBuilder<'a, ()>`. This may be necessary whenever there
/// is a common codepath handling both errors and warnings.
@ -189,35 +169,7 @@ impl EmissionGuarantee for ErrorGuaranteed {
handler: &Handler,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, Self> {
DiagnosticBuilder::new_guaranteeing_error(handler, msg)
}
}
impl<'a> DiagnosticBuilder<'a, ()> {
/// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`Handler`].
#[track_caller]
pub(crate) fn new<M: Into<DiagnosticMessage>>(
handler: &'a Handler,
level: Level,
message: M,
) -> Self {
let diagnostic = Diagnostic::new_with_code(level, None, message);
Self::new_diagnostic(handler, diagnostic)
}
/// Creates a new `DiagnosticBuilder` with an already constructed
/// diagnostic.
#[track_caller]
pub(crate) fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> Self {
debug!("Created new diagnostic");
Self {
inner: DiagnosticBuilderInner {
state: DiagnosticBuilderState::Emittable(handler),
diagnostic: Box::new(diagnostic),
},
_marker: PhantomData,
}
DiagnosticBuilder::new(handler, Level::Error { lint: false }, msg)
}
}
@ -249,28 +201,6 @@ impl EmissionGuarantee for () {
#[derive(Copy, Clone)]
pub struct Noted;
impl<'a> DiagnosticBuilder<'a, Noted> {
/// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`Handler`].
pub(crate) fn new_note(handler: &'a Handler, message: impl Into<DiagnosticMessage>) -> Self {
let diagnostic = Diagnostic::new_with_code(Level::Note, None, message);
Self::new_diagnostic_note(handler, diagnostic)
}
/// Creates a new `DiagnosticBuilder` with an already constructed
/// diagnostic.
pub(crate) fn new_diagnostic_note(handler: &'a Handler, diagnostic: Diagnostic) -> Self {
debug!("Created new diagnostic");
Self {
inner: DiagnosticBuilderInner {
state: DiagnosticBuilderState::Emittable(handler),
diagnostic: Box::new(diagnostic),
},
_marker: PhantomData,
}
}
}
impl EmissionGuarantee for Noted {
fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
match db.inner.state {
@ -290,7 +220,7 @@ impl EmissionGuarantee for Noted {
handler: &Handler,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, Self> {
DiagnosticBuilder::new_note(handler, msg)
DiagnosticBuilder::new(handler, Level::Note, msg)
}
}
@ -299,29 +229,6 @@ impl EmissionGuarantee for Noted {
#[derive(Copy, Clone)]
pub struct Bug;
impl<'a> DiagnosticBuilder<'a, Bug> {
/// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`Handler`].
#[track_caller]
pub(crate) fn new_bug(handler: &'a Handler, message: impl Into<DiagnosticMessage>) -> Self {
let diagnostic = Diagnostic::new_with_code(Level::Bug, None, message);
Self::new_diagnostic_bug(handler, diagnostic)
}
/// Creates a new `DiagnosticBuilder` with an already constructed
/// diagnostic.
pub(crate) fn new_diagnostic_bug(handler: &'a Handler, diagnostic: Diagnostic) -> Self {
debug!("Created new diagnostic bug");
Self {
inner: DiagnosticBuilderInner {
state: DiagnosticBuilderState::Emittable(handler),
diagnostic: Box::new(diagnostic),
},
_marker: PhantomData,
}
}
}
impl EmissionGuarantee for Bug {
fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
match db.inner.state {
@ -342,22 +249,7 @@ impl EmissionGuarantee for Bug {
handler: &Handler,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, Self> {
DiagnosticBuilder::new_bug(handler, msg)
}
}
impl<'a> DiagnosticBuilder<'a, !> {
/// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`Handler`].
#[track_caller]
pub(crate) fn new_fatal(handler: &'a Handler, message: impl Into<DiagnosticMessage>) -> Self {
Self {
inner: DiagnosticBuilderInner {
state: DiagnosticBuilderState::Emittable(handler),
diagnostic: Box::new(Diagnostic::new_with_code(Level::Fatal, None, message)),
},
_marker: PhantomData,
}
DiagnosticBuilder::new(handler, Level::Bug, msg)
}
}
@ -381,36 +273,7 @@ impl EmissionGuarantee for ! {
handler: &Handler,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, Self> {
DiagnosticBuilder::new_fatal(handler, msg)
}
}
impl<'a> DiagnosticBuilder<'a, rustc_span::fatal_error::FatalError> {
/// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`Handler`].
#[track_caller]
pub(crate) fn new_almost_fatal(
handler: &'a Handler,
message: impl Into<DiagnosticMessage>,
) -> Self {
let diagnostic = Diagnostic::new_with_code(Level::Fatal, None, message);
Self::new_diagnostic_almost_fatal(handler, diagnostic)
}
/// Creates a new `DiagnosticBuilder` with an already constructed
/// diagnostic.
pub(crate) fn new_diagnostic_almost_fatal(
handler: &'a Handler,
diagnostic: Diagnostic,
) -> Self {
debug!("Created new diagnostic");
Self {
inner: DiagnosticBuilderInner {
state: DiagnosticBuilderState::Emittable(handler),
diagnostic: Box::new(diagnostic),
},
_marker: PhantomData,
}
DiagnosticBuilder::new(handler, Level::Fatal, msg)
}
}
@ -434,7 +297,7 @@ impl EmissionGuarantee for rustc_span::fatal_error::FatalError {
handler: &Handler,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, Self> {
DiagnosticBuilder::new_almost_fatal(handler, msg)
DiagnosticBuilder::new(handler, Level::Fatal, msg)
}
}
@ -476,6 +339,32 @@ impl<G: EmissionGuarantee> DerefMut for DiagnosticBuilder<'_, G> {
}
impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
/// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`Handler`].
#[track_caller]
pub(crate) fn new<M: Into<DiagnosticMessage>>(
handler: &'a Handler,
level: Level,
message: M,
) -> Self {
let diagnostic = Diagnostic::new(level, message);
Self::new_diagnostic(handler, diagnostic)
}
/// Creates a new `DiagnosticBuilder` with an already constructed
/// diagnostic.
#[track_caller]
pub(crate) fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> Self {
debug!("Created new diagnostic");
Self {
inner: DiagnosticBuilderInner {
state: DiagnosticBuilderState::Emittable(handler),
diagnostic: Box::new(diagnostic),
},
_marker: PhantomData,
}
}
/// Emit the diagnostic.
#[track_caller]
pub fn emit(&mut self) -> G {
@ -626,12 +515,6 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
found_extra: &dyn fmt::Display,
) -> &mut Self);
forward!(pub fn note_unsuccessful_coercion(
&mut self,
expected: DiagnosticStyledString,
found: DiagnosticStyledString,
) -> &mut Self);
forward!(pub fn note(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self);
forward!(pub fn note_once(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self);
forward!(pub fn span_note(
@ -660,7 +543,6 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
forward!(pub fn set_is_lint(&mut self,) -> &mut Self);
forward!(pub fn disable_suggestions(&mut self,) -> &mut Self);
forward!(pub fn clear_suggestions(&mut self,) -> &mut Self);
forward!(pub fn multipart_suggestion(
&mut self,

View file

@ -554,7 +554,8 @@ impl Drop for HandlerInner {
// instead of "require some error happened". Sadly that isn't ideal, as
// lints can be `#[allow]`'d, potentially leading to this triggering.
// Also, "good path" should be replaced with a better naming.
if !self.has_any_message() && !self.suppressed_expected_diag && !std::thread::panicking() {
let has_any_message = self.err_count > 0 || self.lint_err_count > 0 || self.warn_count > 0;
if !has_any_message && !self.suppressed_expected_diag && !std::thread::panicking() {
let bugs = std::mem::replace(&mut self.good_path_delayed_bugs, Vec::new());
self.flush_delayed(
bugs,
@ -675,15 +676,46 @@ impl Handler {
/// Stash a given diagnostic with the given `Span` and [`StashKey`] as the key.
/// Retrieve a stashed diagnostic with `steal_diagnostic`.
pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) {
self.inner.borrow_mut().stash((span.with_parent(None), key), diag);
let mut inner = self.inner.borrow_mut();
let key = (span.with_parent(None), key);
if diag.is_error() {
if matches!(diag.level, Level::Error { lint: true }) {
inner.lint_err_count += 1;
} else {
inner.err_count += 1;
}
} else {
// Warnings are only automatically flushed if they're forced.
if diag.is_force_warn() {
inner.warn_count += 1;
}
}
// FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic
// if/when we have a more robust macro-friendly replacement for `(span, key)` as a key.
// See the PR for a discussion.
inner.stashed_diagnostics.insert(key, diag);
}
/// 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<'_, ()>> {
self.inner
.borrow_mut()
.steal((span.with_parent(None), key))
.map(|diag| DiagnosticBuilder::new_diagnostic(self, diag))
let mut inner = self.inner.borrow_mut();
let key = (span.with_parent(None), key);
let diag = inner.stashed_diagnostics.remove(&key)?;
if diag.is_error() {
if matches!(diag.level, Level::Error { lint: true }) {
inner.lint_err_count -= 1;
} else {
inner.err_count -= 1;
}
} else {
if diag.is_force_warn() {
inner.warn_count -= 1;
}
}
Some(DiagnosticBuilder::new_diagnostic(self, diag))
}
pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool {
@ -847,7 +879,7 @@ impl Handler {
&self,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
DiagnosticBuilder::new_guaranteeing_error(self, msg)
DiagnosticBuilder::new(self, Level::Error { lint: false }, msg)
}
/// This should only be used by `rustc_middle::lint::struct_lint_level`. Do not use it for hard errors.
@ -914,7 +946,7 @@ impl Handler {
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
DiagnosticBuilder::new_fatal(self, msg)
DiagnosticBuilder::new(self, Level::Fatal, msg)
}
/// Construct a builder at the `Help` level with the `msg`.
@ -996,19 +1028,42 @@ impl Handler {
}
/// For documentation on this, see `Session::span_delayed_bug`.
///
/// Note: this function used to be called `delay_span_bug`. It was renamed
/// to match similar functions like `span_bug`, `span_err`, etc.
#[track_caller]
pub fn span_delayed_bug(
&self,
span: impl Into<MultiSpan>,
sp: impl Into<MultiSpan>,
msg: impl Into<String>,
) -> ErrorGuaranteed {
self.inner.borrow_mut().span_delayed_bug(span, msg)
let mut inner = self.inner.borrow_mut();
// This is technically `self.treat_err_as_bug()` but `span_delayed_bug` is called before
// incrementing `err_count` by one, so we need to +1 the comparing.
// FIXME: Would be nice to increment err_count in a more coherent way.
if inner.flags.treat_err_as_bug.is_some_and(|c| {
inner.err_count + inner.lint_err_count + inner.delayed_bug_count() + 1 >= c.get()
}) {
// FIXME: don't abort here if report_delayed_bugs is off
inner.span_bug(sp, msg.into());
}
let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg.into());
diagnostic.set_span(sp.into());
inner.emit_diagnostic(&mut diagnostic).unwrap()
}
// FIXME(eddyb) note the comment inside `impl Drop for HandlerInner`, that's
// where the explanation of what "good path" is (also, it should be renamed).
pub fn good_path_delayed_bug(&self, msg: impl Into<DiagnosticMessage>) {
self.inner.borrow_mut().good_path_delayed_bug(msg)
let mut inner = self.inner.borrow_mut();
let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg);
if inner.flags.report_delayed_bugs {
inner.emit_diagnostic(&mut diagnostic);
}
let backtrace = std::backtrace::Backtrace::capture();
inner.good_path_delayed_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
}
#[track_caller]
@ -1034,34 +1089,34 @@ impl Handler {
db
}
// NOTE: intentionally doesn't raise an error so rustc_codegen_ssa only reports fatal errors in the main thread
#[rustc_lint_diagnostics]
pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> FatalError {
self.inner.borrow_mut().fatal(msg)
pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> ! {
DiagnosticBuilder::<FatalError>::new(self, Fatal, msg).emit().raise()
}
#[rustc_lint_diagnostics]
pub fn err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
self.inner.borrow_mut().err(msg)
DiagnosticBuilder::<ErrorGuaranteed>::new(self, Error { lint: false }, msg).emit()
}
#[rustc_lint_diagnostics]
pub fn warn(&self, msg: impl Into<DiagnosticMessage>) {
DiagnosticBuilder::new(self, Warning(None), msg).emit();
DiagnosticBuilder::<()>::new(self, Warning(None), msg).emit();
}
#[rustc_lint_diagnostics]
pub fn note(&self, msg: impl Into<DiagnosticMessage>) {
DiagnosticBuilder::new(self, Note, msg).emit();
DiagnosticBuilder::<()>::new(self, Note, msg).emit();
}
pub fn bug(&self, msg: impl Into<DiagnosticMessage>) -> ! {
self.inner.borrow_mut().bug(msg)
DiagnosticBuilder::<diagnostic_builder::Bug>::new(self, Bug, msg).emit();
panic::panic_any(ExplicitBug);
}
#[inline]
pub fn err_count(&self) -> usize {
self.inner.borrow().err_count()
self.inner.borrow().err_count
}
pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
@ -1072,26 +1127,103 @@ impl Handler {
}
pub fn has_errors_or_lint_errors(&self) -> Option<ErrorGuaranteed> {
self.inner.borrow().has_errors_or_lint_errors().then(|| {
let inner = self.inner.borrow();
let has_errors_or_lint_errors = inner.has_errors() || inner.lint_err_count > 0;
has_errors_or_lint_errors.then(|| {
#[allow(deprecated)]
ErrorGuaranteed::unchecked_claim_error_was_emitted()
})
}
pub fn has_errors_or_span_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
self.inner.borrow().has_errors_or_span_delayed_bugs().then(|| {
let inner = self.inner.borrow();
let has_errors_or_span_delayed_bugs =
inner.has_errors() || !inner.span_delayed_bugs.is_empty();
has_errors_or_span_delayed_bugs.then(|| {
#[allow(deprecated)]
ErrorGuaranteed::unchecked_claim_error_was_emitted()
})
}
pub fn is_compilation_going_to_fail(&self) -> Option<ErrorGuaranteed> {
self.inner.borrow().is_compilation_going_to_fail().then(|| {
let inner = self.inner.borrow();
let will_fail =
inner.has_errors() || inner.lint_err_count > 0 || !inner.span_delayed_bugs.is_empty();
will_fail.then(|| {
#[allow(deprecated)]
ErrorGuaranteed::unchecked_claim_error_was_emitted()
})
}
pub fn print_error_count(&self, registry: &Registry) {
self.inner.borrow_mut().print_error_count(registry)
let mut inner = self.inner.borrow_mut();
inner.emit_stashed_diagnostics();
let warnings = match inner.deduplicated_warn_count {
0 => Cow::from(""),
1 => Cow::from("1 warning emitted"),
count => Cow::from(format!("{count} warnings emitted")),
};
let errors = match inner.deduplicated_err_count {
0 => Cow::from(""),
1 => Cow::from("aborting due to 1 previous error"),
count => Cow::from(format!("aborting due to {count} previous errors")),
};
if inner.treat_err_as_bug() {
return;
}
match (errors.len(), warnings.len()) {
(0, 0) => return,
(0, _) => inner.emitter.emit_diagnostic(&Diagnostic::new(
Level::Warning(None),
DiagnosticMessage::Str(warnings),
)),
(_, 0) => {
inner.emit_diagnostic(&mut Diagnostic::new(Fatal, errors));
}
(_, _) => {
inner.emit_diagnostic(&mut Diagnostic::new(Fatal, format!("{errors}; {warnings}")));
}
}
let can_show_explain = inner.emitter.should_show_explain();
let are_there_diagnostics = !inner.emitted_diagnostic_codes.is_empty();
if can_show_explain && are_there_diagnostics {
let mut error_codes = inner
.emitted_diagnostic_codes
.iter()
.filter_map(|x| match &x {
DiagnosticId::Error(s) if registry.try_find_description(s).is_ok() => {
Some(s.clone())
}
_ => None,
})
.collect::<Vec<_>>();
if !error_codes.is_empty() {
error_codes.sort();
if error_codes.len() > 1 {
let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
inner.failure_note(format!(
"Some errors have detailed explanations: {}{}",
error_codes[..limit].join(", "),
if error_codes.len() > 9 { "..." } else { "." }
));
inner.failure_note(format!(
"For more information about an error, try \
`rustc --explain {}`.",
&error_codes[0]
));
} else {
inner.failure_note(format!(
"For more information about this error, try \
`rustc --explain {}`.",
&error_codes[0]
));
}
}
}
}
pub fn take_future_breakage_diagnostics(&self) -> Vec<Diagnostic> {
@ -1099,7 +1231,11 @@ impl Handler {
}
pub fn abort_if_errors(&self) {
self.inner.borrow_mut().abort_if_errors()
let mut inner = self.inner.borrow_mut();
inner.emit_stashed_diagnostics();
if inner.has_errors() {
FatalError.raise();
}
}
/// `true` if we haven't taught a diagnostic with this code already.
@ -1108,11 +1244,11 @@ impl Handler {
/// Used to suppress emitting the same error multiple times with extended explanation when
/// calling `-Zteach`.
pub fn must_teach(&self, code: &DiagnosticId) -> bool {
self.inner.borrow_mut().must_teach(code)
self.inner.borrow_mut().taught_diagnostics.insert(code.clone())
}
pub fn force_print_diagnostic(&self, db: Diagnostic) {
self.inner.borrow_mut().force_print_diagnostic(db)
self.inner.borrow_mut().emitter.emit_diagnostic(&db);
}
pub fn emit_diagnostic(&self, diagnostic: &mut Diagnostic) -> Option<ErrorGuaranteed> {
@ -1196,11 +1332,11 @@ impl Handler {
mut diag: Diagnostic,
sp: impl Into<MultiSpan>,
) -> Option<ErrorGuaranteed> {
self.inner.borrow_mut().emit_diagnostic(diag.set_span(sp))
self.emit_diagnostic(diag.set_span(sp))
}
pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
self.inner.borrow_mut().emit_artifact_notification(path, artifact_type)
self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type);
}
pub fn emit_future_breakage_report(&self, diags: Vec<Diagnostic>) {
@ -1219,7 +1355,7 @@ impl Handler {
inner.bump_err_count();
}
inner.emit_unused_externs(lint_level, unused_externs)
inner.emitter.emit_unused_externs(lint_level, unused_externs)
}
pub fn update_unstable_expectation_id(
@ -1270,15 +1406,11 @@ impl Handler {
}
}
// Note: we prefer implementing operations on `Handler`, rather than
// `HandlerInner`, whenever possible. This minimizes functions where
// `Handler::foo()` just borrows `inner` and forwards a call to
// `HanderInner::foo`.
impl HandlerInner {
fn must_teach(&mut self, code: &DiagnosticId) -> bool {
self.taught_diagnostics.insert(code.clone())
}
fn force_print_diagnostic(&mut self, db: Diagnostic) {
self.emitter.emit_diagnostic(&db);
}
/// Emit all stashed diagnostics.
fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
let has_errors = self.has_errors();
@ -1312,6 +1444,11 @@ impl HandlerInner {
// FIXME(eddyb) this should ideally take `diagnostic` by value.
fn emit_diagnostic(&mut self, diagnostic: &mut Diagnostic) -> Option<ErrorGuaranteed> {
if matches!(diagnostic.level, Level::Error { .. } | Level::Fatal) && self.treat_err_as_bug()
{
diagnostic.level = Level::Bug;
}
// 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
@ -1427,17 +1564,9 @@ impl HandlerInner {
guaranteed
}
fn emit_artifact_notification(&mut self, path: &Path, artifact_type: &str) {
self.emitter.emit_artifact_notification(path, artifact_type);
}
fn emit_unused_externs(&mut self, lint_level: rustc_lint_defs::Level, unused_externs: &[&str]) {
self.emitter.emit_unused_externs(lint_level, unused_externs);
}
fn treat_err_as_bug(&self) -> bool {
self.flags.treat_err_as_bug.is_some_and(|c| {
self.err_count() + self.lint_err_count + self.delayed_bug_count() >= c.get()
self.err_count + self.lint_err_count + self.delayed_bug_count() >= c.get()
})
}
@ -1445,141 +1574,8 @@ impl HandlerInner {
self.span_delayed_bugs.len() + self.good_path_delayed_bugs.len()
}
fn print_error_count(&mut self, registry: &Registry) {
self.emit_stashed_diagnostics();
let warnings = match self.deduplicated_warn_count {
0 => Cow::from(""),
1 => Cow::from("1 warning emitted"),
count => Cow::from(format!("{count} warnings emitted")),
};
let errors = match self.deduplicated_err_count {
0 => Cow::from(""),
1 => Cow::from("aborting due to 1 previous error"),
count => Cow::from(format!("aborting due to {count} previous errors")),
};
if self.treat_err_as_bug() {
return;
}
match (errors.len(), warnings.len()) {
(0, 0) => return,
(0, _) => self.emitter.emit_diagnostic(&Diagnostic::new(
Level::Warning(None),
DiagnosticMessage::Str(warnings),
)),
(_, 0) => {
let _ = self.fatal(errors);
}
(_, _) => {
let _ = self.fatal(format!("{errors}; {warnings}"));
}
}
let can_show_explain = self.emitter.should_show_explain();
let are_there_diagnostics = !self.emitted_diagnostic_codes.is_empty();
if can_show_explain && are_there_diagnostics {
let mut error_codes = self
.emitted_diagnostic_codes
.iter()
.filter_map(|x| match &x {
DiagnosticId::Error(s) if registry.try_find_description(s).is_ok() => {
Some(s.clone())
}
_ => None,
})
.collect::<Vec<_>>();
if !error_codes.is_empty() {
error_codes.sort();
if error_codes.len() > 1 {
let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
self.failure_note(format!(
"Some errors have detailed explanations: {}{}",
error_codes[..limit].join(", "),
if error_codes.len() > 9 { "..." } else { "." }
));
self.failure_note(format!(
"For more information about an error, try \
`rustc --explain {}`.",
&error_codes[0]
));
} else {
self.failure_note(format!(
"For more information about this error, try \
`rustc --explain {}`.",
&error_codes[0]
));
}
}
}
}
fn stash(&mut self, key: (Span, StashKey), diagnostic: Diagnostic) {
// Track the diagnostic for counts, but don't panic-if-treat-err-as-bug
// yet; that happens when we actually emit the diagnostic.
if diagnostic.is_error() {
if matches!(diagnostic.level, Level::Error { lint: true }) {
self.lint_err_count += 1;
} else {
self.err_count += 1;
}
} else {
// Warnings are only automatically flushed if they're forced.
if diagnostic.is_force_warn() {
self.warn_count += 1;
}
}
// FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic
// if/when we have a more robust macro-friendly replacement for `(span, key)` as a key.
// See the PR for a discussion.
self.stashed_diagnostics.insert(key, diagnostic);
}
fn steal(&mut self, key: (Span, StashKey)) -> Option<Diagnostic> {
let diagnostic = self.stashed_diagnostics.remove(&key)?;
if diagnostic.is_error() {
if matches!(diagnostic.level, Level::Error { lint: true }) {
self.lint_err_count -= 1;
} else {
self.err_count -= 1;
}
} else {
if diagnostic.is_force_warn() {
self.warn_count -= 1;
}
}
Some(diagnostic)
}
#[inline]
fn err_count(&self) -> usize {
self.err_count
}
fn has_errors(&self) -> bool {
self.err_count() > 0
}
fn has_errors_or_lint_errors(&self) -> bool {
self.has_errors() || self.lint_err_count > 0
}
fn has_errors_or_span_delayed_bugs(&self) -> bool {
self.has_errors() || !self.span_delayed_bugs.is_empty()
}
fn has_any_message(&self) -> bool {
self.err_count() > 0 || self.lint_err_count > 0 || self.warn_count > 0
}
fn is_compilation_going_to_fail(&self) -> bool {
self.has_errors() || self.lint_err_count > 0 || !self.span_delayed_bugs.is_empty()
}
fn abort_if_errors(&mut self) {
self.emit_stashed_diagnostics();
if self.has_errors() {
FatalError.raise();
}
self.err_count > 0
}
#[track_caller]
@ -1592,67 +1588,10 @@ impl HandlerInner {
self.emit_diagnostic(diag.set_span(sp));
}
/// For documentation on this, see `Session::span_delayed_bug`.
///
/// Note: this function used to be called `delay_span_bug`. It was renamed
/// to match similar functions like `span_bug`, `span_err`, etc.
#[track_caller]
fn span_delayed_bug(
&mut self,
sp: impl Into<MultiSpan>,
msg: impl Into<String>,
) -> ErrorGuaranteed {
// This is technically `self.treat_err_as_bug()` but `span_delayed_bug` is called before
// incrementing `err_count` by one, so we need to +1 the comparing.
// FIXME: Would be nice to increment err_count in a more coherent way.
if self.flags.treat_err_as_bug.is_some_and(|c| {
self.err_count() + self.lint_err_count + self.delayed_bug_count() + 1 >= c.get()
}) {
// FIXME: don't abort here if report_delayed_bugs is off
self.span_bug(sp, msg.into());
}
let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg.into());
diagnostic.set_span(sp.into());
self.emit_diagnostic(&mut diagnostic).unwrap()
}
// FIXME(eddyb) note the comment inside `impl Drop for HandlerInner`, that's
// where the explanation of what "good path" is (also, it should be renamed).
fn good_path_delayed_bug(&mut self, msg: impl Into<DiagnosticMessage>) {
let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg);
if self.flags.report_delayed_bugs {
self.emit_diagnostic(&mut diagnostic);
}
let backtrace = std::backtrace::Backtrace::capture();
self.good_path_delayed_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
}
fn failure_note(&mut self, msg: impl Into<DiagnosticMessage>) {
self.emit_diagnostic(&mut Diagnostic::new(FailureNote, msg));
}
fn fatal(&mut self, msg: impl Into<DiagnosticMessage>) -> FatalError {
self.emit(Fatal, msg);
FatalError
}
fn err(&mut self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
self.emit(Error { lint: false }, msg)
}
/// Emit an error; level should be `Error` or `Fatal`.
fn emit(&mut self, level: Level, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
if self.treat_err_as_bug() {
self.bug(msg);
}
self.emit_diagnostic(&mut Diagnostic::new(level, msg)).unwrap()
}
fn bug(&mut self, msg: impl Into<DiagnosticMessage>) -> ! {
self.emit_diagnostic(&mut Diagnostic::new(Bug, msg));
panic::panic_any(ExplicitBug);
}
fn flush_delayed(
&mut self,
bugs: impl IntoIterator<Item = DelayedDiagnostic>,
@ -1723,7 +1662,7 @@ impl HandlerInner {
fn panic_if_treat_err_as_bug(&self) {
if self.treat_err_as_bug() {
match (
self.err_count() + self.lint_err_count,
self.err_count + self.lint_err_count,
self.delayed_bug_count(),
self.flags.treat_err_as_bug.map(|c| c.get()).unwrap(),
) {

View file

@ -1145,11 +1145,6 @@ impl<'a> ExtCtxt<'a> {
pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) {
self.sess.diagnostic().span_err(sp, msg);
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) {
self.sess.diagnostic().span_warn(sp, msg);
}
pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<String>) -> ! {
self.sess.diagnostic().span_bug(sp, msg);
}

View file

@ -2,7 +2,7 @@ use std::borrow::Cow;
use rustc_errors::{
Applicability, DecorateLint, DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage,
EmissionGuarantee, Handler, IntoDiagnostic,
EmissionGuarantee, ErrorGuaranteed, Handler, IntoDiagnostic,
};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::mir::{AssertKind, UnsafetyViolationDetails};
@ -62,9 +62,9 @@ pub(crate) struct RequiresUnsafe {
// so we need to eagerly translate the label here, which isn't supported by the derive API
// We could also exhaustively list out the primary messages for all unsafe violations,
// but this would result in a lot of duplication.
impl<'sess, G: EmissionGuarantee> IntoDiagnostic<'sess, G> for RequiresUnsafe {
impl<'sess> IntoDiagnostic<'sess> for RequiresUnsafe {
#[track_caller]
fn into_diagnostic(self, handler: &'sess Handler) -> DiagnosticBuilder<'sess, G> {
fn into_diagnostic(self, handler: &'sess Handler) -> DiagnosticBuilder<'sess, ErrorGuaranteed> {
let mut diag = handler.struct_diagnostic(fluent::mir_transform_requires_unsafe);
diag.code(rustc_errors::DiagnosticId::Error("E0133".to_string()));
diag.set_span(self.span);

View file

@ -2,7 +2,7 @@ use std::borrow::Cow;
use rustc_ast::token::Token;
use rustc_ast::{Path, Visibility};
use rustc_errors::{AddToDiagnostic, Applicability, EmissionGuarantee, IntoDiagnostic};
use rustc_errors::{AddToDiagnostic, Applicability, ErrorGuaranteed, IntoDiagnostic};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::edition::{Edition, LATEST_STABLE_EDITION};
@ -1038,12 +1038,12 @@ pub(crate) struct ExpectedIdentifier {
pub help_cannot_start_number: Option<HelpIdentifierStartsWithNumber>,
}
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier {
impl<'a> IntoDiagnostic<'a> for ExpectedIdentifier {
#[track_caller]
fn into_diagnostic(
self,
handler: &'a rustc_errors::Handler,
) -> rustc_errors::DiagnosticBuilder<'a, G> {
) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> {
let token_descr = TokenDescription::from_token(&self.token);
let mut diag = handler.struct_diagnostic(match token_descr {
@ -1095,12 +1095,12 @@ pub(crate) struct ExpectedSemi {
pub sugg: ExpectedSemiSugg,
}
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedSemi {
impl<'a> IntoDiagnostic<'a> for ExpectedSemi {
#[track_caller]
fn into_diagnostic(
self,
handler: &'a rustc_errors::Handler,
) -> rustc_errors::DiagnosticBuilder<'a, G> {
) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> {
let token_descr = TokenDescription::from_token(&self.token);
let mut diag = handler.struct_diagnostic(match token_descr {

View file

@ -3,7 +3,7 @@ use std::num::NonZeroU32;
use crate::parse::ParseSess;
use rustc_ast::token;
use rustc_ast::util::literal::LitError;
use rustc_errors::{error_code, DiagnosticMessage, EmissionGuarantee, IntoDiagnostic, MultiSpan};
use rustc_errors::{error_code, DiagnosticMessage, ErrorGuaranteed, IntoDiagnostic, MultiSpan};
use rustc_macros::Diagnostic;
use rustc_span::{BytePos, Span, Symbol};
use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple};
@ -13,12 +13,12 @@ pub struct FeatureGateError {
pub explain: DiagnosticMessage,
}
impl<'a, T: EmissionGuarantee> IntoDiagnostic<'a, T> for FeatureGateError {
impl<'a> IntoDiagnostic<'a> for FeatureGateError {
#[track_caller]
fn into_diagnostic(
self,
handler: &'a rustc_errors::Handler,
) -> rustc_errors::DiagnosticBuilder<'a, T> {
) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> {
let mut diag = handler.struct_diagnostic(self.explain);
diag.set_span(self.span);
diag.code(error_code!(E0658));

View file

@ -461,7 +461,7 @@ impl Session {
}
#[rustc_lint_diagnostics]
pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> ! {
self.diagnostic().fatal(msg).raise()
self.diagnostic().fatal(msg)
}
#[rustc_lint_diagnostics]
#[track_caller]