@@ -428,10 +428,14 @@ pub struct DiagCtxt {
428
428
struct DiagCtxtInner {
429
429
flags : DiagCtxtFlags ,
430
430
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 > ,
435
439
436
440
/// The number of stashed errors. Unlike the other counts, this can go up
437
441
/// and down, so it doesn't guarantee anything.
@@ -447,8 +451,6 @@ struct DiagCtxtInner {
447
451
has_printed : bool ,
448
452
449
453
emitter : Box < DynEmitter > ,
450
- delayed_bugs : Vec < DelayedDiagnostic > ,
451
- good_path_delayed_bugs : Vec < DelayedDiagnostic > ,
452
454
/// This flag indicates that an expected diagnostic was emitted and suppressed.
453
455
/// This is used for the `good_path_delayed_bugs` check.
454
456
suppressed_expected_diag : bool ,
@@ -560,7 +562,7 @@ impl Drop for DiagCtxtInner {
560
562
fn drop ( & mut self ) {
561
563
self . emit_stashed_diagnostics ( ) ;
562
564
563
- if ! self . has_errors ( ) {
565
+ if self . err_guars . is_empty ( ) {
564
566
self . flush_delayed ( DelayedBugKind :: Normal )
565
567
}
566
568
@@ -604,15 +606,15 @@ impl DiagCtxt {
604
606
Self {
605
607
inner : Lock :: new ( DiagCtxtInner {
606
608
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 ( ) ,
609
613
stashed_err_count : 0 ,
610
614
deduplicated_err_count : 0 ,
611
615
deduplicated_warn_count : 0 ,
612
616
has_printed : false ,
613
617
emitter,
614
- delayed_bugs : Vec :: new ( ) ,
615
- good_path_delayed_bugs : Vec :: new ( ) ,
616
618
suppressed_expected_diag : false ,
617
619
taught_diagnostics : Default :: default ( ) ,
618
620
emitted_diagnostic_codes : Default :: default ( ) ,
@@ -661,14 +663,14 @@ impl DiagCtxt {
661
663
/// the overall count of emitted error diagnostics.
662
664
pub fn reset_err_count ( & self ) {
663
665
let mut inner = self . inner . borrow_mut ( ) ;
664
- inner. lint_err_count = 0 ;
665
- inner. err_count = 0 ;
666
666
inner. stashed_err_count = 0 ;
667
667
inner. deduplicated_err_count = 0 ;
668
668
inner. deduplicated_warn_count = 0 ;
669
669
inner. has_printed = false ;
670
670
671
671
// actually free the underlying memory (which `clear` would not do)
672
+ inner. err_guars = Default :: default ( ) ;
673
+ inner. lint_err_guars = Default :: default ( ) ;
672
674
inner. delayed_bugs = Default :: default ( ) ;
673
675
inner. good_path_delayed_bugs = Default :: default ( ) ;
674
676
inner. taught_diagnostics = Default :: default ( ) ;
@@ -932,7 +934,7 @@ impl DiagCtxt {
932
934
/// This excludes lint errors, delayed bugs, and stashed errors.
933
935
#[ inline]
934
936
pub fn err_count ( & self ) -> usize {
935
- self . inner . borrow ( ) . err_count
937
+ self . inner . borrow ( ) . err_guars . len ( )
936
938
}
937
939
938
940
/// This excludes normal errors, lint errors and delayed bugs. Unless
@@ -946,36 +948,19 @@ impl DiagCtxt {
946
948
947
949
/// This excludes lint errors, delayed bugs, and stashed errors.
948
950
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 ( )
954
952
}
955
953
956
954
/// This excludes delayed bugs and stashed errors. Unless absolutely
957
955
/// necessary, prefer `has_errors` to this method.
958
956
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 ( )
966
958
}
967
959
968
960
/// This excludes stashed errors. Unless absolutely necessary, prefer
969
961
/// `has_errors` or `has_errors_or_lint_errors` to this method.
970
962
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 ( )
979
964
}
980
965
981
966
pub fn print_error_count ( & self , registry : & Registry ) {
@@ -1055,7 +1040,7 @@ impl DiagCtxt {
1055
1040
pub fn abort_if_errors ( & self ) {
1056
1041
let mut inner = self . inner . borrow_mut ( ) ;
1057
1042
inner. emit_stashed_diagnostics ( ) ;
1058
- if inner. has_errors ( ) {
1043
+ if ! inner. err_guars . is_empty ( ) {
1059
1044
FatalError . raise ( ) ;
1060
1045
}
1061
1046
}
@@ -1175,8 +1160,21 @@ impl DiagCtxt {
1175
1160
) {
1176
1161
let mut inner = self . inner . borrow_mut ( ) ;
1177
1162
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.
1178
1173
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 ( ) ) ;
1180
1178
inner. panic_if_treat_err_as_bug ( ) ;
1181
1179
}
1182
1180
@@ -1236,7 +1234,7 @@ impl DiagCtxt {
1236
1234
impl DiagCtxtInner {
1237
1235
/// Emit all stashed diagnostics.
1238
1236
fn emit_stashed_diagnostics ( & mut self ) {
1239
- let has_errors = self . has_errors ( ) ;
1237
+ let has_errors = ! self . err_guars . is_empty ( ) ;
1240
1238
for ( _, diag) in std:: mem:: take ( & mut self . stashed_diagnostics ) . into_iter ( ) {
1241
1239
// Decrement the count tracking the stash; emitting will increment it.
1242
1240
if diag. is_error ( ) {
@@ -1298,9 +1296,13 @@ impl DiagCtxtInner {
1298
1296
// when an error is first emitted, also), but maybe there's a case
1299
1297
// in which that's not sound? otherwise this is really inefficient.
1300
1298
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.
1302
1301
#[ 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) ;
1304
1306
}
1305
1307
GoodPathDelayedBug => {
1306
1308
let backtrace = std:: backtrace:: Backtrace :: capture ( ) ;
@@ -1334,7 +1336,6 @@ impl DiagCtxtInner {
1334
1336
!self . emitted_diagnostics . insert ( diagnostic_hash)
1335
1337
} ;
1336
1338
1337
- let level = diagnostic. level ;
1338
1339
let is_error = diagnostic. is_error ( ) ;
1339
1340
let is_lint = diagnostic. is_lint . is_some ( ) ;
1340
1341
@@ -1373,36 +1374,47 @@ impl DiagCtxtInner {
1373
1374
}
1374
1375
1375
1376
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) ;
1376
1382
if is_lint {
1377
- self . lint_err_count += 1 ;
1383
+ self . lint_err_guars . push ( guar ) ;
1378
1384
} else {
1379
- self . err_count += 1 ;
1385
+ self . err_guars . push ( guar ) ;
1380
1386
}
1381
1387
self . panic_if_treat_err_as_bug ( ) ;
1382
1388
}
1383
-
1384
- #[ allow( deprecated) ]
1385
- if level == Level :: Error {
1386
- guaranteed = Some ( ErrorGuaranteed :: unchecked_error_guaranteed ( ) ) ;
1387
- }
1388
1389
} ) ;
1389
1390
1390
1391
guaranteed
1391
1392
}
1392
1393
1393
1394
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 ( ) )
1395
1398
}
1396
1399
1397
1400
// Use this one before incrementing `err_count`.
1398
1401
fn treat_next_err_as_bug ( & self ) -> bool {
1399
1402
self . flags
1400
1403
. 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 ( ) )
1402
1413
}
1403
1414
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 ( ) )
1406
1418
}
1407
1419
1408
1420
fn failure_note ( & mut self , msg : impl Into < DiagnosticMessage > ) {
@@ -1412,7 +1424,7 @@ impl DiagCtxtInner {
1412
1424
fn flush_delayed ( & mut self , kind : DelayedBugKind ) {
1413
1425
let ( bugs, note1) = match kind {
1414
1426
DelayedBugKind :: Normal => (
1415
- std:: mem:: take ( & mut self . delayed_bugs ) ,
1427
+ std:: mem:: take ( & mut self . delayed_bugs ) . into_iter ( ) . map ( | ( b , _ ) | b ) . collect ( ) ,
1416
1428
"no errors encountered even though delayed bugs were created" ,
1417
1429
) ,
1418
1430
DelayedBugKind :: GoodPath => (
@@ -1477,7 +1489,7 @@ impl DiagCtxtInner {
1477
1489
fn panic_if_treat_err_as_bug ( & self ) {
1478
1490
if self . treat_err_as_bug ( ) {
1479
1491
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 ( ) ) ;
1481
1493
if n == 1 {
1482
1494
panic ! ( "aborting due to `-Z treat-err-as-bug=1`" ) ;
1483
1495
} else {
0 commit comments