1
Fork 0

Don't consider delayed bugs for -Ztreat-err-as-bug.

`-Ztreat-err-as-bug` treats normal errors and delayed bugs equally,
which can lead to some really surprising results.

This commit changes `-Ztreat-err-as-bug` so it ignores delayed bugs,
unless they get promoted to proper bugs and are printed.

This feels to me much simpler and more logical. And it simplifies the
implementation:
- The `-Ztreat-err-as-bug` check is removed from in
  `DiagCtxt::{delayed_bug,span_delayed_bug}`.
- `treat_err_as_bug` doesn't need to count delayed bugs.
- The `-Ztreat-err-as-bug` panic message is simpler, because it doesn't
  have to mention delayed bugs.

Output of delayed bugs is now more consistent. They're always printed
the same way. Previously when they triggered `-Ztreat-err-as-bug` they
would be printed slightly differently, via `span_bug` in
`span_delayed_bug` or `delayed_bug`.

A minor behaviour change: the "no errors encountered even though
`span_delayed_bug` issued" printed before delayed bugs is now a note
rather than a bug. This is done so it doesn't get counted as an error
that might trigger `-Ztreat-err-as-bug`, which would be silly.
This means that if you use `-Ztreat-err-as-bug=1` and there are no
normal errors but there are delayed bugs, the first delayed bug will be
shown (and the panic will happen after it's printed).

Also, I have added a second note saying "those delayed bugs will now be
shown as internal compiler errors". I think this makes it clearer what
is happening, because the whole concept of delayed bugs is non-obvious.

There are some test changes.
- equality-in-canonical-query.rs: Minor output changes, and the error
  count reduces by one because the "no errors encountered even though
  `span_delayed_bug` issued" message is no longer counted as an error.
- rpit_tait_equality_in_canonical_query.rs: Ditto.
- storage-live.rs: The query stack disappears because these delayed bugs
  are now printed at the end, rather than when they are created.
- storage-return.rs, span_delayed_bug.rs: now need
  `-Zeagerly-emit-delayed-bugs` because they need the delayed bugs
  emitted immediately to preserve behaviour.
This commit is contained in:
Nicholas Nethercote 2024-01-12 07:38:42 +11:00
parent 2319be8e26
commit f1ac54123f
8 changed files with 51 additions and 68 deletions

View file

@ -865,10 +865,6 @@ impl DiagCtxt {
/// directly).
#[track_caller]
pub fn delayed_bug(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
let treat_next_err_as_bug = self.inner.borrow().treat_next_err_as_bug();
if treat_next_err_as_bug {
self.bug(msg);
}
DiagnosticBuilder::<ErrorGuaranteed>::new(self, DelayedBug(DelayedBugKind::Normal), msg)
.emit()
}
@ -883,10 +879,6 @@ impl DiagCtxt {
sp: impl Into<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
) -> ErrorGuaranteed {
let treat_next_err_as_bug = self.inner.borrow().treat_next_err_as_bug();
if treat_next_err_as_bug {
self.span_bug(sp, msg);
}
DiagnosticBuilder::<ErrorGuaranteed>::new(self, DelayedBug(DelayedBugKind::Normal), msg)
.with_span(sp)
.emit()
@ -1259,10 +1251,6 @@ impl DiagCtxtInner {
}
fn emit_diagnostic(&mut self, mut diagnostic: Diagnostic) -> Option<ErrorGuaranteed> {
if matches!(diagnostic.level, Error | Fatal) && self.treat_next_err_as_bug() {
diagnostic.level = Bug;
}
// The `LintExpectationId` can be stable or unstable depending on when it was created.
// Diagnostics created before the definition of `HirId`s are unstable and can not yet
// be stored. Instead, they are buffered until the `LintExpectationId` is replaced by
@ -1298,6 +1286,12 @@ impl DiagCtxtInner {
_ => {}
}
// This must come after the possible promotion of `DelayedBug` to
// `Error` above.
if matches!(diagnostic.level, Error | Fatal) && self.treat_next_err_as_bug() {
diagnostic.level = Bug;
}
if diagnostic.has_future_breakage() {
// Future breakages aren't emitted if they're Level::Allow,
// but they still need to be constructed and stashed below,
@ -1387,20 +1381,14 @@ impl DiagCtxtInner {
}
fn treat_err_as_bug(&self) -> bool {
self.flags.treat_err_as_bug.is_some_and(|c| {
self.err_count + self.lint_err_count + self.delayed_bug_count() >= c.get()
})
self.flags.treat_err_as_bug.is_some_and(|c| self.err_count + self.lint_err_count >= c.get())
}
// Use this one before incrementing `err_count`.
fn treat_next_err_as_bug(&self) -> bool {
self.flags.treat_err_as_bug.is_some_and(|c| {
self.err_count + self.lint_err_count + self.delayed_bug_count() + 1 >= c.get()
})
}
fn delayed_bug_count(&self) -> usize {
self.span_delayed_bugs.len() + self.good_path_delayed_bugs.len()
self.flags
.treat_err_as_bug
.is_some_and(|c| self.err_count + self.lint_err_count + 1 >= c.get())
}
fn has_errors(&self) -> bool {
@ -1412,7 +1400,7 @@ impl DiagCtxtInner {
}
fn flush_delayed(&mut self, kind: DelayedBugKind) {
let (bugs, explanation) = match kind {
let (bugs, note1) = match kind {
DelayedBugKind::Normal => (
std::mem::take(&mut self.span_delayed_bugs),
"no errors encountered even though `span_delayed_bug` issued",
@ -1422,6 +1410,7 @@ impl DiagCtxtInner {
"no warnings or errors encountered even though `good_path_delayed_bugs` issued",
),
};
let note2 = "those delayed bugs will now be shown as internal compiler errors";
if bugs.is_empty() {
return;
@ -1447,8 +1436,11 @@ impl DiagCtxtInner {
if i == 0 {
// Put the overall explanation before the `DelayedBug`s, to
// frame them better (e.g. separate warnings from them).
self.emit_diagnostic(Diagnostic::new(Bug, explanation));
// frame them better (e.g. separate warnings from them). Also,
// make it a note so it doesn't count as an error, because that
// could trigger `-Ztreat-err-as-bug`, which we don't want.
self.emit_diagnostic(Diagnostic::new(Note, note1));
self.emit_diagnostic(Diagnostic::new(Note, note2));
}
let mut bug =
@ -1474,22 +1466,12 @@ impl DiagCtxtInner {
fn panic_if_treat_err_as_bug(&self) {
if self.treat_err_as_bug() {
match (
self.err_count + self.lint_err_count,
self.delayed_bug_count(),
self.flags.treat_err_as_bug.map(|c| c.get()).unwrap(),
) {
(1, 0, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"),
(0, 1, 1) => panic!("aborting due delayed bug with `-Z treat-err-as-bug=1`"),
(count, delayed_count, val) => {
if delayed_count > 0 {
panic!(
"aborting after {count} errors and {delayed_count} delayed bugs due to `-Z treat-err-as-bug={val}`",
)
} else {
panic!("aborting after {count} errors due to `-Z treat-err-as-bug={val}`")
}
}
let n = self.flags.treat_err_as_bug.map(|c| c.get()).unwrap();
assert_eq!(n, self.err_count + self.lint_err_count);
if n == 1 {
panic!("aborting due to `-Z treat-err-as-bug=1`");
} else {
panic!("aborting after {n} errors due to `-Z treat-err-as-bug={n}`");
}
}
}