diff options
Diffstat (limited to 'compiler/rustc_errors/src')
| -rw-r--r-- | compiler/rustc_errors/src/diagnostic.rs | 31 | ||||
| -rw-r--r-- | compiler/rustc_errors/src/diagnostic_builder.rs | 32 | ||||
| -rw-r--r-- | compiler/rustc_errors/src/lib.rs | 104 |
3 files changed, 138 insertions, 29 deletions
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 356f9dfdb3b..f75e2596f36 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -13,6 +13,7 @@ use rustc_span::{edition::Edition, Span, DUMMY_SP}; use std::borrow::Cow; use std::fmt; use std::hash::{Hash, Hasher}; +use std::path::{Path, PathBuf}; /// Error type for `Diagnostic`'s `suggestions` field, indicating that /// `.disable_suggestions()` was called on the `Diagnostic`. @@ -83,6 +84,7 @@ into_diagnostic_arg_using_display!( u64, i128, u128, + std::io::Error, std::num::NonZeroU32, hir::Target, Edition, @@ -124,6 +126,18 @@ impl IntoDiagnosticArg for String { } } +impl<'a> IntoDiagnosticArg for &'a Path { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(self.display().to_string())) + } +} + +impl IntoDiagnosticArg for PathBuf { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(self.display().to_string())) + } +} + impl IntoDiagnosticArg for usize { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { DiagnosticArgValue::Number(self) @@ -672,19 +686,12 @@ impl Diagnostic { suggestion: Vec<(Span, String)>, applicability: Applicability, ) -> &mut Self { - assert!(!suggestion.is_empty()); - self.push_suggestion(CodeSuggestion { - substitutions: vec![Substitution { - parts: suggestion - .into_iter() - .map(|(span, snippet)| SubstitutionPart { snippet, span }) - .collect(), - }], - msg: self.subdiagnostic_message_to_diagnostic_message(msg), - style: SuggestionStyle::CompletelyHidden, + self.multipart_suggestion_with_style( + msg, + suggestion, applicability, - }); - self + SuggestionStyle::CompletelyHidden, + ) } /// Prints out a message with a suggested edit of the code. diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 9e68ee282e6..61d767a1cc6 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -84,6 +84,13 @@ pub trait EmissionGuarantee: Sized { /// of `Self` without actually performing the emission. #[track_caller] fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self; + + /// Creates a new `DiagnosticBuilder` that will return this type of guarantee. + #[track_caller] + fn make_diagnostic_builder( + handler: &Handler, + msg: impl Into<DiagnosticMessage>, + ) -> DiagnosticBuilder<'_, Self>; } /// Private module for sealing the `IsError` helper trait. @@ -166,6 +173,15 @@ impl EmissionGuarantee for ErrorGuaranteed { } } } + + fn make_diagnostic_builder( + handler: &Handler, + msg: impl Into<DiagnosticMessage>, + ) -> DiagnosticBuilder<'_, Self> { + DiagnosticBuilder::new_guaranteeing_error::<_, { Level::Error { lint: false } }>( + handler, msg, + ) + } } impl<'a> DiagnosticBuilder<'a, ()> { @@ -208,6 +224,13 @@ impl EmissionGuarantee for () { DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {} } } + + fn make_diagnostic_builder( + handler: &Handler, + msg: impl Into<DiagnosticMessage>, + ) -> DiagnosticBuilder<'_, Self> { + DiagnosticBuilder::new(handler, Level::Warning(None), msg) + } } impl<'a> DiagnosticBuilder<'a, !> { @@ -247,6 +270,13 @@ impl EmissionGuarantee for ! { // Then fatally error, returning `!` crate::FatalError.raise() } + + fn make_diagnostic_builder( + handler: &Handler, + msg: impl Into<DiagnosticMessage>, + ) -> DiagnosticBuilder<'_, Self> { + DiagnosticBuilder::new_fatal(handler, msg) + } } /// In general, the `DiagnosticBuilder` uses deref to allow access to @@ -566,7 +596,7 @@ impl Drop for DiagnosticBuilderInner<'_> { ), )); handler.emit_diagnostic(&mut self.diagnostic); - panic!(); + panic!("error was constructed but not emitted"); } } // `.emit()` was previously called, or maybe we're during `.cancel()`. diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 6555b93ac0b..68abdd0bad1 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -6,6 +6,7 @@ #![feature(drain_filter)] #![feature(if_let_guard)] #![feature(adt_const_params)] +#![feature(let_chains)] #![feature(let_else)] #![feature(never_type)] #![feature(result_option_inspect)] @@ -459,6 +460,7 @@ struct HandlerInner { pub enum StashKey { ItemNoType, UnderscoreForArrayLengths, + EarlySyntaxWarning, } fn default_track_diagnostic(_: &Diagnostic) {} @@ -626,19 +628,13 @@ impl Handler { /// Stash a given diagnostic with the given `Span` and `StashKey` as the key for later stealing. pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) { let mut inner = self.inner.borrow_mut(); - // 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((span, key), diag); + inner.stash((span, 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() - .stashed_diagnostics - .remove(&(span, key)) - .map(|diag| DiagnosticBuilder::new_diagnostic(self, diag)) + let mut inner = self.inner.borrow_mut(); + inner.steal((span, key)).map(|diag| DiagnosticBuilder::new_diagnostic(self, diag)) } /// Emit all stashed diagnostics. @@ -646,6 +642,15 @@ impl Handler { self.inner.borrow_mut().emit_stashed_diagnostics() } + /// Construct a builder with the `msg` at the level appropriate for the specific `EmissionGuarantee`. + #[rustc_lint_diagnostics] + pub fn struct_diagnostic<G: EmissionGuarantee>( + &self, + msg: impl Into<DiagnosticMessage>, + ) -> DiagnosticBuilder<'_, G> { + G::make_diagnostic_builder(self, msg) + } + /// Construct a builder at the `Warning` level at the given `span` and with the `msg`. /// /// Attempting to `.emit()` the builder will only emit if either: @@ -1106,13 +1111,31 @@ impl HandlerInner { /// Emit all stashed diagnostics. fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> { + let has_errors = self.has_errors(); let diags = self.stashed_diagnostics.drain(..).map(|x| x.1).collect::<Vec<_>>(); let mut reported = None; for mut diag in diags { + // Decrement the count tracking the stash; emitting will increment it. if diag.is_error() { - reported = Some(ErrorGuaranteed(())); + if matches!(diag.level, Level::Error { lint: true }) { + self.lint_err_count -= 1; + } else { + self.err_count -= 1; + } + } else { + if diag.is_force_warn() { + self.warn_count -= 1; + } else { + // Unless they're forced, don't flush stashed warnings when + // there are errors, to avoid causing warning overload. The + // stash would've been stolen already if it were important. + if has_errors { + continue; + } + } } - self.emit_diagnostic(&mut diag); + let reported_this = self.emit_diagnostic(&mut diag); + reported = reported.or(reported_this); } reported } @@ -1226,9 +1249,13 @@ impl HandlerInner { } fn treat_err_as_bug(&self) -> bool { - self.flags - .treat_err_as_bug - .map_or(false, |c| self.err_count() + self.lint_err_count >= c.get()) + self.flags.treat_err_as_bug.map_or(false, |c| { + self.err_count() + + self.lint_err_count + + self.delayed_span_bugs.len() + + self.delayed_good_path_bugs.len() + >= c.get() + }) } fn print_error_count(&mut self, registry: &Registry) { @@ -1302,9 +1329,47 @@ impl HandlerInner { } } + 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 + self.stashed_diagnostics.len() + self.err_count } fn has_errors(&self) -> bool { @@ -1346,7 +1411,14 @@ impl HandlerInner { // This is technically `self.treat_err_as_bug()` but `delay_span_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.map_or(false, |c| self.err_count() + 1 >= c.get()) { + if self.flags.treat_err_as_bug.map_or(false, |c| { + self.err_count() + + self.lint_err_count + + self.delayed_span_bugs.len() + + self.delayed_good_path_bugs.len() + + 1 + >= c.get() + }) { // FIXME: don't abort here if report_delayed_bugs is off self.span_bug(sp, msg); } |
