Skip to content

Commit bb88be9

Browse files
committed
[stable-mir failure] XXX: stashed fixes
The remove error counts in the ones with delayed bugs: because we no longer flush delayed bugs in `codegen_and_link` (do that in a precursor?) --- Require explicit calls to `emit_stashed_diagnostic`. `DiagCtxtInner::drop` will emit any remaining stashed diagnostics. But we also have explicit calls to `emit_stashed_diagnostics` in several places. All this makes it difficult to understand where the responsibility for emitting stashed diagnostics lies. As it happens, the call in `DiagCtxtInner::drop` isn't necessary. So this commit replaces that call with an assertion that there are no stashed diagnostics left. This makes things clearer. In particular, numerous `DiagCtxt`s are created during compilation, but stashing/stealing only occurs in the main one, which is the one used for `print_error_count`.
1 parent f74d5aa commit bb88be9

File tree

9 files changed

+73
-42
lines changed

9 files changed

+73
-42
lines changed

compiler/rustc_errors/src/lib.rs

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -476,9 +476,10 @@ struct DiagCtxtInner {
476476
emitted_diagnostics: FxHashSet<Hash128>,
477477

478478
/// Stashed diagnostics emitted in one stage of the compiler that may be
479-
/// stolen by other stages (e.g. to improve them and add more information).
480-
/// The stashed diagnostics count towards the total error count.
481-
/// When `.abort_if_errors()` is called, these are also emitted.
479+
/// stolen and emitted/cancelled by other stages (e.g. to improve them and
480+
/// add more information). All stashed diagnostics must be emitted with
481+
/// `emit_stashed_diagnostics` by the time the `DiagCtxtInner` is dropped,
482+
/// otherwise an assertion failure will occur.
482483
stashed_diagnostics: FxIndexMap<(Span, StashKey), Diagnostic>,
483484

484485
future_breakage_diagnostics: Vec<Diagnostic>,
@@ -563,7 +564,9 @@ pub struct DiagCtxtFlags {
563564

564565
impl Drop for DiagCtxtInner {
565566
fn drop(&mut self) {
566-
self.emit_stashed_diagnostics();
567+
// Any stashed diagnostics should have been handled by
568+
// `emit_stashed_diagnostics` by now.
569+
assert!(self.stashed_diagnostics.is_empty());
567570

568571
if self.err_guars.is_empty() {
569572
self.flush_delayed()
@@ -755,7 +758,7 @@ impl DiagCtxt {
755758
}
756759

757760
/// Emit all stashed diagnostics.
758-
pub fn emit_stashed_diagnostics(&self) {
761+
pub fn emit_stashed_diagnostics(&self) -> Option<ErrorGuaranteed> {
759762
self.inner.borrow_mut().emit_stashed_diagnostics()
760763
}
761764

@@ -801,8 +804,6 @@ impl DiagCtxt {
801804
pub fn print_error_count(&self, registry: &Registry) {
802805
let mut inner = self.inner.borrow_mut();
803806

804-
inner.emit_stashed_diagnostics();
805-
806807
if inner.treat_err_as_bug() {
807808
return;
808809
}
@@ -877,9 +878,7 @@ impl DiagCtxt {
877878
}
878879

879880
pub fn abort_if_errors(&self) {
880-
let mut inner = self.inner.borrow_mut();
881-
inner.emit_stashed_diagnostics();
882-
if !inner.err_guars.is_empty() {
881+
if self.has_errors().is_some() {
883882
FatalError.raise();
884883
}
885884
}
@@ -1280,7 +1279,8 @@ impl DiagCtxt {
12801279
// `DiagCtxtInner::foo`.
12811280
impl DiagCtxtInner {
12821281
/// Emit all stashed diagnostics.
1283-
fn emit_stashed_diagnostics(&mut self) {
1282+
fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
1283+
let mut guar = None;
12841284
let has_errors = !self.err_guars.is_empty();
12851285
for (_, diag) in std::mem::take(&mut self.stashed_diagnostics).into_iter() {
12861286
if diag.is_error() {
@@ -1295,8 +1295,9 @@ impl DiagCtxtInner {
12951295
continue;
12961296
}
12971297
}
1298-
self.emit_diagnostic(diag);
1298+
guar = guar.or(self.emit_diagnostic(diag));
12991299
}
1300+
guar
13001301
}
13011302

13021303
// Return value is only `Some` if the level is `Error` or `DelayedBug`.
@@ -1489,6 +1490,11 @@ impl DiagCtxtInner {
14891490
}
14901491

14911492
fn flush_delayed(&mut self) {
1493+
// Stashed diagnostics must be emitted before delayed bugs are flushed.
1494+
// Otherwise, we might ICE prematurely when errors would have
1495+
// eventually happened.
1496+
assert!(self.stashed_diagnostics.is_empty());
1497+
14921498
if self.delayed_bugs.is_empty() {
14931499
return;
14941500
}

compiler/rustc_interface/src/interface.rs

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -423,18 +423,43 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
423423
Compiler { sess, codegen_backend, override_queries: config.override_queries };
424424

425425
rustc_span::set_source_map(compiler.sess.parse_sess.clone_source_map(), move || {
426-
let r = {
427-
let _sess_abort_error = defer(|| {
428-
compiler.sess.finish_diagnostics(&config.registry);
426+
// There are two paths out of `f`.
427+
// - Normal exit.
428+
// - Panic, e.g. triggered by `abort_if_errors`.
429+
//
430+
// We must run `finish_diagnostics` in both cases.
431+
let res = {
432+
// If `f` panics, `finish_diagnostics` will run during
433+
// unwinding because of the `defer`.
434+
let mut guar = None;
435+
let sess_abort_guard = defer(|| {
436+
guar = compiler.sess.finish_diagnostics(&config.registry);
429437
});
430438

431-
f(&compiler)
439+
let res = f(&compiler);
440+
441+
// If `f` doesn't panic, `finish_diagnostics` will run
442+
// normally when `sess_abort_guard` is dropped.
443+
drop(sess_abort_guard);
444+
445+
// If `finish_diagnostics` emits errors (e.g. stashed
446+
// errors) we can't return an error directly, because the
447+
// return type of this function is `R`, not `Result<R, E>`.
448+
// But we need to communicate the errors' existence to the
449+
// caller, otherwise the caller might mistakenly think that
450+
// no errors occurred and return a zero exit code. So we
451+
// abort (panic) instead, similar to if `f` had panicked.
452+
if guar.is_some() {
453+
compiler.sess.dcx().abort_if_errors();
454+
}
455+
456+
res
432457
};
433458

434459
let prof = compiler.sess.prof.clone();
435-
436460
prof.generic_activity("drop_compiler").run(move || drop(compiler));
437-
r
461+
462+
res
438463
})
439464
},
440465
)

compiler/rustc_interface/src/passes.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -772,12 +772,11 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
772772
// lot of annoying errors in the ui tests (basically,
773773
// lint warnings and so on -- kindck used to do this abort, but
774774
// kindck is gone now). -nmatsakis
775-
if let Some(reported) = sess.dcx().has_errors_excluding_lint_errors() {
776-
return Err(reported);
777-
} else if sess.dcx().stashed_err_count() > 0 {
778-
// Without this case we sometimes get delayed bug ICEs and I don't
779-
// understand why. -nnethercote
780-
return Err(sess.dcx().delayed_bug("some stashed error is waiting for use"));
775+
//
776+
// But we exclude lint errors from this, because lint errors are typically
777+
// less serious and we're more likely to want to continue (#87337).
778+
if let Some(guar) = sess.dcx().has_errors_excluding_lint_errors() {
779+
return Err(guar);
781780
}
782781

783782
sess.time("misc_checking_3", || {

compiler/rustc_interface/src/queries.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -222,12 +222,12 @@ impl<'tcx> Queries<'tcx> {
222222

223223
pub fn codegen_and_build_linker(&'tcx self) -> Result<Linker> {
224224
self.global_ctxt()?.enter(|tcx| {
225-
// Don't do code generation if there were any errors
226-
self.compiler.sess.compile_status()?;
227-
228-
// If we have any delayed bugs, for example because we created TyKind::Error earlier,
229-
// it's likely that codegen will only cause more ICEs, obscuring the original problem
230-
self.compiler.sess.dcx().flush_delayed();
225+
// Don't do code generation if there were any errors. Likewise if
226+
// there were any delayed bugs, because codegen will likely cause
227+
// more ICEs, obscuring the original problem.
228+
if let Some(guar) = self.compiler.sess.dcx().has_errors_or_delayed_bugs() {
229+
return Err(guar);
230+
}
231231

232232
// Hook for UI tests.
233233
Self::check_for_rustc_errors_attr(tcx);

compiler/rustc_passes/src/dead.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
237237
) {
238238
let variant = match self.typeck_results().node_type(lhs.hir_id).kind() {
239239
ty::Adt(adt, _) => adt.variant_of_res(res),
240-
_ => span_bug!(lhs.span, "non-ADT in tuple struct pattern"),
240+
_ => {
241+
self.tcx.dcx().span_delayed_bug(lhs.span, "non-ADT in tuple struct pattern");
242+
return;
243+
}
241244
};
242245
let dotdot = dotdot.as_opt_usize().unwrap_or(pats.len());
243246
let first_n = pats.iter().enumerate().take(dotdot);

compiler/rustc_session/src/session.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,8 @@ impl Session {
258258
}
259259
}
260260

261-
fn check_miri_unleashed_features(&self) {
261+
fn check_miri_unleashed_features(&self) -> Option<ErrorGuaranteed> {
262+
let mut guar = None;
262263
let unleashed_features = self.miri_unleashed_features.lock();
263264
if !unleashed_features.is_empty() {
264265
let mut must_err = false;
@@ -279,18 +280,22 @@ impl Session {
279280
// If we should err, make sure we did.
280281
if must_err && self.dcx().has_errors().is_none() {
281282
// We have skipped a feature gate, and not run into other errors... reject.
282-
self.dcx().emit_err(errors::NotCircumventFeature);
283+
guar = Some(self.dcx().emit_err(errors::NotCircumventFeature));
283284
}
284285
}
286+
guar
285287
}
286288

287289
/// Invoked all the way at the end to finish off diagnostics printing.
288-
pub fn finish_diagnostics(&self, registry: &Registry) {
289-
self.check_miri_unleashed_features();
290+
pub fn finish_diagnostics(&self, registry: &Registry) -> Option<ErrorGuaranteed> {
291+
let mut guar = None;
292+
guar = guar.or(self.check_miri_unleashed_features());
293+
guar = guar.or(self.dcx().emit_stashed_diagnostics());
290294
self.dcx().print_error_count(registry);
291295
if self.opts.json_future_incompat {
292296
self.dcx().emit_future_breakage_report();
293297
}
298+
guar
294299
}
295300

296301
/// Returns true if the crate is a testing one.
@@ -314,7 +319,6 @@ impl Session {
314319

315320
pub fn compile_status(&self) -> Result<(), ErrorGuaranteed> {
316321
if let Some(reported) = self.dcx().has_errors() {
317-
self.dcx().emit_stashed_diagnostics();
318322
Err(reported)
319323
} else {
320324
Ok(())

tests/ui/impl-trait/equality-in-canonical-query.clone.stderr

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,3 @@ LL | same_output(foo, rpit);
2121

2222
query stack during panic:
2323
end of query stack
24-
error: aborting due to 2 previous errors
25-

tests/ui/inference/issue-80409.no-compat.stderr

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,3 @@ error: internal compiler error: error performing ParamEnvAnd { param_env: ParamE
22
|
33
= query stack during panic:
44
end of query stack
5-
error: aborting due to 1 previous error
6-

tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,3 @@ LL | query(get_rpit);
2121

2222
query stack during panic:
2323
end of query stack
24-
error: aborting due to 2 previous errors
25-

0 commit comments

Comments
 (0)