#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(crate_visibility_modifier)]
+#![feature(backtrace)]
#![feature(nll)]
#[macro_use]
/// This is not necessarily the count that's reported to the user once
/// compilation ends.
err_count: usize,
+ warn_count: usize,
deduplicated_err_count: usize,
emitter: Box<dyn Emitter + sync::Send>,
delayed_span_bugs: Vec<Diagnostic>,
+ delayed_good_path_bugs: Vec<Diagnostic>,
/// This set contains the `DiagnosticId` of all emitted diagnostics to avoid
/// emitting the same diagnostic with extended help (`--teach`) twice, which
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 {
- self.emit_diagnostic(&bug);
- }
- if has_bugs {
- panic!("no errors encountered even though `delay_span_bug` issued");
- }
+ self.flush_delayed(bugs, "no errors encountered even though `delay_span_bug` issued");
+ }
+
+ if !self.has_any_message() {
+ let bugs = std::mem::replace(&mut self.delayed_good_path_bugs, Vec::new());
+ self.flush_delayed(
+ bugs,
+ "no warnings or errors encountered even though `delayed_good_path_bugs` issued",
+ );
}
}
}
inner: Lock::new(HandlerInner {
flags,
err_count: 0,
+ warn_count: 0,
deduplicated_err_count: 0,
deduplicated_warn_count: 0,
emitter,
delayed_span_bugs: Vec::new(),
+ delayed_good_path_bugs: Vec::new(),
taught_diagnostics: Default::default(),
emitted_diagnostic_codes: Default::default(),
emitted_diagnostics: Default::default(),
pub fn reset_err_count(&self) {
let mut inner = self.inner.borrow_mut();
inner.err_count = 0;
+ inner.warn_count = 0;
inner.deduplicated_err_count = 0;
inner.deduplicated_warn_count = 0;
// actually free the underlying memory (which `clear` would not do)
inner.delayed_span_bugs = Default::default();
+ inner.delayed_good_path_bugs = Default::default();
inner.taught_diagnostics = Default::default();
inner.emitted_diagnostic_codes = Default::default();
inner.emitted_diagnostics = Default::default();
self.inner.borrow_mut().delay_span_bug(span, msg)
}
+ pub fn delay_good_path_bug(&self, msg: &str) {
+ self.inner.borrow_mut().delay_good_path_bug(msg)
+ }
+
pub fn span_bug_no_panic(&self, span: impl Into<MultiSpan>, msg: &str) {
self.emit_diag_at_span(Diagnostic::new(Bug, msg), span);
}
}
if diagnostic.is_error() {
self.bump_err_count();
+ } else {
+ self.bump_warn_count();
}
}
fn has_errors_or_delayed_span_bugs(&self) -> bool {
self.has_errors() || !self.delayed_span_bugs.is_empty()
}
+ fn has_any_message(&self) -> bool {
+ self.err_count() > 0 || self.warn_count > 0
+ }
fn abort_if_errors(&mut self) {
self.emit_stashed_diagnostics();
self.delay_as_bug(diagnostic)
}
+ fn delay_good_path_bug(&mut self, msg: &str) {
+ let mut diagnostic = Diagnostic::new(Level::Bug, msg);
+ if self.flags.report_delayed_bugs {
+ self.emit_diagnostic(&diagnostic);
+ }
+ diagnostic.note(&format!("delayed at {}", std::backtrace::Backtrace::force_capture()));
+ self.delayed_good_path_bugs.push(diagnostic);
+ }
+
fn failure(&mut self, msg: &str) {
self.emit_diagnostic(&Diagnostic::new(FailureNote, msg));
}
self.delayed_span_bugs.push(diagnostic);
}
+ fn flush_delayed(&mut self, bugs: Vec<Diagnostic>, explanation: &str) {
+ let has_bugs = !bugs.is_empty();
+ for bug in bugs {
+ self.emit_diagnostic(&bug);
+ }
+ if has_bugs {
+ panic!("{}", explanation);
+ }
+ }
+
fn bump_err_count(&mut self) {
self.err_count += 1;
self.panic_if_treat_err_as_bug();
}
+ fn bump_warn_count(&mut self) {
+ self.warn_count += 1;
+ }
+
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)) {
pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.diagnostic().delay_span_bug(sp, msg)
}
+
+ /// Used for code paths of expensive computations that should only take place when
+ /// warnings or errors are emitted. If no messages are emitted ("good path"), then
+ /// it's likely a bug.
+ pub fn delay_good_path_bug(&self, msg: &str) {
+ if self.opts.debugging_opts.print_type_sizes
+ || self.opts.debugging_opts.query_dep_graph
+ || self.opts.debugging_opts.dump_mir.is_some()
+ || self.opts.debugging_opts.unpretty.is_some()
+ || self.opts.output_types.contains_key(&OutputType::Mir)
+ || std::env::var_os("RUSTC_LOG").is_some()
+ {
+ return;
+ }
+
+ self.diagnostic().delay_good_path_bug(msg)
+ }
+
pub fn note_without_error(&self, msg: &str) {
self.diagnostic().note_without_error(msg)
}