Skip to content

Commit 7b2deb5

Browse files
committed
rustc_{errors,session}: add delay_good_path_bug
The first use case of this detection of regression for trimmed paths computation, that is in the case of rustc, which should be computed only in case of errors or warnings. Our current user of this method is deeply nested, being a side effect from `Display` formatting on lots of rustc types. So taking only the caller to the error message is not enough - we should collect the traceback instead.
1 parent 75a042e commit 7b2deb5

File tree

2 files changed

+66
-7
lines changed

2 files changed

+66
-7
lines changed

compiler/rustc_errors/src/lib.rs

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
55
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
66
#![feature(crate_visibility_modifier)]
7+
#![feature(backtrace)]
78
#![feature(nll)]
89

910
#[macro_use]
@@ -296,9 +297,11 @@ struct HandlerInner {
296297
/// This is not necessarily the count that's reported to the user once
297298
/// compilation ends.
298299
err_count: usize,
300+
warn_count: usize,
299301
deduplicated_err_count: usize,
300302
emitter: Box<dyn Emitter + sync::Send>,
301303
delayed_span_bugs: Vec<Diagnostic>,
304+
delayed_good_path_bugs: Vec<Diagnostic>,
302305

303306
/// This set contains the `DiagnosticId` of all emitted diagnostics to avoid
304307
/// emitting the same diagnostic with extended help (`--teach`) twice, which
@@ -361,13 +364,15 @@ impl Drop for HandlerInner {
361364

362365
if !self.has_errors() {
363366
let bugs = std::mem::replace(&mut self.delayed_span_bugs, Vec::new());
364-
let has_bugs = !bugs.is_empty();
365-
for bug in bugs {
366-
self.emit_diagnostic(&bug);
367-
}
368-
if has_bugs {
369-
panic!("no errors encountered even though `delay_span_bug` issued");
370-
}
367+
self.flush_delayed(bugs, "no errors encountered even though `delay_span_bug` issued");
368+
}
369+
370+
if !self.has_any_message() {
371+
let bugs = std::mem::replace(&mut self.delayed_good_path_bugs, Vec::new());
372+
self.flush_delayed(
373+
bugs,
374+
"no warnings or errors encountered even though `delayed_good_path_bugs` issued",
375+
);
371376
}
372377
}
373378
}
@@ -422,10 +427,12 @@ impl Handler {
422427
inner: Lock::new(HandlerInner {
423428
flags,
424429
err_count: 0,
430+
warn_count: 0,
425431
deduplicated_err_count: 0,
426432
deduplicated_warn_count: 0,
427433
emitter,
428434
delayed_span_bugs: Vec::new(),
435+
delayed_good_path_bugs: Vec::new(),
429436
taught_diagnostics: Default::default(),
430437
emitted_diagnostic_codes: Default::default(),
431438
emitted_diagnostics: Default::default(),
@@ -448,11 +455,13 @@ impl Handler {
448455
pub fn reset_err_count(&self) {
449456
let mut inner = self.inner.borrow_mut();
450457
inner.err_count = 0;
458+
inner.warn_count = 0;
451459
inner.deduplicated_err_count = 0;
452460
inner.deduplicated_warn_count = 0;
453461

454462
// actually free the underlying memory (which `clear` would not do)
455463
inner.delayed_span_bugs = Default::default();
464+
inner.delayed_good_path_bugs = Default::default();
456465
inner.taught_diagnostics = Default::default();
457466
inner.emitted_diagnostic_codes = Default::default();
458467
inner.emitted_diagnostics = Default::default();
@@ -629,6 +638,10 @@ impl Handler {
629638
self.inner.borrow_mut().delay_span_bug(span, msg)
630639
}
631640

641+
pub fn delay_good_path_bug(&self, msg: &str) {
642+
self.inner.borrow_mut().delay_good_path_bug(msg)
643+
}
644+
632645
pub fn span_bug_no_panic(&self, span: impl Into<MultiSpan>, msg: &str) {
633646
self.emit_diag_at_span(Diagnostic::new(Bug, msg), span);
634647
}
@@ -768,6 +781,8 @@ impl HandlerInner {
768781
}
769782
if diagnostic.is_error() {
770783
self.bump_err_count();
784+
} else {
785+
self.bump_warn_count();
771786
}
772787
}
773788

@@ -859,6 +874,9 @@ impl HandlerInner {
859874
fn has_errors_or_delayed_span_bugs(&self) -> bool {
860875
self.has_errors() || !self.delayed_span_bugs.is_empty()
861876
}
877+
fn has_any_message(&self) -> bool {
878+
self.err_count() > 0 || self.warn_count > 0
879+
}
862880

863881
fn abort_if_errors(&mut self) {
864882
self.emit_stashed_diagnostics();
@@ -892,6 +910,15 @@ impl HandlerInner {
892910
self.delay_as_bug(diagnostic)
893911
}
894912

913+
fn delay_good_path_bug(&mut self, msg: &str) {
914+
let mut diagnostic = Diagnostic::new(Level::Bug, msg);
915+
if self.flags.report_delayed_bugs {
916+
self.emit_diagnostic(&diagnostic);
917+
}
918+
diagnostic.note(&format!("delayed at {}", std::backtrace::Backtrace::force_capture()));
919+
self.delayed_good_path_bugs.push(diagnostic);
920+
}
921+
895922
fn failure(&mut self, msg: &str) {
896923
self.emit_diagnostic(&Diagnostic::new(FailureNote, msg));
897924
}
@@ -925,11 +952,25 @@ impl HandlerInner {
925952
self.delayed_span_bugs.push(diagnostic);
926953
}
927954

955+
fn flush_delayed(&mut self, bugs: Vec<Diagnostic>, explanation: &str) {
956+
let has_bugs = !bugs.is_empty();
957+
for bug in bugs {
958+
self.emit_diagnostic(&bug);
959+
}
960+
if has_bugs {
961+
panic!("{}", explanation);
962+
}
963+
}
964+
928965
fn bump_err_count(&mut self) {
929966
self.err_count += 1;
930967
self.panic_if_treat_err_as_bug();
931968
}
932969

970+
fn bump_warn_count(&mut self) {
971+
self.warn_count += 1;
972+
}
973+
933974
fn panic_if_treat_err_as_bug(&self) {
934975
if self.treat_err_as_bug() {
935976
let s = match (self.err_count(), self.flags.treat_err_as_bug.unwrap_or(0)) {

compiler/rustc_session/src/session.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,24 @@ impl Session {
442442
pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
443443
self.diagnostic().delay_span_bug(sp, msg)
444444
}
445+
446+
/// Used for code paths of expensive computations that should only take place when
447+
/// warnings or errors are emitted. If no messages are emitted ("good path"), then
448+
/// it's likely a bug.
449+
pub fn delay_good_path_bug(&self, msg: &str) {
450+
if self.opts.debugging_opts.print_type_sizes
451+
|| self.opts.debugging_opts.query_dep_graph
452+
|| self.opts.debugging_opts.dump_mir.is_some()
453+
|| self.opts.debugging_opts.unpretty.is_some()
454+
|| self.opts.output_types.contains_key(&OutputType::Mir)
455+
|| std::env::var_os("RUSTC_LOG").is_some()
456+
{
457+
return;
458+
}
459+
460+
self.diagnostic().delay_good_path_bug(msg)
461+
}
462+
445463
pub fn note_without_error(&self, msg: &str) {
446464
self.diagnostic().note_without_error(msg)
447465
}

0 commit comments

Comments
 (0)