Even if that is just happening because of `abort_if_errors`
"run all passes except codegen; no output"),
treat_err_as_bug: bool = (false, parse_bool, [TRACKED],
"treat all errors that occur as bugs"),
"run all passes except codegen; no output"),
treat_err_as_bug: bool = (false, parse_bool, [TRACKED],
"treat all errors that occur as bugs"),
+ report_delayed_bugs: bool = (false, parse_bool, [TRACKED],
+ "immediately print bugs registered with `delay_span_bug`"),
external_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
"show macro backtraces even for non-local macros"),
teach: bool = (false, parse_bool, [TRACKED],
external_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
"show macro backtraces even for non-local macros"),
teach: bool = (false, parse_bool, [TRACKED],
opts.debugging_opts.treat_err_as_bug = true;
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
opts.debugging_opts.treat_err_as_bug = true;
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+ opts = reference.clone();
+ opts.debugging_opts.report_delayed_bugs = true;
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
opts = reference.clone();
opts.debugging_opts.continue_parse_after_error = true;
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
opts = reference.clone();
opts.debugging_opts.continue_parse_after_error = true;
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
let can_emit_warnings = !(warnings_allow || cap_lints_allow);
let treat_err_as_bug = sopts.debugging_opts.treat_err_as_bug;
let can_emit_warnings = !(warnings_allow || cap_lints_allow);
let treat_err_as_bug = sopts.debugging_opts.treat_err_as_bug;
+ let report_delayed_bugs = sopts.debugging_opts.report_delayed_bugs;
let external_macro_backtrace = sopts.debugging_opts.external_macro_backtrace;
let external_macro_backtrace = sopts.debugging_opts.external_macro_backtrace;
errors::HandlerFlags {
can_emit_warnings,
treat_err_as_bug,
errors::HandlerFlags {
can_emit_warnings,
treat_err_as_bug,
external_macro_backtrace,
..Default::default()
},
external_macro_backtrace,
..Default::default()
},
/// locally in whichever way makes the most sense.
pub fn delay_as_bug(&mut self) {
self.level = Level::Bug;
/// locally in whichever way makes the most sense.
pub fn delay_as_bug(&mut self) {
self.level = Level::Bug;
- *self.handler.delayed_span_bug.borrow_mut() = Some(self.diagnostic.clone());
+ self.handler.delay_as_bug(self.diagnostic.clone());
err_count: AtomicUsize,
emitter: Lock<Box<dyn Emitter + sync::Send>>,
continue_after_error: LockCell<bool>,
err_count: AtomicUsize,
emitter: Lock<Box<dyn Emitter + sync::Send>>,
continue_after_error: LockCell<bool>,
- delayed_span_bug: Lock<Option<Diagnostic>>,
+ delayed_span_bug: Lock<Vec<Diagnostic>>,
// This set contains the `DiagnosticId` of all emitted diagnostics to avoid
// emitting the same diagnostic with extended help (`--teach`) twice, which
// This set contains the `DiagnosticId` of all emitted diagnostics to avoid
// emitting the same diagnostic with extended help (`--teach`) twice, which
pub struct HandlerFlags {
pub can_emit_warnings: bool,
pub treat_err_as_bug: bool,
pub struct HandlerFlags {
pub can_emit_warnings: bool,
pub treat_err_as_bug: bool,
+ pub report_delayed_bugs: bool,
pub external_macro_backtrace: bool,
}
pub external_macro_backtrace: bool,
}
+impl Drop for Handler {
+ fn drop(&mut self) {
+ if self.err_count() == 0 {
+ let mut bugs = self.delayed_span_bug.borrow_mut();
+ let has_bugs = !bugs.is_empty();
+ for bug in bugs.drain(..) {
+ DiagnosticBuilder::new_diagnostic(self, bug).emit();
+ }
+ if has_bugs {
+ panic!("no errors encountered even though `delay_span_bug` issued");
+ }
+ }
+ }
+}
+
impl Handler {
pub fn with_tty_emitter(color_config: ColorConfig,
can_emit_warnings: bool,
impl Handler {
pub fn with_tty_emitter(color_config: ColorConfig,
can_emit_warnings: bool,
err_count: AtomicUsize::new(0),
emitter: Lock::new(e),
continue_after_error: LockCell::new(true),
err_count: AtomicUsize::new(0),
emitter: Lock::new(e),
continue_after_error: LockCell::new(true),
- delayed_span_bug: Lock::new(None),
+ delayed_span_bug: Lock::new(Vec::new()),
taught_diagnostics: Lock::new(FxHashSet()),
emitted_diagnostic_codes: Lock::new(FxHashSet()),
emitted_diagnostics: Lock::new(FxHashSet()),
taught_diagnostics: Lock::new(FxHashSet()),
emitted_diagnostic_codes: Lock::new(FxHashSet()),
emitted_diagnostics: Lock::new(FxHashSet()),
}
pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
if self.flags.treat_err_as_bug {
}
pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
if self.flags.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.span_bug(sp, msg);
}
let mut diagnostic = Diagnostic::new(Level::Bug, msg);
diagnostic.set_span(sp.into());
- *self.delayed_span_bug.borrow_mut() = Some(diagnostic);
+ 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_bug.borrow_mut().push(diagnostic);
}
pub fn span_bug_no_panic<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.emit(&sp.into(), msg, Bug);
}
pub fn span_bug_no_panic<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.emit(&sp.into(), msg, Bug);
pub fn abort_if_errors(&self) {
if self.err_count() == 0 {
pub fn abort_if_errors(&self) {
if self.err_count() == 0 {
- if let Some(bug) = self.delayed_span_bug.borrow_mut().take() {
- DiagnosticBuilder::new_diagnostic(self, bug).emit();
- }
return;
}
FatalError.raise();
return;
}
FatalError.raise();
errors::HandlerFlags {
can_emit_warnings: true,
treat_err_as_bug: false,
errors::HandlerFlags {
can_emit_warnings: true,
treat_err_as_bug: false,
+ report_delayed_bugs: false,
external_macro_backtrace: false,
..Default::default()
},
external_macro_backtrace: false,
..Default::default()
},