@@ -519,6 +519,12 @@ fn default_track_diagnostic(diag: Diagnostic, f: &mut dyn FnMut(Diagnostic)) {
519519pub 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 ) ]
523529pub 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" ,
0 commit comments