@@ -428,10 +428,14 @@ pub struct DiagCtxt {
428428struct DiagCtxtInner {
429429 flags : DiagCtxtFlags ,
430430
431- /// The number of lint errors that have been emitted, including duplicates.
432- lint_err_count : usize ,
433- /// The number of non-lint errors that have been emitted, including duplicates.
434- err_count : usize ,
431+ /// The error guarantees from all emitted errors. The length gives the error count.
432+ err_guars : Vec < ErrorGuaranteed > ,
433+ /// The error guarantee from all emitted lint errors. The length gives the
434+ /// lint error count.
435+ lint_err_guars : Vec < ErrorGuaranteed > ,
436+ /// The delayed bugs and their error guarantees.
437+ delayed_bugs : Vec < ( DelayedDiagnostic , ErrorGuaranteed ) > ,
438+ good_path_delayed_bugs : Vec < DelayedDiagnostic > ,
435439
436440 /// The number of stashed errors. Unlike the other counts, this can go up
437441 /// and down, so it doesn't guarantee anything.
@@ -447,8 +451,6 @@ struct DiagCtxtInner {
447451 has_printed : bool ,
448452
449453 emitter : Box < DynEmitter > ,
450- delayed_bugs : Vec < DelayedDiagnostic > ,
451- good_path_delayed_bugs : Vec < DelayedDiagnostic > ,
452454 /// This flag indicates that an expected diagnostic was emitted and suppressed.
453455 /// This is used for the `good_path_delayed_bugs` check.
454456 suppressed_expected_diag : bool ,
@@ -560,7 +562,7 @@ impl Drop for DiagCtxtInner {
560562 fn drop ( & mut self ) {
561563 self . emit_stashed_diagnostics ( ) ;
562564
563- if ! self . has_errors ( ) {
565+ if self . err_guars . is_empty ( ) {
564566 self . flush_delayed ( DelayedBugKind :: Normal )
565567 }
566568
@@ -604,15 +606,15 @@ impl DiagCtxt {
604606 Self {
605607 inner : Lock :: new ( DiagCtxtInner {
606608 flags : DiagCtxtFlags { can_emit_warnings : true , ..Default :: default ( ) } ,
607- lint_err_count : 0 ,
608- err_count : 0 ,
609+ err_guars : Vec :: new ( ) ,
610+ lint_err_guars : Vec :: new ( ) ,
611+ delayed_bugs : Vec :: new ( ) ,
612+ good_path_delayed_bugs : Vec :: new ( ) ,
609613 stashed_err_count : 0 ,
610614 deduplicated_err_count : 0 ,
611615 deduplicated_warn_count : 0 ,
612616 has_printed : false ,
613617 emitter,
614- delayed_bugs : Vec :: new ( ) ,
615- good_path_delayed_bugs : Vec :: new ( ) ,
616618 suppressed_expected_diag : false ,
617619 taught_diagnostics : Default :: default ( ) ,
618620 emitted_diagnostic_codes : Default :: default ( ) ,
@@ -661,14 +663,14 @@ impl DiagCtxt {
661663 /// the overall count of emitted error diagnostics.
662664 pub fn reset_err_count ( & self ) {
663665 let mut inner = self . inner . borrow_mut ( ) ;
664- inner. lint_err_count = 0 ;
665- inner. err_count = 0 ;
666666 inner. stashed_err_count = 0 ;
667667 inner. deduplicated_err_count = 0 ;
668668 inner. deduplicated_warn_count = 0 ;
669669 inner. has_printed = false ;
670670
671671 // actually free the underlying memory (which `clear` would not do)
672+ inner. err_guars = Default :: default ( ) ;
673+ inner. lint_err_guars = Default :: default ( ) ;
672674 inner. delayed_bugs = Default :: default ( ) ;
673675 inner. good_path_delayed_bugs = Default :: default ( ) ;
674676 inner. taught_diagnostics = Default :: default ( ) ;
@@ -932,7 +934,7 @@ impl DiagCtxt {
932934 /// This excludes lint errors, delayed bugs, and stashed errors.
933935 #[ inline]
934936 pub fn err_count ( & self ) -> usize {
935- self . inner . borrow ( ) . err_count
937+ self . inner . borrow ( ) . err_guars . len ( )
936938 }
937939
938940 /// This excludes normal errors, lint errors and delayed bugs. Unless
@@ -946,36 +948,19 @@ impl DiagCtxt {
946948
947949 /// This excludes lint errors, delayed bugs, and stashed errors.
948950 pub fn has_errors ( & self ) -> Option < ErrorGuaranteed > {
949- self . inner . borrow ( ) . has_errors ( ) . then ( || {
950- // FIXME(nnethercote) find a way to store an `ErrorGuaranteed`.
951- #[ allow( deprecated) ]
952- ErrorGuaranteed :: unchecked_error_guaranteed ( )
953- } )
951+ self . inner . borrow ( ) . has_errors ( )
954952 }
955953
956954 /// This excludes delayed bugs and stashed errors. Unless absolutely
957955 /// necessary, prefer `has_errors` to this method.
958956 pub fn has_errors_or_lint_errors ( & self ) -> Option < ErrorGuaranteed > {
959- let inner = self . inner . borrow ( ) ;
960- let result = inner. has_errors ( ) || inner. lint_err_count > 0 ;
961- result. then ( || {
962- // FIXME(nnethercote) find a way to store an `ErrorGuaranteed`.
963- #[ allow( deprecated) ]
964- ErrorGuaranteed :: unchecked_error_guaranteed ( )
965- } )
957+ self . inner . borrow ( ) . has_errors_or_lint_errors ( )
966958 }
967959
968960 /// This excludes stashed errors. Unless absolutely necessary, prefer
969961 /// `has_errors` or `has_errors_or_lint_errors` to this method.
970962 pub fn has_errors_or_lint_errors_or_delayed_bugs ( & self ) -> Option < ErrorGuaranteed > {
971- let inner = self . inner . borrow ( ) ;
972- let result =
973- inner. has_errors ( ) || inner. lint_err_count > 0 || !inner. delayed_bugs . is_empty ( ) ;
974- result. then ( || {
975- // FIXME(nnethercote) find a way to store an `ErrorGuaranteed`.
976- #[ allow( deprecated) ]
977- ErrorGuaranteed :: unchecked_error_guaranteed ( )
978- } )
963+ self . inner . borrow ( ) . has_errors_or_lint_errors_or_delayed_bugs ( )
979964 }
980965
981966 pub fn print_error_count ( & self , registry : & Registry ) {
@@ -1055,7 +1040,7 @@ impl DiagCtxt {
10551040 pub fn abort_if_errors ( & self ) {
10561041 let mut inner = self . inner . borrow_mut ( ) ;
10571042 inner. emit_stashed_diagnostics ( ) ;
1058- if inner. has_errors ( ) {
1043+ if ! inner. err_guars . is_empty ( ) {
10591044 FatalError . raise ( ) ;
10601045 }
10611046 }
@@ -1175,8 +1160,21 @@ impl DiagCtxt {
11751160 ) {
11761161 let mut inner = self . inner . borrow_mut ( ) ;
11771162
1163+ // This "error" is an odd duck.
1164+ // - It's only produce with JSON output.
1165+ // - It's not emitted the usual way, via `emit_diagnostic`.
1166+ // - The `$message_type` field is "unused_externs" rather than the usual
1167+ // "diagnosic".
1168+ //
1169+ // We count it as a lint error because it has a lint level. The value
1170+ // of `loud` (which comes from "unused-externs" or
1171+ // "unused-externs-silent"), also affects whether it's treated like a
1172+ // hard error or not.
11781173 if loud && lint_level. is_error ( ) {
1179- inner. lint_err_count += 1 ;
1174+ // This `unchecked_error_guaranteed` is valid. It is where the
1175+ // `ErrorGuaranteed` for unused_extern errors originates.
1176+ #[ allow( deprecated) ]
1177+ inner. lint_err_guars . push ( ErrorGuaranteed :: unchecked_error_guaranteed ( ) ) ;
11801178 inner. panic_if_treat_err_as_bug ( ) ;
11811179 }
11821180
@@ -1236,7 +1234,7 @@ impl DiagCtxt {
12361234impl DiagCtxtInner {
12371235 /// Emit all stashed diagnostics.
12381236 fn emit_stashed_diagnostics ( & mut self ) {
1239- let has_errors = self . has_errors ( ) ;
1237+ let has_errors = ! self . err_guars . is_empty ( ) ;
12401238 for ( _, diag) in std:: mem:: take ( & mut self . stashed_diagnostics ) . into_iter ( ) {
12411239 // Decrement the count tracking the stash; emitting will increment it.
12421240 if diag. is_error ( ) {
@@ -1298,9 +1296,13 @@ impl DiagCtxtInner {
12981296 // when an error is first emitted, also), but maybe there's a case
12991297 // in which that's not sound? otherwise this is really inefficient.
13001298 let backtrace = std:: backtrace:: Backtrace :: capture ( ) ;
1301- self . delayed_bugs . push ( DelayedDiagnostic :: with_backtrace ( diagnostic, backtrace) ) ;
1299+ // This `unchecked_error_guaranteed` is valid. It is where the
1300+ // `ErrorGuaranteed` for delayed bugs originates.
13021301 #[ allow( deprecated) ]
1303- return Some ( ErrorGuaranteed :: unchecked_error_guaranteed ( ) ) ;
1302+ let guar = ErrorGuaranteed :: unchecked_error_guaranteed ( ) ;
1303+ self . delayed_bugs
1304+ . push ( ( DelayedDiagnostic :: with_backtrace ( diagnostic, backtrace) , guar) ) ;
1305+ return Some ( guar) ;
13041306 }
13051307 GoodPathDelayedBug => {
13061308 let backtrace = std:: backtrace:: Backtrace :: capture ( ) ;
@@ -1334,7 +1336,6 @@ impl DiagCtxtInner {
13341336 !self . emitted_diagnostics . insert ( diagnostic_hash)
13351337 } ;
13361338
1337- let level = diagnostic. level ;
13381339 let is_error = diagnostic. is_error ( ) ;
13391340 let is_lint = diagnostic. is_lint . is_some ( ) ;
13401341
@@ -1373,36 +1374,47 @@ impl DiagCtxtInner {
13731374 }
13741375
13751376 if is_error {
1377+ // This `unchecked_error_guaranteed` is valid. It is where the
1378+ // `ErrorGuaranteed` for errors and lint errors originates.
1379+ #[ allow( deprecated) ]
1380+ let guar = ErrorGuaranteed :: unchecked_error_guaranteed ( ) ;
1381+ guaranteed = Some ( guar) ;
13761382 if is_lint {
1377- self . lint_err_count += 1 ;
1383+ self . lint_err_guars . push ( guar ) ;
13781384 } else {
1379- self . err_count += 1 ;
1385+ self . err_guars . push ( guar ) ;
13801386 }
13811387 self . panic_if_treat_err_as_bug ( ) ;
13821388 }
1383-
1384- #[ allow( deprecated) ]
1385- if level == Level :: Error {
1386- guaranteed = Some ( ErrorGuaranteed :: unchecked_error_guaranteed ( ) ) ;
1387- }
13881389 } ) ;
13891390
13901391 guaranteed
13911392 }
13921393
13931394 fn treat_err_as_bug ( & self ) -> bool {
1394- self . flags . treat_err_as_bug . is_some_and ( |c| self . err_count + self . lint_err_count >= c. get ( ) )
1395+ self . flags
1396+ . treat_err_as_bug
1397+ . is_some_and ( |c| self . err_guars . len ( ) + self . lint_err_guars . len ( ) >= c. get ( ) )
13951398 }
13961399
13971400 // Use this one before incrementing `err_count`.
13981401 fn treat_next_err_as_bug ( & self ) -> bool {
13991402 self . flags
14001403 . treat_err_as_bug
1401- . is_some_and ( |c| self . err_count + self . lint_err_count + 1 >= c. get ( ) )
1404+ . is_some_and ( |c| self . err_guars . len ( ) + self . lint_err_guars . len ( ) + 1 >= c. get ( ) )
1405+ }
1406+
1407+ fn has_errors ( & self ) -> Option < ErrorGuaranteed > {
1408+ self . err_guars . get ( 0 ) . copied ( )
1409+ }
1410+
1411+ fn has_errors_or_lint_errors ( & self ) -> Option < ErrorGuaranteed > {
1412+ self . has_errors ( ) . or_else ( || self . lint_err_guars . get ( 0 ) . copied ( ) )
14021413 }
14031414
1404- fn has_errors ( & self ) -> bool {
1405- self . err_count > 0
1415+ fn has_errors_or_lint_errors_or_delayed_bugs ( & self ) -> Option < ErrorGuaranteed > {
1416+ self . has_errors_or_lint_errors ( )
1417+ . or_else ( || self . delayed_bugs . get ( 0 ) . map ( |( _, guar) | guar) . copied ( ) )
14061418 }
14071419
14081420 fn failure_note ( & mut self , msg : impl Into < DiagnosticMessage > ) {
@@ -1412,7 +1424,7 @@ impl DiagCtxtInner {
14121424 fn flush_delayed ( & mut self , kind : DelayedBugKind ) {
14131425 let ( bugs, note1) = match kind {
14141426 DelayedBugKind :: Normal => (
1415- std:: mem:: take ( & mut self . delayed_bugs ) ,
1427+ std:: mem:: take ( & mut self . delayed_bugs ) . into_iter ( ) . map ( | ( b , _ ) | b ) . collect ( ) ,
14161428 "no errors encountered even though delayed bugs were created" ,
14171429 ) ,
14181430 DelayedBugKind :: GoodPath => (
@@ -1477,7 +1489,7 @@ impl DiagCtxtInner {
14771489 fn panic_if_treat_err_as_bug ( & self ) {
14781490 if self . treat_err_as_bug ( ) {
14791491 let n = self . flags . treat_err_as_bug . map ( |c| c. get ( ) ) . unwrap ( ) ;
1480- assert_eq ! ( n, self . err_count + self . lint_err_count ) ;
1492+ assert_eq ! ( n, self . err_guars . len ( ) + self . lint_err_guars . len ( ) ) ;
14811493 if n == 1 {
14821494 panic ! ( "aborting due to `-Z treat-err-as-bug=1`" ) ;
14831495 } else {
0 commit comments