Introduce a diagnostic stashing API.
This commit is contained in:
parent
66bf391c3a
commit
ae8b3e8fc6
@ -321,6 +321,7 @@ impl Session {
|
||||
}
|
||||
pub fn compile_status(&self) -> Result<(), ErrorReported> {
|
||||
if self.has_errors() {
|
||||
self.diagnostic().emit_stashed_diagnostics();
|
||||
Err(ErrorReported)
|
||||
} else {
|
||||
Ok(())
|
||||
|
@ -296,7 +296,6 @@ pub fn run_compiler(
|
||||
);
|
||||
Ok(())
|
||||
})?;
|
||||
return sess.compile_status();
|
||||
} else {
|
||||
let mut krate = compiler.parse()?.take();
|
||||
pretty::visit_crate(sess, &mut krate, ppm);
|
||||
@ -307,8 +306,8 @@ pub fn run_compiler(
|
||||
ppm,
|
||||
compiler.output_file().as_ref().map(|p| &**p),
|
||||
);
|
||||
return sess.compile_status();
|
||||
}
|
||||
return sess.compile_status();
|
||||
}
|
||||
|
||||
if callbacks.after_parsing(compiler) == Compilation::Stop {
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user