Rollup merge of #121015 - nnethercote:opt-delayed-bug, r=oli-obk

Optimize `delayed_bug` handling.

Once we have emitted at least one error, delayed bugs won't be used. So we can (a) we can (a) discard any existing delayed bugs, and (b) stop recording any new delayed bugs.

This eliminates a longstanding `FIXME` comment. There should be no soundness issues because it's not possible to un-emit an error.

r? `@oli-obk`
This commit is contained in:
Oli Scherer 2024-02-14 11:53:40 +01:00 committed by GitHub
commit bad2cb08de
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1315,6 +1315,9 @@ impl DiagCtxtInner {
self.future_breakage_diagnostics.push(diagnostic.clone()); self.future_breakage_diagnostics.push(diagnostic.clone());
} }
// Note that because this comes before the `match` below,
// `-Zeagerly-emit-delayed-bugs` continues to work even after we've
// issued an error and stopped recording new delayed bugs.
if diagnostic.level == DelayedBug && self.flags.eagerly_emit_delayed_bugs { if diagnostic.level == DelayedBug && self.flags.eagerly_emit_delayed_bugs {
diagnostic.level = Error; diagnostic.level = Error;
} }
@ -1326,10 +1329,11 @@ impl DiagCtxtInner {
diagnostic.level = Bug; diagnostic.level = Bug;
} }
DelayedBug => { DelayedBug => {
// FIXME(eddyb) this should check for `has_errors` and stop pushing // If we have already emitted at least one error, we don't need
// once *any* errors were emitted (and truncate `delayed_bugs` // to record the delayed bug, because it'll never be used.
// when an error is first emitted, also), but maybe there's a case return if let Some(guar) = self.has_errors_or_lint_errors() {
// in which that's not sound? otherwise this is really inefficient. Some(guar)
} else {
let backtrace = std::backtrace::Backtrace::capture(); let backtrace = std::backtrace::Backtrace::capture();
// This `unchecked_error_guaranteed` is valid. It is where the // This `unchecked_error_guaranteed` is valid. It is where the
// `ErrorGuaranteed` for delayed bugs originates. // `ErrorGuaranteed` for delayed bugs originates.
@ -1337,7 +1341,8 @@ impl DiagCtxtInner {
let guar = ErrorGuaranteed::unchecked_error_guaranteed(); let guar = ErrorGuaranteed::unchecked_error_guaranteed();
self.delayed_bugs self.delayed_bugs
.push((DelayedDiagnostic::with_backtrace(diagnostic, backtrace), guar)); .push((DelayedDiagnostic::with_backtrace(diagnostic, backtrace), guar));
return Some(guar); Some(guar)
};
} }
Warning if !self.flags.can_emit_warnings => { Warning if !self.flags.can_emit_warnings => {
if diagnostic.has_future_breakage() { if diagnostic.has_future_breakage() {
@ -1403,6 +1408,16 @@ impl DiagCtxtInner {
} }
if is_error { if is_error {
// If we have any delayed bugs recorded, we can discard them
// because they won't be used. (This should only occur if there
// have been no errors previously emitted, because we don't add
// new delayed bugs once the first error is emitted.)
if !self.delayed_bugs.is_empty() {
assert_eq!(self.lint_err_guars.len() + self.err_guars.len(), 0);
self.delayed_bugs.clear();
self.delayed_bugs.shrink_to_fit();
}
// This `unchecked_error_guaranteed` is valid. It is where the // This `unchecked_error_guaranteed` is valid. It is where the
// `ErrorGuaranteed` for errors and lint errors originates. // `ErrorGuaranteed` for errors and lint errors originates.
#[allow(deprecated)] #[allow(deprecated)]