@@ -519,6 +519,12 @@ fn default_track_diagnostic(diag: Diagnostic, f: &mut dyn FnMut(Diagnostic)) {
519
519
pub static TRACK_DIAGNOSTIC : AtomicRef < fn ( Diagnostic , & mut dyn FnMut ( Diagnostic ) ) > =
520
520
AtomicRef :: new ( & ( default_track_diagnostic as _ ) ) ;
521
521
522
+ #[ derive( Copy , PartialEq , Eq , Clone , Hash , Debug , Encodable , Decodable ) ]
523
+ pub enum DelayedBugKind {
524
+ Normal ,
525
+ GoodPath ,
526
+ }
527
+
522
528
#[ derive( Copy , Clone , Default ) ]
523
529
pub struct DiagCtxtFlags {
524
530
/// If false, warning-level lints are suppressed.
@@ -527,6 +533,9 @@ pub struct DiagCtxtFlags {
527
533
/// If Some, the Nth error-level diagnostic is upgraded to bug-level.
528
534
/// (rustc: see `-Z treat-err-as-bug`)
529
535
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 ,
530
539
/// Show macro backtraces.
531
540
/// (rustc: see `-Z macro-backtrace`)
532
541
pub macro_backtrace : bool ,
@@ -541,8 +550,7 @@ impl Drop for DiagCtxtInner {
541
550
self . emit_stashed_diagnostics ( ) ;
542
551
543
552
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 )
546
554
}
547
555
548
556
// FIXME(eddyb) this explains what `good_path_delayed_bugs` are!
@@ -551,11 +559,7 @@ impl Drop for DiagCtxtInner {
551
559
// lints can be `#[allow]`'d, potentially leading to this triggering.
552
560
// Also, "good path" should be replaced with a better naming.
553
561
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 ) ;
559
563
}
560
564
561
565
if self . check_unstable_expect_diagnostics {
@@ -865,7 +869,8 @@ impl DiagCtxt {
865
869
if treat_next_err_as_bug {
866
870
self . bug ( msg) ;
867
871
}
868
- DiagnosticBuilder :: < ErrorGuaranteed > :: new ( self , DelayedBug , msg) . emit ( )
872
+ DiagnosticBuilder :: < ErrorGuaranteed > :: new ( self , DelayedBug ( DelayedBugKind :: Normal ) , msg)
873
+ . emit ( )
869
874
}
870
875
871
876
/// Like `delayed_bug`, but takes an additional span.
@@ -882,16 +887,15 @@ impl DiagCtxt {
882
887
if treat_next_err_as_bug {
883
888
self . span_bug ( sp, msg) ;
884
889
}
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 ( )
886
893
}
887
894
888
895
// FIXME(eddyb) note the comment inside `impl Drop for DiagCtxtInner`, that's
889
896
// where the explanation of what "good path" is (also, it should be renamed).
890
897
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 ( )
895
899
}
896
900
897
901
#[ track_caller]
@@ -1218,9 +1222,7 @@ impl DiagCtxt {
1218
1222
}
1219
1223
1220
1224
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 ) ;
1224
1226
}
1225
1227
}
1226
1228
@@ -1270,17 +1272,30 @@ impl DiagCtxtInner {
1270
1272
return None ;
1271
1273
}
1272
1274
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) ) ;
1281
1287
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
+ _ => { }
1284
1299
}
1285
1300
1286
1301
if diagnostic. has_future_breakage ( ) {
@@ -1396,11 +1411,18 @@ impl DiagCtxtInner {
1396
1411
self . emit_diagnostic ( Diagnostic :: new ( FailureNote , msg) ) ;
1397
1412
}
1398
1413
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
+
1404
1426
if bugs. is_empty ( ) {
1405
1427
return ;
1406
1428
}
@@ -1433,7 +1455,7 @@ impl DiagCtxtInner {
1433
1455
if backtrace || self . ice_file . is_none ( ) { bug. decorate ( ) } else { bug. inner } ;
1434
1456
1435
1457
// "Undelay" the `DelayedBug`s (into plain `Bug`s).
1436
- if bug. level != DelayedBug {
1458
+ if ! matches ! ( bug. level, DelayedBug ( _ ) ) {
1437
1459
// NOTE(eddyb) not panicking here because we're already producing
1438
1460
// an ICE, and the more information the merrier.
1439
1461
bug. subdiagnostic ( InvalidFlushedDelayedDiagnosticLevel {
@@ -1521,8 +1543,9 @@ pub enum Level {
1521
1543
/// silently dropped. I.e. "expect other errors are emitted" semantics. Useful on code paths
1522
1544
/// that should only be reached when compiling erroneous code.
1523
1545
///
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 ) ,
1526
1549
1527
1550
/// An error that causes an immediate abort. Used for things like configuration errors,
1528
1551
/// internal overflows, some file operation errors.
@@ -1597,7 +1620,7 @@ impl Level {
1597
1620
fn color ( self ) -> ColorSpec {
1598
1621
let mut spec = ColorSpec :: new ( ) ;
1599
1622
match self {
1600
- Bug | DelayedBug | Fatal | Error => {
1623
+ Bug | DelayedBug ( _ ) | Fatal | Error => {
1601
1624
spec. set_fg ( Some ( Color :: Red ) ) . set_intense ( true ) ;
1602
1625
}
1603
1626
ForceWarning ( _) | Warning => {
@@ -1617,7 +1640,7 @@ impl Level {
1617
1640
1618
1641
pub fn to_str ( self ) -> & ' static str {
1619
1642
match self {
1620
- Bug | DelayedBug => "error: internal compiler error" ,
1643
+ Bug | DelayedBug ( _ ) => "error: internal compiler error" ,
1621
1644
Fatal | Error => "error" ,
1622
1645
ForceWarning ( _) | Warning => "warning" ,
1623
1646
Note | OnceNote => "note" ,
0 commit comments