Skip to content

Commit 83f5142

Browse files
committed
Handle unwinding out of the closure argument of run_compiler with pending delayed bugs
1 parent d4e3d36 commit 83f5142

File tree

2 files changed

+28
-17
lines changed

2 files changed

+28
-17
lines changed

compiler/rustc_errors/src/lib.rs

+11-3
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,7 @@ struct DiagCtxtInner {
493493
lint_err_guars: Vec<ErrorGuaranteed>,
494494
/// The delayed bugs and their error guarantees.
495495
delayed_bugs: Vec<(DelayedDiagInner, ErrorGuaranteed)>,
496+
emitted_delayed_bug: Option<ErrorGuaranteed>,
496497

497498
/// The error count shown to the user at the end.
498499
deduplicated_err_count: usize,
@@ -622,9 +623,7 @@ impl Drop for DiagCtxtInner {
622623
// Important: it is sound to produce an `ErrorGuaranteed` when emitting
623624
// delayed bugs because they are guaranteed to be emitted here if
624625
// necessary.
625-
if self.err_guars.is_empty() {
626-
self.flush_delayed()
627-
}
626+
self.flush_delayed();
628627

629628
// Sanity check: did we use some of the expensive `trimmed_def_paths` functions
630629
// unexpectedly, that is, without producing diagnostics? If so, for debugging purposes, we
@@ -770,6 +769,7 @@ impl DiagCtxt {
770769
registry: _,
771770
err_guars,
772771
lint_err_guars,
772+
emitted_delayed_bug,
773773
delayed_bugs,
774774
deduplicated_err_count,
775775
deduplicated_warn_count,
@@ -790,6 +790,7 @@ impl DiagCtxt {
790790
// underlying memory (which `clear` would not do).
791791
*err_guars = Default::default();
792792
*lint_err_guars = Default::default();
793+
*emitted_delayed_bug = None;
793794
*delayed_bugs = Default::default();
794795
*deduplicated_err_count = 0;
795796
*deduplicated_warn_count = 0;
@@ -1421,6 +1422,7 @@ impl DiagCtxtInner {
14211422
registry: Registry::new(&[]),
14221423
err_guars: Vec::new(),
14231424
lint_err_guars: Vec::new(),
1425+
emitted_delayed_bug: None,
14241426
delayed_bugs: Vec::new(),
14251427
deduplicated_err_count: 0,
14261428
deduplicated_warn_count: 0,
@@ -1705,7 +1707,13 @@ impl DiagCtxtInner {
17051707
// eventually happened.
17061708
assert!(self.stashed_diagnostics.is_empty());
17071709

1710+
if !self.err_guars.is_empty() {
1711+
// If an error happened already. We shouldn't expose delayed bugs.
1712+
return;
1713+
}
1714+
17081715
if self.delayed_bugs.is_empty() {
1716+
// Nothing to do.
17091717
return;
17101718
}
17111719

compiler/rustc_interface/src/interface.rs

+17-14
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ use std::sync::Arc;
55
use rustc_ast::{LitKind, MetaItemKind, token};
66
use rustc_codegen_ssa::traits::CodegenBackend;
77
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
8+
use rustc_data_structures::jobserver;
89
use rustc_data_structures::stable_hasher::StableHasher;
910
use rustc_data_structures::sync::Lrc;
10-
use rustc_data_structures::{defer, jobserver};
1111
use rustc_errors::registry::Registry;
1212
use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed};
1313
use rustc_lint::LintStore;
@@ -492,21 +492,13 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
492492

493493
// There are two paths out of `f`.
494494
// - Normal exit.
495-
// - Panic, e.g. triggered by `abort_if_errors`.
495+
// - Panic, e.g. triggered by `abort_if_errors` or a fatal error.
496496
//
497497
// We must run `finish_diagnostics` in both cases.
498498
let res = {
499-
// If `f` panics, `finish_diagnostics` will run during
500-
// unwinding because of the `defer`.
501-
let sess_abort_guard = defer(|| {
502-
compiler.sess.finish_diagnostics();
503-
});
499+
let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f(&compiler)));
504500

505-
let res = f(&compiler);
506-
507-
// If `f` doesn't panic, `finish_diagnostics` will run
508-
// normally when `sess_abort_guard` is dropped.
509-
drop(sess_abort_guard);
501+
compiler.sess.finish_diagnostics();
510502

511503
// If error diagnostics have been emitted, we can't return an
512504
// error directly, because the return type of this function
@@ -515,9 +507,20 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
515507
// mistakenly think that no errors occurred and return a zero
516508
// exit code. So we abort (panic) instead, similar to if `f`
517509
// had panicked.
518-
compiler.sess.dcx().abort_if_errors();
510+
if res.is_ok() {
511+
compiler.sess.dcx().abort_if_errors();
512+
}
519513

520-
res
514+
// Also make sure to flush delayed bugs as if we panicked, the
515+
// bugs would be flushed by the Drop impl of DiagCtxt while
516+
// unwinding, which would result in an abort with
517+
// "panic in a destructor during cleanup".
518+
compiler.sess.dcx().flush_delayed();
519+
520+
match res {
521+
Ok(res) => res,
522+
Err(err) => std::panic::resume_unwind(err),
523+
}
521524
};
522525

523526
let prof = compiler.sess.prof.clone();

0 commit comments

Comments
 (0)