Auto merge of #64272 - Mark-Simulacrum:parallel-handler, r=estebank

Refactor librustc_errors::Handler API

This should be reviewed by-commit.

The last commit moves all fields into an inner struct behind a single lock; this is done to prevent possible deadlocks in a multi-threaded compiler, as well as inconsistent state observation.
This commit is contained in:
bors 2019-09-23 06:38:23 +00:00
commit 66bf391c3a
28 changed files with 328 additions and 268 deletions

View File

@ -1,4 +1,4 @@
use errors::{Diagnostic, DiagnosticBuilder};
use errors::Diagnostic;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
@ -819,7 +819,7 @@ impl DepGraph {
let handle = tcx.sess.diagnostic();
for diagnostic in diagnostics {
DiagnosticBuilder::new_diagnostic(handle, diagnostic).emit();
handle.emit_diagnostic(&diagnostic);
}
// Mark the node as green now that diagnostics are emitted

View File

@ -1119,7 +1119,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
Some((expected, found)) => Some((expected, found)),
None => {
// Derived error. Cancel the emitter.
self.tcx.sess.diagnostic().cancel(diag);
diag.cancel();
return;
}
};

View File

@ -1855,7 +1855,7 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
struct NullEmitter;
impl errors::emitter::Emitter for NullEmitter {
fn emit_diagnostic(&mut self, _: &errors::DiagnosticBuilder<'_>) {}
fn emit_diagnostic(&mut self, _: &errors::Diagnostic) {}
}
// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`.

View File

@ -87,7 +87,7 @@ fn test_can_print_warnings() {
let registry = errors::registry::Registry::new(&[]);
let (sessopts, _) = build_session_options_and_crate_config(&matches);
let sess = build_session(sessopts, None, registry);
assert!(!sess.diagnostic().flags.can_emit_warnings);
assert!(!sess.diagnostic().can_emit_warnings());
});
syntax::with_default_globals(|| {
@ -97,7 +97,7 @@ fn test_can_print_warnings() {
let registry = errors::registry::Registry::new(&[]);
let (sessopts, _) = build_session_options_and_crate_config(&matches);
let sess = build_session(sessopts, None, registry);
assert!(sess.diagnostic().flags.can_emit_warnings);
assert!(sess.diagnostic().can_emit_warnings());
});
syntax::with_default_globals(|| {
@ -105,7 +105,7 @@ fn test_can_print_warnings() {
let registry = errors::registry::Registry::new(&[]);
let (sessopts, _) = build_session_options_and_crate_config(&matches);
let sess = build_session(sessopts, None, registry);
assert!(sess.diagnostic().flags.can_emit_warnings);
assert!(sess.diagnostic().can_emit_warnings());
});
}

View File

@ -365,12 +365,6 @@ impl Session {
pub fn span_note_without_error<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.diagnostic().span_note_without_error(sp, msg)
}
pub fn span_unimpl<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
self.diagnostic().span_unimpl(sp, msg)
}
pub fn unimpl(&self, msg: &str) -> ! {
self.diagnostic().unimpl(msg)
}
pub fn buffer_lint<S: Into<MultiSpan>>(
&self,
@ -1040,6 +1034,7 @@ fn default_emitter(
source_map: &Lrc<source_map::SourceMap>,
emitter_dest: Option<Box<dyn Write + Send>>,
) -> Box<dyn Emitter + sync::Send> {
let external_macro_backtrace = sopts.debugging_opts.external_macro_backtrace;
match (sopts.error_format, emitter_dest) {
(config::ErrorOutputType::HumanReadable(kind), dst) => {
let (short, color_config) = kind.unzip();
@ -1048,6 +1043,7 @@ fn default_emitter(
let emitter = AnnotateSnippetEmitterWriter::new(
Some(source_map.clone()),
short,
external_macro_backtrace,
);
Box::new(emitter.ui_testing(sopts.debugging_opts.ui_testing))
} else {
@ -1058,6 +1054,7 @@ fn default_emitter(
short,
sopts.debugging_opts.teach,
sopts.debugging_opts.terminal_width,
external_macro_backtrace,
),
Some(dst) => EmitterWriter::new(
dst,
@ -1066,6 +1063,7 @@ fn default_emitter(
false, // no teach messages when writing to a buffer
false, // no colors when writing to a buffer
None, // no terminal width
external_macro_backtrace,
),
};
Box::new(emitter.ui_testing(sopts.debugging_opts.ui_testing))
@ -1077,6 +1075,7 @@ fn default_emitter(
source_map.clone(),
pretty,
json_rendered,
external_macro_backtrace,
).ui_testing(sopts.debugging_opts.ui_testing),
),
(config::ErrorOutputType::Json { pretty, json_rendered }, Some(dst)) => Box::new(
@ -1086,6 +1085,7 @@ fn default_emitter(
source_map.clone(),
pretty,
json_rendered,
external_macro_backtrace,
).ui_testing(sopts.debugging_opts.ui_testing),
),
}
@ -1382,13 +1382,13 @@ pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! {
let emitter: Box<dyn Emitter + sync::Send> = match output {
config::ErrorOutputType::HumanReadable(kind) => {
let (short, color_config) = kind.unzip();
Box::new(EmitterWriter::stderr(color_config, None, short, false, None))
Box::new(EmitterWriter::stderr(color_config, None, short, false, None, false))
}
config::ErrorOutputType::Json { pretty, json_rendered } =>
Box::new(JsonEmitter::basic(pretty, json_rendered)),
Box::new(JsonEmitter::basic(pretty, json_rendered, false)),
};
let handler = errors::Handler::with_emitter(true, None, emitter);
handler.emit(&MultiSpan::new(), msg, errors::Level::Fatal);
handler.struct_fatal(msg).emit();
errors::FatalError.raise();
}
@ -1396,13 +1396,13 @@ pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
let emitter: Box<dyn Emitter + sync::Send> = match output {
config::ErrorOutputType::HumanReadable(kind) => {
let (short, color_config) = kind.unzip();
Box::new(EmitterWriter::stderr(color_config, None, short, false, None))
Box::new(EmitterWriter::stderr(color_config, None, short, false, None, false))
}
config::ErrorOutputType::Json { pretty, json_rendered } =>
Box::new(JsonEmitter::basic(pretty, json_rendered)),
Box::new(JsonEmitter::basic(pretty, json_rendered, false)),
};
let handler = errors::Handler::with_emitter(true, None, emitter);
handler.emit(&MultiSpan::new(), msg, errors::Level::Warning);
handler.struct_warn(msg).emit();
}
pub type CompileResult = Result<(), ErrorReported>;

View File

@ -330,14 +330,13 @@ impl<'tcx> TyCtxt<'tcx> {
let mut i = 0;
while let Some(query) = current_query {
let mut db = DiagnosticBuilder::new(icx.tcx.sess.diagnostic(),
Level::FailureNote,
let mut diag = Diagnostic::new(Level::FailureNote,
&format!("#{} [{}] {}",
i,
query.info.query.name(),
query.info.query.describe(icx.tcx)));
db.set_span(icx.tcx.sess.source_map().def_span(query.info.span));
icx.tcx.sess.diagnostic().force_print_db(db);
diag.span = icx.tcx.sess.source_map().def_span(query.info.span).into();
icx.tcx.sess.diagnostic().force_print_diagnostic(diag);
current_query = query.parent.clone();
i += 1;

View File

@ -22,12 +22,11 @@ use rustc::util::common::{time_depth, set_time_depth, print_time_passes_entry};
use rustc::util::profiling::SelfProfiler;
use rustc_fs_util::link_or_copy;
use rustc_data_structures::svh::Svh;
use rustc_errors::{Handler, Level, DiagnosticBuilder, FatalError, DiagnosticId};
use rustc_errors::{Handler, Level, FatalError, DiagnosticId};
use rustc_errors::emitter::{Emitter};
use rustc_target::spec::MergeFunctions;
use syntax::attr;
use syntax::ext::hygiene::ExpnId;
use syntax_pos::MultiSpan;
use syntax_pos::symbol::{Symbol, sym};
use jobserver::{Client, Acquired};
@ -1725,7 +1724,7 @@ impl SharedEmitter {
}
impl Emitter for SharedEmitter {
fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>) {
fn emit_diagnostic(&mut self, db: &rustc_errors::Diagnostic) {
drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {
msg: db.message(),
code: db.code.clone(),
@ -1760,19 +1759,12 @@ impl SharedEmitterMain {
match message {
Ok(SharedEmitterMessage::Diagnostic(diag)) => {
let handler = sess.diagnostic();
match diag.code {
Some(ref code) => {
handler.emit_with_code(&MultiSpan::new(),
&diag.msg,
code.clone(),
diag.lvl);
}
None => {
handler.emit(&MultiSpan::new(),
&diag.msg,
diag.lvl);
}
let mut d = rustc_errors::Diagnostic::new(diag.lvl, &diag.msg);
if let Some(code) = diag.code {
d.code(code);
}
handler.emit_diagnostic(&d);
handler.abort_if_errors_and_should_abort();
}
Ok(SharedEmitterMessage::InlineAsmError(cookie, msg)) => {
sess.span_err(ExpnId::from_u32(cookie).expn_data().call_site, &msg)

View File

@ -66,7 +66,7 @@ use syntax::source_map::FileLoader;
use syntax::feature_gate::{GatedCfg, UnstableFeatures};
use syntax::parse::{self, PResult};
use syntax::symbol::sym;
use syntax_pos::{DUMMY_SP, MultiSpan, FileName};
use syntax_pos::{DUMMY_SP, FileName};
pub mod pretty;
mod args;
@ -1196,15 +1196,16 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
false,
false,
None,
false,
));
let handler = errors::Handler::with_emitter(true, None, emitter);
// a .span_bug or .bug call has already printed what
// it wants to print.
if !info.payload().is::<errors::ExplicitBug>() {
handler.emit(&MultiSpan::new(),
"unexpected panic",
errors::Level::Bug);
let d = errors::Diagnostic::new(errors::Level::Bug, "unexpected panic");
handler.emit_diagnostic(&d);
handler.abort_if_errors_and_should_abort();
}
let mut xs: Vec<Cow<'static, str>> = vec![
@ -1224,9 +1225,7 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
}
for note in &xs {
handler.emit(&MultiSpan::new(),
note,
errors::Level::Note);
handler.note_without_error(&note);
}
// If backtraces are enabled, also print the query stack

View File

@ -7,7 +7,7 @@
use syntax_pos::{SourceFile, MultiSpan, Loc};
use crate::{
Level, CodeSuggestion, DiagnosticBuilder, Emitter,
Level, CodeSuggestion, Diagnostic, Emitter,
SourceMapperDyn, SubDiagnostic, DiagnosticId
};
use crate::emitter::FileWithAnnotatedLines;
@ -25,11 +25,13 @@ pub struct AnnotateSnippetEmitterWriter {
short_message: bool,
/// If true, will normalize line numbers with `LL` to prevent noise in UI test diffs.
ui_testing: bool,
external_macro_backtrace: bool,
}
impl Emitter for AnnotateSnippetEmitterWriter {
/// The entry point for the diagnostics generation
fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>) {
fn emit_diagnostic(&mut self, db: &Diagnostic) {
let mut children = db.children.clone();
let (mut primary_span, suggestions) = self.primary_span_formatted(&db);
@ -37,7 +39,7 @@ impl Emitter for AnnotateSnippetEmitterWriter {
&mut primary_span,
&mut children,
&db.level,
db.handler().flags.external_macro_backtrace);
self.external_macro_backtrace);
self.emit_messages_default(&db.level,
db.message(),
@ -163,12 +165,14 @@ impl<'a> DiagnosticConverter<'a> {
impl AnnotateSnippetEmitterWriter {
pub fn new(
source_map: Option<Lrc<SourceMapperDyn>>,
short_message: bool
short_message: bool,
external_macro_backtrace: bool,
) -> Self {
Self {
source_map,
short_message,
ui_testing: false,
external_macro_backtrace,
}
}

View File

@ -99,17 +99,9 @@ impl<'a> DerefMut for DiagnosticBuilder<'a> {
}
impl<'a> DiagnosticBuilder<'a> {
pub fn handler(&self) -> &'a Handler{
self.0.handler
}
/// Emit the diagnostic.
pub fn emit(&mut self) {
if self.cancelled() {
return;
}
self.0.handler.emit_db(&self);
self.0.handler.emit_diagnostic(&self);
self.cancel();
}
@ -354,7 +346,7 @@ impl<'a> DiagnosticBuilder<'a> {
/// Convenience function for internal use, clients should use one of the
/// struct_* methods on Handler.
pub fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> {
crate fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> {
DiagnosticBuilder::new_with_code(handler, level, None, message)
}
@ -371,7 +363,8 @@ impl<'a> DiagnosticBuilder<'a> {
/// Creates a new `DiagnosticBuilder` with an already constructed
/// diagnostic.
pub fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> DiagnosticBuilder<'a> {
crate fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic)
-> DiagnosticBuilder<'a> {
DiagnosticBuilder(Box::new(DiagnosticBuilderInner {
handler,
diagnostic,

View File

@ -12,7 +12,7 @@ use Destination::*;
use syntax_pos::{SourceFile, Span, MultiSpan};
use crate::{
Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic,
Level, CodeSuggestion, Diagnostic, SubDiagnostic,
SuggestionStyle, SourceMapperDyn, DiagnosticId,
};
use crate::Level::Error;
@ -52,10 +52,12 @@ impl HumanReadableErrorType {
source_map: Option<Lrc<SourceMapperDyn>>,
teach: bool,
terminal_width: Option<usize>,
external_macro_backtrace: bool,
) -> EmitterWriter {
let (short, color_config) = self.unzip();
let color = color_config.suggests_using_colors();
EmitterWriter::new(dst, source_map, short, teach, color, terminal_width)
EmitterWriter::new(dst, source_map, short, teach, color, terminal_width,
external_macro_backtrace)
}
}
@ -180,7 +182,7 @@ const ANONYMIZED_LINE_NUM: &str = "LL";
/// Emitter trait for emitting errors.
pub trait Emitter {
/// Emit a structured diagnostic.
fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>);
fn emit_diagnostic(&mut self, db: &Diagnostic);
/// Emit a notification that an artifact has been output.
/// This is currently only supported for the JSON format,
@ -204,7 +206,7 @@ pub trait Emitter {
/// we return the original `primary_span` and the original suggestions.
fn primary_span_formatted<'a>(
&mut self,
db: &'a DiagnosticBuilder<'_>
db: &'a Diagnostic
) -> (MultiSpan, &'a [CodeSuggestion]) {
let mut primary_span = db.span.clone();
if let Some((sugg, rest)) = db.suggestions.split_first() {
@ -377,7 +379,7 @@ pub trait Emitter {
}
impl Emitter for EmitterWriter {
fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>) {
fn emit_diagnostic(&mut self, db: &Diagnostic) {
let mut children = db.children.clone();
let (mut primary_span, suggestions) = self.primary_span_formatted(&db);
@ -385,7 +387,7 @@ impl Emitter for EmitterWriter {
&mut primary_span,
&mut children,
&db.level,
db.handler().flags.external_macro_backtrace);
self.external_macro_backtrace);
self.emit_messages_default(&db.level,
&db.styled_message(),
@ -449,6 +451,8 @@ pub struct EmitterWriter {
teach: bool,
ui_testing: bool,
terminal_width: Option<usize>,
external_macro_backtrace: bool,
}
#[derive(Debug)]
@ -465,6 +469,7 @@ impl EmitterWriter {
short_message: bool,
teach: bool,
terminal_width: Option<usize>,
external_macro_backtrace: bool,
) -> EmitterWriter {
let dst = Destination::from_stderr(color_config);
EmitterWriter {
@ -474,6 +479,7 @@ impl EmitterWriter {
teach,
ui_testing: false,
terminal_width,
external_macro_backtrace,
}
}
@ -484,6 +490,7 @@ impl EmitterWriter {
teach: bool,
colored: bool,
terminal_width: Option<usize>,
external_macro_backtrace: bool,
) -> EmitterWriter {
EmitterWriter {
dst: Raw(dst, colored),
@ -492,6 +499,7 @@ impl EmitterWriter {
teach,
ui_testing: false,
terminal_width,
external_macro_backtrace,
}
}

View File

@ -16,7 +16,7 @@ use Level::*;
use emitter::{Emitter, EmitterWriter};
use registry::Registry;
use rustc_data_structures::sync::{self, Lrc, Lock, AtomicUsize, AtomicBool, SeqCst};
use rustc_data_structures::sync::{self, Lrc, Lock};
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::stable_hasher::StableHasher;
@ -298,30 +298,34 @@ pub use diagnostic_builder::DiagnosticBuilder;
/// Certain errors (fatal, bug, unimpl) may cause immediate exit,
/// others log errors for later reporting.
pub struct Handler {
pub flags: HandlerFlags,
flags: HandlerFlags,
inner: Lock<HandlerInner>,
}
struct HandlerInner {
flags: HandlerFlags,
/// The number of errors that have been emitted, including duplicates.
///
/// This is not necessarily the count that's reported to the user once
/// compilation ends.
err_count: AtomicUsize,
deduplicated_err_count: AtomicUsize,
emitter: Lock<Box<dyn Emitter + sync::Send>>,
continue_after_error: AtomicBool,
delayed_span_bugs: Lock<Vec<Diagnostic>>,
err_count: usize,
deduplicated_err_count: usize,
emitter: Box<dyn Emitter + sync::Send>,
continue_after_error: bool,
delayed_span_bugs: Vec<Diagnostic>,
/// This set contains the `DiagnosticId` of all emitted diagnostics to avoid
/// emitting the same diagnostic with extended help (`--teach`) twice, which
/// would be uneccessary repetition.
taught_diagnostics: Lock<FxHashSet<DiagnosticId>>,
taught_diagnostics: FxHashSet<DiagnosticId>,
/// Used to suggest rustc --explain <error code>
emitted_diagnostic_codes: Lock<FxHashSet<DiagnosticId>>,
emitted_diagnostic_codes: FxHashSet<DiagnosticId>,
/// This set contains a hash of every diagnostic that has been emitted by
/// this handler. These hashes is used to avoid emitting the same error
/// twice.
emitted_diagnostics: Lock<FxHashSet<u128>>,
emitted_diagnostics: FxHashSet<u128>,
}
fn default_track_diagnostic(_: &Diagnostic) {}
@ -329,7 +333,7 @@ fn default_track_diagnostic(_: &Diagnostic) {}
thread_local!(pub static TRACK_DIAGNOSTICS: Cell<fn(&Diagnostic)> =
Cell::new(default_track_diagnostic));
#[derive(Default)]
#[derive(Copy, Clone, Default)]
pub struct HandlerFlags {
/// If false, warning-level lints are suppressed.
/// (rustc: see `--allow warnings` and `--cap-lints`)
@ -348,13 +352,13 @@ pub struct HandlerFlags {
pub external_macro_backtrace: bool,
}
impl Drop for Handler {
impl Drop for HandlerInner {
fn drop(&mut self) {
if !self.has_errors() {
let mut bugs = self.delayed_span_bugs.borrow_mut();
if self.err_count == 0 {
let bugs = std::mem::replace(&mut self.delayed_span_bugs, Vec::new());
let has_bugs = !bugs.is_empty();
for bug in bugs.drain(..) {
DiagnosticBuilder::new_diagnostic(self, bug).emit();
for bug in bugs {
self.emit_diagnostic(&bug);
}
if has_bugs {
panic!("no errors encountered even though `delay_span_bug` issued");
@ -383,7 +387,8 @@ impl Handler {
cm: Option<Lrc<SourceMapperDyn>>,
flags: HandlerFlags)
-> Handler {
let emitter = Box::new(EmitterWriter::stderr(color_config, cm, false, false, None));
let emitter = Box::new(EmitterWriter::stderr(
color_config, cm, false, false, None, flags.external_macro_backtrace));
Handler::with_emitter_and_flags(emitter, flags)
}
@ -404,19 +409,28 @@ impl Handler {
{
Handler {
flags,
err_count: AtomicUsize::new(0),
deduplicated_err_count: AtomicUsize::new(0),
emitter: Lock::new(e),
continue_after_error: AtomicBool::new(true),
delayed_span_bugs: Lock::new(Vec::new()),
taught_diagnostics: Default::default(),
emitted_diagnostic_codes: Default::default(),
emitted_diagnostics: Default::default(),
inner: Lock::new(HandlerInner {
flags,
err_count: 0,
deduplicated_err_count: 0,
emitter: e,
continue_after_error: true,
delayed_span_bugs: Vec::new(),
taught_diagnostics: Default::default(),
emitted_diagnostic_codes: Default::default(),
emitted_diagnostics: Default::default(),
}),
}
}
pub fn set_continue_after_error(&self, continue_after_error: bool) {
self.continue_after_error.store(continue_after_error, SeqCst);
self.inner.borrow_mut().continue_after_error = continue_after_error;
}
// This is here to not allow mutation of flags;
// as of this writing it's only used in tests in librustc.
pub fn can_emit_warnings(&self) -> bool {
self.flags.can_emit_warnings
}
/// Resets the diagnostic error count as well as the cached emitted diagnostics.
@ -424,11 +438,13 @@ impl Handler {
/// NOTE: *do not* call this function from rustc. It is only meant to be called from external
/// tools that want to reuse a `Parser` cleaning the previously emitted diagnostics as well as
/// the overall count of emitted error diagnostics.
// FIXME: this does not clear inner entirely
pub fn reset_err_count(&self) {
let mut inner = self.inner.borrow_mut();
// actually frees the underlying memory (which `clear` would not do)
*self.emitted_diagnostics.borrow_mut() = Default::default();
self.deduplicated_err_count.store(0, SeqCst);
self.err_count.store(0, SeqCst);
inner.emitted_diagnostics = Default::default();
inner.deduplicated_err_count = 0;
inner.err_count = 0;
}
pub fn struct_dummy(&self) -> DiagnosticBuilder<'_> {
@ -519,30 +535,9 @@ impl Handler {
DiagnosticBuilder::new(self, Level::Fatal, msg)
}
pub fn cancel(&self, err: &mut DiagnosticBuilder<'_>) {
err.cancel();
}
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)) {
(0, _) => return,
(1, 1) => "aborting due to `-Z treat-err-as-bug=1`".to_string(),
(1, _) => return,
(count, as_bug) => {
format!(
"aborting after {} errors due to `-Z treat-err-as-bug={}`",
count,
as_bug,
)
}
};
panic!(s);
}
}
pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> FatalError {
self.emit(&sp.into(), msg, Fatal);
self.emit_diagnostic(Diagnostic::new(Fatal, msg).set_span(sp));
self.abort_if_errors_and_should_abort();
FatalError
}
pub fn span_fatal_with_code<S: Into<MultiSpan>>(&self,
@ -550,11 +545,13 @@ impl Handler {
msg: &str,
code: DiagnosticId)
-> FatalError {
self.emit_with_code(&sp.into(), msg, code, Fatal);
self.emit_diagnostic(Diagnostic::new_with_code(Fatal, Some(code), msg).set_span(sp));
self.abort_if_errors_and_should_abort();
FatalError
}
pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.emit(&sp.into(), msg, Error);
self.emit_diagnostic(Diagnostic::new(Error, msg).set_span(sp));
self.abort_if_errors_and_should_abort();
}
pub fn mut_span_err<S: Into<MultiSpan>>(&self,
sp: S,
@ -565,38 +562,30 @@ impl Handler {
result
}
pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
self.emit_with_code(&sp.into(), msg, code, Error);
self.emit_diagnostic(Diagnostic::new_with_code(Error, Some(code), msg).set_span(sp));
self.abort_if_errors_and_should_abort();
}
pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.emit(&sp.into(), msg, Warning);
self.emit_diagnostic(Diagnostic::new(Warning, msg).set_span(sp));
self.abort_if_errors_and_should_abort();
}
pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
self.emit_with_code(&sp.into(), msg, code, Warning);
self.emit_diagnostic(Diagnostic::new_with_code(Warning, Some(code), msg).set_span(sp));
self.abort_if_errors_and_should_abort();
}
pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
self.emit(&sp.into(), msg, Bug);
panic!(ExplicitBug);
self.inner.borrow_mut().span_bug(sp, msg)
}
pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
if self.treat_err_as_bug() {
// FIXME: don't abort here if report_delayed_bugs is off
self.span_bug(sp, msg);
}
let mut diagnostic = Diagnostic::new(Level::Bug, msg);
diagnostic.set_span(sp.into());
self.delay_as_bug(diagnostic);
}
fn delay_as_bug(&self, diagnostic: Diagnostic) {
if self.flags.report_delayed_bugs {
DiagnosticBuilder::new_diagnostic(self, diagnostic.clone()).emit();
}
self.delayed_span_bugs.borrow_mut().push(diagnostic);
self.inner.borrow_mut().delay_span_bug(sp, msg)
}
pub fn span_bug_no_panic<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.emit(&sp.into(), msg, Bug);
self.emit_diagnostic(Diagnostic::new(Bug, msg).set_span(sp));
self.abort_if_errors_and_should_abort();
}
pub fn span_note_without_error<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.emit(&sp.into(), msg, Note);
self.emit_diagnostic(Diagnostic::new(Note, msg).set_span(sp));
self.abort_if_errors_and_should_abort();
}
pub fn span_note_diag(&self,
sp: Span,
@ -606,53 +595,29 @@ impl Handler {
db.set_span(sp);
db
}
pub fn span_unimpl<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
self.span_bug(sp, &format!("unimplemented {}", msg));
}
pub fn failure(&self, msg: &str) {
DiagnosticBuilder::new(self, FailureNote, msg).emit()
self.inner.borrow_mut().failure(msg);
}
pub fn fatal(&self, msg: &str) -> FatalError {
if self.treat_err_as_bug() {
self.bug(msg);
}
DiagnosticBuilder::new(self, Fatal, msg).emit();
FatalError
self.inner.borrow_mut().fatal(msg)
}
pub fn err(&self, msg: &str) {
if self.treat_err_as_bug() {
self.bug(msg);
}
let mut db = DiagnosticBuilder::new(self, Error, msg);
db.emit();
self.inner.borrow_mut().err(msg);
}
pub fn warn(&self, msg: &str) {
let mut db = DiagnosticBuilder::new(self, Warning, msg);
db.emit();
}
fn treat_err_as_bug(&self) -> bool {
self.flags.treat_err_as_bug.map(|c| self.err_count() >= c).unwrap_or(false)
}
pub fn note_without_error(&self, msg: &str) {
let mut db = DiagnosticBuilder::new(self, Note, msg);
db.emit();
}
pub fn bug(&self, msg: &str) -> ! {
let mut db = DiagnosticBuilder::new(self, Bug, msg);
db.emit();
panic!(ExplicitBug);
}
pub fn unimpl(&self, msg: &str) -> ! {
self.bug(&format!("unimplemented {}", msg));
}
fn bump_err_count(&self) {
self.err_count.fetch_add(1, SeqCst);
self.panic_if_treat_err_as_bug();
self.inner.borrow_mut().bug(msg)
}
pub fn err_count(&self) -> usize {
self.err_count.load(SeqCst)
self.inner.borrow().err_count
}
pub fn has_errors(&self) -> bool {
@ -660,7 +625,99 @@ impl Handler {
}
pub fn print_error_count(&self, registry: &Registry) {
let s = match self.deduplicated_err_count.load(SeqCst) {
self.inner.borrow_mut().print_error_count(registry)
}
pub fn abort_if_errors(&self) {
self.inner.borrow().abort_if_errors()
}
pub fn abort_if_errors_and_should_abort(&self) {
self.inner.borrow().abort_if_errors_and_should_abort()
}
pub fn must_teach(&self, code: &DiagnosticId) -> bool {
self.inner.borrow_mut().must_teach(code)
}
pub fn force_print_diagnostic(&self, db: Diagnostic) {
self.inner.borrow_mut().force_print_diagnostic(db)
}
pub fn emit_diagnostic(&self, diagnostic: &Diagnostic) {
self.inner.borrow_mut().emit_diagnostic(diagnostic)
}
pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
self.inner.borrow_mut().emit_artifact_notification(path, artifact_type)
}
pub fn delay_as_bug(&self, diagnostic: Diagnostic) {
self.inner.borrow_mut().delay_as_bug(diagnostic)
}
}
impl HandlerInner {
/// `true` if we haven't taught a diagnostic with this code already.
/// The caller must then teach the user about such a diagnostic.
///
/// Used to suppress emitting the same error multiple times with extended explanation when
/// calling `-Zteach`.
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);
}
fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) {
if diagnostic.cancelled() {
return;
}
if diagnostic.level == Warning && !self.flags.can_emit_warnings {
return;
}
TRACK_DIAGNOSTICS.with(|track_diagnostics| {
track_diagnostics.get()(diagnostic);
});
if let Some(ref code) = diagnostic.code {
self.emitted_diagnostic_codes.insert(code.clone());
}
let diagnostic_hash = {
use std::hash::Hash;
let mut hasher = StableHasher::new();
diagnostic.hash(&mut hasher);
hasher.finish()
};
// Only emit the diagnostic if we haven't already emitted an equivalent
// one:
if self.emitted_diagnostics.insert(diagnostic_hash) {
self.emitter.emit_diagnostic(diagnostic);
if diagnostic.is_error() {
self.deduplicated_err_count += 1;
}
}
if diagnostic.is_error() {
self.bump_err_count();
}
}
fn emit_artifact_notification(&mut self, path: &Path, artifact_type: &str) {
self.emitter.emit_artifact_notification(path, artifact_type);
}
fn treat_err_as_bug(&self) -> bool {
self.flags.treat_err_as_bug.map(|c| self.err_count >= c).unwrap_or(false)
}
fn print_error_count(&mut self, registry: &Registry) {
let s = match self.deduplicated_err_count {
0 => return,
1 => "aborting due to previous error".to_string(),
count => format!("aborting due to {} previous errors", count)
@ -671,12 +728,11 @@ impl Handler {
let _ = self.fatal(&s);
let can_show_explain = self.emitter.borrow().should_show_explain();
let are_there_diagnostics = !self.emitted_diagnostic_codes.borrow().is_empty();
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
.borrow()
.iter()
.filter_map(|x| match &x {
DiagnosticId::Error(s) if registry.find_description(s).is_some() => {
@ -704,81 +760,86 @@ impl Handler {
}
}
pub fn abort_if_errors(&self) {
if self.has_errors() {
fn abort_if_errors_and_should_abort(&self) {
if self.err_count > 0 && !self.continue_after_error {
FatalError.raise();
}
}
pub fn emit(&self, msp: &MultiSpan, msg: &str, lvl: Level) {
if lvl == Warning && !self.flags.can_emit_warnings {
return;
}
let mut db = DiagnosticBuilder::new(self, lvl, msg);
db.set_span(msp.clone());
db.emit();
if !self.continue_after_error.load(SeqCst) {
self.abort_if_errors();
}
}
pub fn emit_with_code(&self, msp: &MultiSpan, msg: &str, code: DiagnosticId, lvl: Level) {
if lvl == Warning && !self.flags.can_emit_warnings {
return;
}
let mut db = DiagnosticBuilder::new_with_code(self, lvl, Some(code), msg);
db.set_span(msp.clone());
db.emit();
if !self.continue_after_error.load(SeqCst) {
self.abort_if_errors();
fn abort_if_errors(&self) {
if self.err_count > 0 {
FatalError.raise();
}
}
/// `true` if we haven't taught a diagnostic with this code already.
/// The caller must then teach the user about such a diagnostic.
///
/// Used to suppress emitting the same error multiple times with extended explanation when
/// calling `-Zteach`.
pub fn must_teach(&self, code: &DiagnosticId) -> bool {
self.taught_diagnostics.borrow_mut().insert(code.clone())
fn span_bug<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> ! {
self.emit_diagnostic(Diagnostic::new(Bug, msg).set_span(sp));
self.abort_if_errors_and_should_abort();
panic!(ExplicitBug);
}
pub fn force_print_db(&self, mut db: DiagnosticBuilder<'_>) {
self.emitter.borrow_mut().emit_diagnostic(&db);
db.cancel();
fn delay_span_bug<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) {
if self.treat_err_as_bug() {
// FIXME: don't abort here if report_delayed_bugs is off
self.span_bug(sp, msg);
}
let mut diagnostic = Diagnostic::new(Level::Bug, msg);
diagnostic.set_span(sp.into());
self.delay_as_bug(diagnostic)
}
fn emit_db(&self, db: &DiagnosticBuilder<'_>) {
let diagnostic = &**db;
TRACK_DIAGNOSTICS.with(|track_diagnostics| {
track_diagnostics.get()(diagnostic);
});
if let Some(ref code) = diagnostic.code {
self.emitted_diagnostic_codes.borrow_mut().insert(code.clone());
}
let diagnostic_hash = {
use std::hash::Hash;
let mut hasher = StableHasher::new();
diagnostic.hash(&mut hasher);
hasher.finish()
};
// Only emit the diagnostic if we haven't already emitted an equivalent
// one:
if self.emitted_diagnostics.borrow_mut().insert(diagnostic_hash) {
self.emitter.borrow_mut().emit_diagnostic(db);
if db.is_error() {
self.deduplicated_err_count.fetch_add(1, SeqCst);
}
}
if db.is_error() {
self.bump_err_count();
}
fn failure(&mut self, msg: &str) {
self.emit_diagnostic(&Diagnostic::new(FailureNote, msg));
}
pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
self.emitter.borrow_mut().emit_artifact_notification(path, artifact_type);
fn fatal(&mut self, msg: &str) -> FatalError {
if self.treat_err_as_bug() {
self.bug(msg);
}
self.emit_diagnostic(&Diagnostic::new(Fatal, msg));
FatalError
}
fn err(&mut self, msg: &str) {
if self.treat_err_as_bug() {
self.bug(msg);
}
self.emit_diagnostic(&Diagnostic::new(Error, msg));
}
fn bug(&mut self, msg: &str) -> ! {
self.emit_diagnostic(&Diagnostic::new(Bug, msg));
panic!(ExplicitBug);
}
fn delay_as_bug(&mut self, diagnostic: Diagnostic) {
if self.flags.report_delayed_bugs {
self.emit_diagnostic(&diagnostic);
}
self.delayed_span_bugs.push(diagnostic);
}
fn bump_err_count(&mut self) {
self.err_count += 1;
self.panic_if_treat_err_as_bug();
}
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)) {
(0, _) => return,
(1, 1) => "aborting due to `-Z treat-err-as-bug=1`".to_string(),
(1, _) => return,
(count, as_bug) => {
format!(
"aborting after {} errors due to `-Z treat-err-as-bug={}`",
count,
as_bug,
)
}
};
panic!(s);
}
}
}

View File

@ -402,7 +402,7 @@ fn do_mir_borrowck<'a, 'tcx>(
}
for diag in mbcx.errors_buffer.drain(..) {
DiagnosticBuilder::new_diagnostic(mbcx.infcx.tcx.sess.diagnostic(), diag).emit();
mbcx.infcx.tcx.sess.diagnostic().emit_diagnostic(&diag);
}
}

View File

@ -3,7 +3,6 @@
// substitutions.
use crate::check::FnCtxt;
use errors::DiagnosticBuilder;
use rustc::hir;
use rustc::hir::def_id::{DefId, DefIndex};
use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
@ -407,7 +406,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
if !errors_buffer.is_empty() {
errors_buffer.sort_by_key(|diag| diag.span.primary_span());
for diag in errors_buffer.drain(..) {
DiagnosticBuilder::new_diagnostic(self.tcx().sess.diagnostic(), diag).emit();
self.tcx().sess.diagnostic().emit_diagnostic(&diag);
}
}
}

View File

@ -193,6 +193,7 @@ pub fn new_handler(error_format: ErrorOutputType,
short,
sessopts.debugging_opts.teach,
sessopts.debugging_opts.terminal_width,
false,
).ui_testing(ui_testing)
)
},
@ -205,6 +206,7 @@ pub fn new_handler(error_format: ErrorOutputType,
source_map,
pretty,
json_rendered,
false,
).ui_testing(ui_testing)
)
},

View File

@ -401,7 +401,7 @@ pub fn make_test(s: &str,
// Any errors in parsing should also appear when the doctest is compiled for real, so just
// send all the errors that libsyntax emits directly into a `Sink` instead of stderr.
let cm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
let emitter = EmitterWriter::new(box io::sink(), None, false, false, false, None);
let emitter = EmitterWriter::new(box io::sink(), None, false, false, false, None, false);
// FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser
let handler = Handler::with_emitter(false, None, box emitter);
let sess = ParseSess::with_span_handler(handler, cm);

View File

@ -1048,9 +1048,6 @@ impl<'a> ExtCtxt<'a> {
pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.parse_sess.span_diagnostic.span_warn(sp, msg);
}
pub fn span_unimpl<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
self.parse_sess.span_diagnostic.span_unimpl(sp, msg);
}
pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
self.parse_sess.span_diagnostic.span_bug(sp, msg);
}

View File

@ -4,7 +4,7 @@ use crate::parse::{self, token, ParseSess};
use crate::parse::lexer::comments;
use crate::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint};
use errors::{Diagnostic, DiagnosticBuilder};
use errors::Diagnostic;
use rustc_data_structures::sync::Lrc;
use syntax_pos::{BytePos, FileName, MultiSpan, Pos, SourceFile, Span};
use syntax_pos::symbol::{kw, sym, Symbol};
@ -650,7 +650,7 @@ impl server::Diagnostic for Rustc<'_> {
diag.sub(level.to_internal(), msg, MultiSpan::from_spans(spans), None);
}
fn emit(&mut self, diag: Self::Diagnostic) {
DiagnosticBuilder::new_diagnostic(&self.sess.span_diagnostic, diag).emit()
self.sess.span_diagnostic.emit_diagnostic(&diag);
}
}

View File

@ -12,7 +12,7 @@
use crate::source_map::{SourceMap, FilePathMapping};
use errors::registry::Registry;
use errors::{DiagnosticBuilder, SubDiagnostic, CodeSuggestion, SourceMapper};
use errors::{SubDiagnostic, CodeSuggestion, SourceMapper};
use errors::{DiagnosticId, Applicability};
use errors::emitter::{Emitter, HumanReadableErrorType};
@ -32,6 +32,7 @@ pub struct JsonEmitter {
pretty: bool,
ui_testing: bool,
json_rendered: HumanReadableErrorType,
external_macro_backtrace: bool,
}
impl JsonEmitter {
@ -40,6 +41,7 @@ impl JsonEmitter {
source_map: Lrc<SourceMap>,
pretty: bool,
json_rendered: HumanReadableErrorType,
external_macro_backtrace: bool,
) -> JsonEmitter {
JsonEmitter {
dst: Box::new(io::stderr()),
@ -48,13 +50,18 @@ impl JsonEmitter {
pretty,
ui_testing: false,
json_rendered,
external_macro_backtrace,
}
}
pub fn basic(pretty: bool, json_rendered: HumanReadableErrorType) -> JsonEmitter {
pub fn basic(
pretty: bool,
json_rendered: HumanReadableErrorType,
external_macro_backtrace: bool,
) -> JsonEmitter {
let file_path_mapping = FilePathMapping::empty();
JsonEmitter::stderr(None, Lrc::new(SourceMap::new(file_path_mapping)),
pretty, json_rendered)
pretty, json_rendered, external_macro_backtrace)
}
pub fn new(
@ -63,6 +70,7 @@ impl JsonEmitter {
source_map: Lrc<SourceMap>,
pretty: bool,
json_rendered: HumanReadableErrorType,
external_macro_backtrace: bool,
) -> JsonEmitter {
JsonEmitter {
dst,
@ -71,6 +79,7 @@ impl JsonEmitter {
pretty,
ui_testing: false,
json_rendered,
external_macro_backtrace,
}
}
@ -80,8 +89,8 @@ impl JsonEmitter {
}
impl Emitter for JsonEmitter {
fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>) {
let data = Diagnostic::from_diagnostic_builder(db, self);
fn emit_diagnostic(&mut self, db: &errors::Diagnostic) {
let data = Diagnostic::from_errors_diagnostic(db, self);
let result = if self.pretty {
writeln!(&mut self.dst, "{}", as_pretty_json(&data))
} else {
@ -189,7 +198,7 @@ struct ArtifactNotification<'a> {
}
impl Diagnostic {
fn from_diagnostic_builder(db: &DiagnosticBuilder<'_>,
fn from_errors_diagnostic(db: &errors::Diagnostic,
je: &JsonEmitter)
-> Diagnostic {
let sugg = db.suggestions.iter().map(|sugg| {
@ -219,8 +228,9 @@ impl Diagnostic {
}
let buf = BufWriter::default();
let output = buf.clone();
je.json_rendered.new_emitter(Box::new(buf), Some(je.sm.clone()), false, None)
.ui_testing(je.ui_testing).emit_diagnostic(db);
je.json_rendered.new_emitter(
Box::new(buf), Some(je.sm.clone()), false, None, je.external_macro_backtrace
).ui_testing(je.ui_testing).emit_diagnostic(db);
let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap();
let output = String::from_utf8(output).unwrap();

View File

@ -60,12 +60,12 @@ macro_rules! panictry {
macro_rules! panictry_buffer {
($handler:expr, $e:expr) => ({
use std::result::Result::{Ok, Err};
use errors::{FatalError, DiagnosticBuilder};
use errors::FatalError;
match $e {
Ok(e) => e,
Err(errs) => {
for e in errs {
DiagnosticBuilder::new_diagnostic($handler, e).emit();
$handler.emit_diagnostic(&e);
}
FatalError.raise()
}

View File

@ -302,14 +302,14 @@ impl<'a> Parser<'a> {
Ok(lit) => {
return Ok(ast::NestedMetaItem::Literal(lit))
}
Err(ref mut err) => self.diagnostic().cancel(err)
Err(ref mut err) => err.cancel(),
}
match self.parse_meta_item() {
Ok(mi) => {
return Ok(ast::NestedMetaItem::MetaItem(mi))
}
Err(ref mut err) => self.diagnostic().cancel(err)
Err(ref mut err) => err.cancel(),
}
let found = self.this_token_to_string();

View File

@ -197,10 +197,6 @@ impl<'a> Parser<'a> {
self.sess.span_diagnostic.span_bug(sp, m)
}
crate fn cancel(&self, err: &mut DiagnosticBuilder<'_>) {
self.sess.span_diagnostic.cancel(err)
}
crate fn diagnostic(&self) -> &'a errors::Handler {
&self.sess.span_diagnostic
}
@ -426,15 +422,13 @@ impl<'a> Parser<'a> {
/// Eats and discards tokens until one of `kets` is encountered. Respects token trees,
/// passes through any errors encountered. Used for error recovery.
crate fn eat_to_tokens(&mut self, kets: &[&TokenKind]) {
let handler = self.diagnostic();
if let Err(ref mut err) = self.parse_seq_to_before_tokens(
kets,
SeqSep::none(),
TokenExpectType::Expect,
|p| Ok(p.parse_token_tree()),
) {
handler.cancel(err);
err.cancel();
}
}

View File

@ -18,6 +18,7 @@ fn mk_sess(sm: Lrc<SourceMap>) -> ParseSess {
false,
false,
None,
false,
);
ParseSess::with_span_handler(Handler::with_emitter(true, None, Box::new(emitter)), sm)
}

View File

@ -304,7 +304,7 @@ fn file_to_source_file(sess: &ParseSess, path: &Path, spanopt: Option<Span>)
match try_file_to_source_file(sess, path, spanopt) {
Ok(source_file) => source_file,
Err(d) => {
DiagnosticBuilder::new_diagnostic(&sess.span_diagnostic, d).emit();
sess.span_diagnostic.emit_diagnostic(&d);
FatalError.raise();
}
}

View File

@ -777,7 +777,7 @@ impl<'a> Parser<'a> {
ex = ExprKind::Lit(literal);
}
Err(mut err) => {
self.cancel(&mut err);
err.cancel();
return Err(self.expected_expression_found());
}
}

View File

@ -537,7 +537,7 @@ impl<'a> Parser<'a> {
mut err: DiagnosticBuilder<'a>,
expected: Expected,
) -> PResult<'a, P<Pat>> {
self.cancel(&mut err);
err.cancel();
let expected = expected.unwrap_or("pattern");
let msg = format!("expected {}, found {}", expected, self.this_token_descr());

View File

@ -361,7 +361,7 @@ impl<'a> Parser<'a> {
}
Err(mut e) => {
self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore);
self.cancel(&mut e);
e.cancel();
}
_ => ()
}

View File

@ -147,6 +147,7 @@ fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &
false,
false,
None,
false,
);
let handler = Handler::with_emitter(true, None, Box::new(emitter));
handler.span_err(msp, "foo");