diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2019-09-23 04:45:21 +0200 |
|---|---|---|
| committer | Mazdak Farrokhzad <twingoow@gmail.com> | 2019-09-23 17:50:06 +0200 |
| commit | ae8b3e8fc6e95a0f68fc49338f394d670e233883 (patch) | |
| tree | 1bf3feee7671515ce6921ea2c1bf041eb3e96e93 /src/librustc_errors | |
| parent | 66bf391c3aabfc77f5f7139fc9e6944f995d574e (diff) | |
| download | rust-ae8b3e8fc6e95a0f68fc49338f394d670e233883.tar.gz rust-ae8b3e8fc6e95a0f68fc49338f394d670e233883.zip | |
Introduce a diagnostic stashing API.
Diffstat (limited to 'src/librustc_errors')
| -rw-r--r-- | src/librustc_errors/diagnostic_builder.rs | 41 | ||||
| -rw-r--r-- | src/librustc_errors/lib.rs | 84 |
2 files changed, 100 insertions, 25 deletions
diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs index e85388bfea2..cc60bf89c7e 100644 --- a/src/librustc_errors/diagnostic_builder.rs +++ b/src/librustc_errors/diagnostic_builder.rs @@ -1,10 +1,6 @@ -use crate::Diagnostic; -use crate::DiagnosticId; -use crate::DiagnosticStyledString; -use crate::Applicability; +use crate::{Diagnostic, DiagnosticId, DiagnosticStyledString}; +use crate::{Applicability, Level, Handler, StashKey}; -use crate::Level; -use crate::Handler; use std::fmt::{self, Debug}; use std::ops::{Deref, DerefMut}; use std::thread::panicking; @@ -117,18 +113,30 @@ impl<'a> DiagnosticBuilder<'a> { } } - /// Buffers the diagnostic for later emission, unless handler - /// has disabled such buffering. - pub fn buffer(mut self, buffered_diagnostics: &mut Vec<Diagnostic>) { + /// Stashes diagnostic for possible later improvement in a different, + /// later stage of the compiler. The diagnostic can be accessed with + /// the provided `span` and `key` through `.steal_diagnostic` on `Handler`. + /// + /// As with `buffer`, this is unless the handler has disabled such buffering. + pub fn stash(self, span: Span, key: StashKey) { + if let Some((diag, handler)) = self.into_diagnostic() { + handler.stash_diagnostic(span, key, diag); + } + } + + /// Converts the builder to a `Diagnostic` for later emission, + /// unless handler has disabled such buffering. + pub fn into_diagnostic(mut self) -> Option<(Diagnostic, &'a Handler)> { if self.0.handler.flags.dont_buffer_diagnostics || self.0.handler.flags.treat_err_as_bug.is_some() { self.emit(); - return; + return None; } - // We need to use `ptr::read` because `DiagnosticBuilder` - // implements `Drop`. + let handler = self.0.handler; + + // We need to use `ptr::read` because `DiagnosticBuilder` implements `Drop`. let diagnostic; unsafe { diagnostic = std::ptr::read(&self.0.diagnostic); @@ -137,7 +145,14 @@ impl<'a> DiagnosticBuilder<'a> { // Logging here is useful to help track down where in logs an error was // actually emitted. debug!("buffer: diagnostic={:?}", diagnostic); - buffered_diagnostics.push(diagnostic); + + Some((diagnostic, handler)) + } + + /// Buffers the diagnostic for later emission, + /// unless handler has disabled such buffering. + pub fn buffer(self, buffered_diagnostics: &mut Vec<Diagnostic>) { + buffered_diagnostics.extend(self.into_diagnostic().map(|(diag, _)| diag)); } /// Convenience function for internal use, clients should use one of the diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 1fe5b71d7b1..40f63ae1eee 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -17,7 +17,7 @@ use emitter::{Emitter, EmitterWriter}; use registry::Registry; use rustc_data_structures::sync::{self, Lrc, Lock}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::stable_hasher::StableHasher; use std::borrow::Cow; @@ -326,6 +326,18 @@ struct HandlerInner { /// this handler. These hashes is used to avoid emitting the same error /// twice. emitted_diagnostics: FxHashSet<u128>, + + /// Stashed diagnostics emitted in one stage of the compiler that may be + /// stolen by other stages (e.g. to improve them and add more information). + /// The stashed diagnostics count towards the total error count. + /// When `.abort_if_errors()` is called, these are also emitted. + stashed_diagnostics: FxIndexMap<(Span, StashKey), Diagnostic>, +} + +/// A key denoting where from a diagnostic was stashed. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub enum StashKey { + ItemNoType, } fn default_track_diagnostic(_: &Diagnostic) {} @@ -354,7 +366,9 @@ pub struct HandlerFlags { impl Drop for HandlerInner { fn drop(&mut self) { - if self.err_count == 0 { + self.emit_stashed_diagnostics(); + + if !self.has_errors() { let bugs = std::mem::replace(&mut self.delayed_span_bugs, Vec::new()); let has_bugs = !bugs.is_empty(); for bug in bugs { @@ -419,6 +433,7 @@ impl Handler { taught_diagnostics: Default::default(), emitted_diagnostic_codes: Default::default(), emitted_diagnostics: Default::default(), + stashed_diagnostics: Default::default(), }), } } @@ -445,6 +460,31 @@ impl Handler { inner.emitted_diagnostics = Default::default(); inner.deduplicated_err_count = 0; inner.err_count = 0; + inner.stashed_diagnostics.clear(); + } + + /// Stash a given diagnostic with the given `Span` and `StashKey` as the key for later stealing. + /// If the diagnostic with this `(span, key)` already exists, this will result in an ICE. + pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) { + if let Some(old) = self.inner.borrow_mut().stashed_diagnostics.insert((span, key), diag) { + // We are removing a previously stashed diagnostic which should not happen. + // Create a builder and drop it on the floor to get an ICE. + drop(DiagnosticBuilder::new_diagnostic(self, old)); + } + } + + /// 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)) + } + + /// Emit all stashed diagnostics. + pub fn emit_stashed_diagnostics(&self) { + self.inner.borrow_mut().emit_stashed_diagnostics(); } pub fn struct_dummy(&self) -> DiagnosticBuilder<'_> { @@ -617,11 +657,11 @@ impl Handler { } pub fn err_count(&self) -> usize { - self.inner.borrow().err_count + self.inner.borrow().err_count() } pub fn has_errors(&self) -> bool { - self.err_count() > 0 + self.inner.borrow().has_errors() } pub fn print_error_count(&self, registry: &Registry) { @@ -629,11 +669,11 @@ impl Handler { } pub fn abort_if_errors(&self) { - self.inner.borrow().abort_if_errors() + self.inner.borrow_mut().abort_if_errors() } pub fn abort_if_errors_and_should_abort(&self) { - self.inner.borrow().abort_if_errors_and_should_abort() + self.inner.borrow_mut().abort_if_errors_and_should_abort() } pub fn must_teach(&self, code: &DiagnosticId) -> bool { @@ -671,6 +711,12 @@ impl HandlerInner { self.emitter.emit_diagnostic(&db); } + /// Emit all stashed diagnostics. + fn emit_stashed_diagnostics(&mut self) { + let diags = self.stashed_diagnostics.drain(..).map(|x| x.1).collect::<Vec<_>>(); + diags.iter().for_each(|diag| self.emit_diagnostic(diag)); + } + fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) { if diagnostic.cancelled() { return; @@ -713,10 +759,12 @@ impl HandlerInner { } fn treat_err_as_bug(&self) -> bool { - self.flags.treat_err_as_bug.map(|c| self.err_count >= c).unwrap_or(false) + self.flags.treat_err_as_bug.map(|c| self.err_count() >= c).unwrap_or(false) } fn print_error_count(&mut self, registry: &Registry) { + self.emit_stashed_diagnostics(); + let s = match self.deduplicated_err_count { 0 => return, 1 => "aborting due to previous error".to_string(), @@ -760,14 +808,26 @@ impl HandlerInner { } } - fn abort_if_errors_and_should_abort(&self) { - if self.err_count > 0 && !self.continue_after_error { + fn err_count(&self) -> usize { + self.err_count + self.stashed_diagnostics.len() + } + + fn has_errors(&self) -> bool { + self.err_count() > 0 + } + + fn abort_if_errors_and_should_abort(&mut self) { + self.emit_stashed_diagnostics(); + + if self.has_errors() && !self.continue_after_error { FatalError.raise(); } } - fn abort_if_errors(&self) { - if self.err_count > 0 { + fn abort_if_errors(&mut self) { + self.emit_stashed_diagnostics(); + + if self.has_errors() { FatalError.raise(); } } @@ -826,7 +886,7 @@ impl HandlerInner { fn panic_if_treat_err_as_bug(&self) { if self.treat_err_as_bug() { - let s = match (self.err_count, self.flags.treat_err_as_bug.unwrap_or(0)) { + let s = match (self.err_count(), self.flags.treat_err_as_bug.unwrap_or(0)) { (0, _) => return, (1, 1) => "aborting due to `-Z treat-err-as-bug=1`".to_string(), (1, _) => return, |
