Skip to content

Commit 504794b

Browse files
Rollup merge of #119872 - compiler-errors:eagerly-emit-delayed-bugs, r=oli-obk,nnethercote
Give me a way to emit all the delayed bugs as errors (add `-Zeagerly-emit-delayed-bugs`) This is probably a *better* way to inspect all the delayed bugs in a program that what exists currently (and therefore makes it very easy to choose the right number `N` with `-Zemit-err-as-bug=N`, though I guess the naming is a bit ironic when you pair both of the flags together, but that feels like naming bikeshed more than anything). This pacifies my only concern with #119871 (comment), because (afaict?) that PR doesn't allow you to intercept a delayed bug's stack trace anymore, which as someone who debugs the compiler a lot, is something that I can *promise* that I do. r? `@nnethercote` or `@oli-obk`
2 parents 737452a + 7df43d3 commit 504794b

File tree

7 files changed

+112
-43
lines changed

7 files changed

+112
-43
lines changed

compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ fn source_string(file: Lrc<SourceFile>, line: &Line) -> String {
8585
/// Maps `Diagnostic::Level` to `snippet::AnnotationType`
8686
fn annotation_type_for_level(level: Level) -> AnnotationType {
8787
match level {
88-
Level::Bug | Level::DelayedBug | Level::Fatal | Level::Error => AnnotationType::Error,
88+
Level::Bug | Level::DelayedBug(_) | Level::Fatal | Level::Error => AnnotationType::Error,
8989
Level::ForceWarning(_) | Level::Warning => AnnotationType::Warning,
9090
Level::Note | Level::OnceNote => AnnotationType::Note,
9191
Level::Help | Level::OnceHelp => AnnotationType::Help,

compiler/rustc_errors/src/diagnostic.rs

+9-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::snippet::Style;
22
use crate::{
3-
CodeSuggestion, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, Level, MultiSpan,
4-
SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle,
3+
CodeSuggestion, DelayedBugKind, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, Level,
4+
MultiSpan, SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle,
55
};
66
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
77
use rustc_error_messages::fluent_value_from_str_list_sep_by_and;
@@ -243,12 +243,15 @@ impl Diagnostic {
243243

244244
pub fn is_error(&self) -> bool {
245245
match self.level {
246-
Level::Bug | Level::DelayedBug | Level::Fatal | Level::Error | Level::FailureNote => {
247-
true
248-
}
246+
Level::Bug
247+
| Level::DelayedBug(DelayedBugKind::Normal)
248+
| Level::Fatal
249+
| Level::Error
250+
| Level::FailureNote => true,
249251

250252
Level::ForceWarning(_)
251253
| Level::Warning
254+
| Level::DelayedBug(DelayedBugKind::GoodPath)
252255
| Level::Note
253256
| Level::OnceNote
254257
| Level::Help
@@ -318,7 +321,7 @@ impl Diagnostic {
318321
"downgrade_to_delayed_bug: cannot downgrade {:?} to DelayedBug: not an error",
319322
self.level
320323
);
321-
self.level = Level::DelayedBug;
324+
self.level = Level::DelayedBug(DelayedBugKind::Normal);
322325
}
323326

324327
/// Appends a labeled span to the diagnostic.

compiler/rustc_errors/src/lib.rs

+59-36
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,12 @@ fn default_track_diagnostic(diag: Diagnostic, f: &mut dyn FnMut(Diagnostic)) {
519519
pub static TRACK_DIAGNOSTIC: AtomicRef<fn(Diagnostic, &mut dyn FnMut(Diagnostic))> =
520520
AtomicRef::new(&(default_track_diagnostic as _));
521521

522+
#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug, Encodable, Decodable)]
523+
pub enum DelayedBugKind {
524+
Normal,
525+
GoodPath,
526+
}
527+
522528
#[derive(Copy, Clone, Default)]
523529
pub struct DiagCtxtFlags {
524530
/// If false, warning-level lints are suppressed.
@@ -527,6 +533,9 @@ pub struct DiagCtxtFlags {
527533
/// If Some, the Nth error-level diagnostic is upgraded to bug-level.
528534
/// (rustc: see `-Z treat-err-as-bug`)
529535
pub treat_err_as_bug: Option<NonZeroUsize>,
536+
/// Eagerly emit delayed bugs as errors, so that the compiler debugger may
537+
/// see all of the errors being emitted at once.
538+
pub eagerly_emit_delayed_bugs: bool,
530539
/// Show macro backtraces.
531540
/// (rustc: see `-Z macro-backtrace`)
532541
pub macro_backtrace: bool,
@@ -541,8 +550,7 @@ impl Drop for DiagCtxtInner {
541550
self.emit_stashed_diagnostics();
542551

543552
if !self.has_errors() {
544-
let bugs = std::mem::replace(&mut self.span_delayed_bugs, Vec::new());
545-
self.flush_delayed(bugs, "no errors encountered even though `span_delayed_bug` issued");
553+
self.flush_delayed(DelayedBugKind::Normal)
546554
}
547555

548556
// FIXME(eddyb) this explains what `good_path_delayed_bugs` are!
@@ -551,11 +559,7 @@ impl Drop for DiagCtxtInner {
551559
// lints can be `#[allow]`'d, potentially leading to this triggering.
552560
// Also, "good path" should be replaced with a better naming.
553561
if !self.has_printed && !self.suppressed_expected_diag && !std::thread::panicking() {
554-
let bugs = std::mem::replace(&mut self.good_path_delayed_bugs, Vec::new());
555-
self.flush_delayed(
556-
bugs,
557-
"no warnings or errors encountered even though `good_path_delayed_bugs` issued",
558-
);
562+
self.flush_delayed(DelayedBugKind::GoodPath);
559563
}
560564

561565
if self.check_unstable_expect_diagnostics {
@@ -865,7 +869,8 @@ impl DiagCtxt {
865869
if treat_next_err_as_bug {
866870
self.bug(msg);
867871
}
868-
DiagnosticBuilder::<ErrorGuaranteed>::new(self, DelayedBug, msg).emit()
872+
DiagnosticBuilder::<ErrorGuaranteed>::new(self, DelayedBug(DelayedBugKind::Normal), msg)
873+
.emit()
869874
}
870875

871876
/// Like `delayed_bug`, but takes an additional span.
@@ -882,16 +887,15 @@ impl DiagCtxt {
882887
if treat_next_err_as_bug {
883888
self.span_bug(sp, msg);
884889
}
885-
DiagnosticBuilder::<ErrorGuaranteed>::new(self, DelayedBug, msg).with_span(sp).emit()
890+
DiagnosticBuilder::<ErrorGuaranteed>::new(self, DelayedBug(DelayedBugKind::Normal), msg)
891+
.with_span(sp)
892+
.emit()
886893
}
887894

888895
// FIXME(eddyb) note the comment inside `impl Drop for DiagCtxtInner`, that's
889896
// where the explanation of what "good path" is (also, it should be renamed).
890897
pub fn good_path_delayed_bug(&self, msg: impl Into<DiagnosticMessage>) {
891-
let mut inner = self.inner.borrow_mut();
892-
let diagnostic = Diagnostic::new(DelayedBug, msg);
893-
let backtrace = std::backtrace::Backtrace::capture();
894-
inner.good_path_delayed_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
898+
DiagnosticBuilder::<()>::new(self, DelayedBug(DelayedBugKind::GoodPath), msg).emit()
895899
}
896900

897901
#[track_caller]
@@ -1218,9 +1222,7 @@ impl DiagCtxt {
12181222
}
12191223

12201224
pub fn flush_delayed(&self) {
1221-
let mut inner = self.inner.borrow_mut();
1222-
let bugs = std::mem::replace(&mut inner.span_delayed_bugs, Vec::new());
1223-
inner.flush_delayed(bugs, "no errors encountered even though `span_delayed_bug` issued");
1225+
self.inner.borrow_mut().flush_delayed(DelayedBugKind::Normal);
12241226
}
12251227
}
12261228

@@ -1270,17 +1272,30 @@ impl DiagCtxtInner {
12701272
return None;
12711273
}
12721274

1273-
if diagnostic.level == DelayedBug {
1274-
// FIXME(eddyb) this should check for `has_errors` and stop pushing
1275-
// once *any* errors were emitted (and truncate `span_delayed_bugs`
1276-
// when an error is first emitted, also), but maybe there's a case
1277-
// in which that's not sound? otherwise this is really inefficient.
1278-
let backtrace = std::backtrace::Backtrace::capture();
1279-
self.span_delayed_bugs
1280-
.push(DelayedDiagnostic::with_backtrace(diagnostic.clone(), backtrace));
1275+
// FIXME(eddyb) this should check for `has_errors` and stop pushing
1276+
// once *any* errors were emitted (and truncate `span_delayed_bugs`
1277+
// when an error is first emitted, also), but maybe there's a case
1278+
// in which that's not sound? otherwise this is really inefficient.
1279+
match diagnostic.level {
1280+
DelayedBug(_) if self.flags.eagerly_emit_delayed_bugs => {
1281+
diagnostic.level = Error;
1282+
}
1283+
DelayedBug(DelayedBugKind::Normal) => {
1284+
let backtrace = std::backtrace::Backtrace::capture();
1285+
self.span_delayed_bugs
1286+
.push(DelayedDiagnostic::with_backtrace(diagnostic.clone(), backtrace));
12811287

1282-
#[allow(deprecated)]
1283-
return Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
1288+
#[allow(deprecated)]
1289+
return Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
1290+
}
1291+
DelayedBug(DelayedBugKind::GoodPath) => {
1292+
let backtrace = std::backtrace::Backtrace::capture();
1293+
self.good_path_delayed_bugs
1294+
.push(DelayedDiagnostic::with_backtrace(diagnostic.clone(), backtrace));
1295+
1296+
return None;
1297+
}
1298+
_ => {}
12841299
}
12851300

12861301
if diagnostic.has_future_breakage() {
@@ -1396,11 +1411,18 @@ impl DiagCtxtInner {
13961411
self.emit_diagnostic(Diagnostic::new(FailureNote, msg));
13971412
}
13981413

1399-
fn flush_delayed(
1400-
&mut self,
1401-
bugs: Vec<DelayedDiagnostic>,
1402-
explanation: impl Into<DiagnosticMessage> + Copy,
1403-
) {
1414+
fn flush_delayed(&mut self, kind: DelayedBugKind) {
1415+
let (bugs, explanation) = match kind {
1416+
DelayedBugKind::Normal => (
1417+
std::mem::take(&mut self.span_delayed_bugs),
1418+
"no errors encountered even though `span_delayed_bug` issued",
1419+
),
1420+
DelayedBugKind::GoodPath => (
1421+
std::mem::take(&mut self.good_path_delayed_bugs),
1422+
"no warnings or errors encountered even though `good_path_delayed_bugs` issued",
1423+
),
1424+
};
1425+
14041426
if bugs.is_empty() {
14051427
return;
14061428
}
@@ -1433,7 +1455,7 @@ impl DiagCtxtInner {
14331455
if backtrace || self.ice_file.is_none() { bug.decorate() } else { bug.inner };
14341456

14351457
// "Undelay" the `DelayedBug`s (into plain `Bug`s).
1436-
if bug.level != DelayedBug {
1458+
if !matches!(bug.level, DelayedBug(_)) {
14371459
// NOTE(eddyb) not panicking here because we're already producing
14381460
// an ICE, and the more information the merrier.
14391461
bug.subdiagnostic(InvalidFlushedDelayedDiagnosticLevel {
@@ -1521,8 +1543,9 @@ pub enum Level {
15211543
/// silently dropped. I.e. "expect other errors are emitted" semantics. Useful on code paths
15221544
/// that should only be reached when compiling erroneous code.
15231545
///
1524-
/// Its `EmissionGuarantee` is `ErrorGuaranteed`.
1525-
DelayedBug,
1546+
/// Its `EmissionGuarantee` is `ErrorGuaranteed` for `Normal` delayed bugs, and `()` for
1547+
/// `GoodPath` delayed bugs.
1548+
DelayedBug(DelayedBugKind),
15261549

15271550
/// An error that causes an immediate abort. Used for things like configuration errors,
15281551
/// internal overflows, some file operation errors.
@@ -1597,7 +1620,7 @@ impl Level {
15971620
fn color(self) -> ColorSpec {
15981621
let mut spec = ColorSpec::new();
15991622
match self {
1600-
Bug | DelayedBug | Fatal | Error => {
1623+
Bug | DelayedBug(_) | Fatal | Error => {
16011624
spec.set_fg(Some(Color::Red)).set_intense(true);
16021625
}
16031626
ForceWarning(_) | Warning => {
@@ -1617,7 +1640,7 @@ impl Level {
16171640

16181641
pub fn to_str(self) -> &'static str {
16191642
match self {
1620-
Bug | DelayedBug => "error: internal compiler error",
1643+
Bug | DelayedBug(_) => "error: internal compiler error",
16211644
Fatal | Error => "error",
16221645
ForceWarning(_) | Warning => "warning",
16231646
Note | OnceNote => "note",

compiler/rustc_session/src/config.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1146,6 +1146,7 @@ impl UnstableOptions {
11461146
DiagCtxtFlags {
11471147
can_emit_warnings,
11481148
treat_err_as_bug: self.treat_err_as_bug,
1149+
eagerly_emit_delayed_bugs: self.eagerly_emit_delayed_bugs,
11491150
macro_backtrace: self.macro_backtrace,
11501151
deduplicate_diagnostics: self.deduplicate_diagnostics,
11511152
track_diagnostics: self.track_diagnostics,

compiler/rustc_session/src/options.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1583,6 +1583,9 @@ options! {
15831583
"version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
15841584
dylib_lto: bool = (false, parse_bool, [UNTRACKED],
15851585
"enables LTO for dylib crate type"),
1586+
eagerly_emit_delayed_bugs: bool = (false, parse_bool, [UNTRACKED],
1587+
"emit delayed bugs eagerly as errors instead of stashing them and emitting \
1588+
them only if an error has not been emitted"),
15861589
ehcont_guard: bool = (false, parse_bool, [TRACKED],
15871590
"generate Windows EHCont Guard tables"),
15881591
emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// compile-flags: -Zeagerly-emit-delayed-bugs
2+
3+
trait Foo {}
4+
5+
fn main() {}
6+
7+
fn f() -> impl Foo {
8+
//~^ ERROR the trait bound `i32: Foo` is not satisfied
9+
//~| ERROR `report_selection_error` did not emit an error
10+
1i32
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
error: `report_selection_error` did not emit an error
2+
--> $DIR/eagerly-emit.rs:7:11
3+
|
4+
LL | fn f() -> impl Foo {
5+
| ^^^^^^^^
6+
7+
error: trimmed_def_paths constructed but no error emitted; use `DelayDm` for lints or `with_no_trimmed_paths` for debugging
8+
9+
error[E0277]: the trait bound `i32: Foo` is not satisfied
10+
--> $DIR/eagerly-emit.rs:7:11
11+
|
12+
LL | fn f() -> impl Foo {
13+
| ^^^^^^^^ the trait `Foo` is not implemented for `i32`
14+
...
15+
LL | 1i32
16+
| ---- return type was inferred to be `i32` here
17+
|
18+
help: this trait has no implementations, consider adding one
19+
--> $DIR/eagerly-emit.rs:3:1
20+
|
21+
LL | trait Foo {}
22+
| ^^^^^^^^^
23+
24+
error: expected fulfillment errors
25+
26+
error: aborting due to 4 previous errors
27+
28+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)