@@ -424,10 +424,14 @@ pub struct DiagCtxt {
424
424
struct DiagCtxtInner {
425
425
flags : DiagCtxtFlags ,
426
426
427
- /// The number of lint errors that have been emitted, including duplicates.
428
- lint_err_count : usize ,
429
- /// The number of non-lint errors that have been emitted, including duplicates.
430
- err_count : usize ,
427
+ /// The error guarantees from all emitted errors. The length gives the error count.
428
+ err_guars : Vec < ErrorGuaranteed > ,
429
+ /// The error guarantee from all emitted lint errors. The length gives the
430
+ /// lint error count.
431
+ lint_err_guars : Vec < ErrorGuaranteed > ,
432
+ /// The delayed bugs and their error guarantees.
433
+ delayed_bugs : Vec < ( DelayedDiagnostic , ErrorGuaranteed ) > ,
434
+ good_path_delayed_bugs : Vec < DelayedDiagnostic > ,
431
435
432
436
/// The number of stashed errors. Unlike the other counts, this can go up
433
437
/// and down, so it doesn't guarantee anything.
@@ -443,8 +447,6 @@ struct DiagCtxtInner {
443
447
has_printed : bool ,
444
448
445
449
emitter : Box < DynEmitter > ,
446
- delayed_bugs : Vec < DelayedDiagnostic > ,
447
- good_path_delayed_bugs : Vec < DelayedDiagnostic > ,
448
450
/// This flag indicates that an expected diagnostic was emitted and suppressed.
449
451
/// This is used for the `good_path_delayed_bugs` check.
450
452
suppressed_expected_diag : bool ,
@@ -556,7 +558,7 @@ impl Drop for DiagCtxtInner {
556
558
fn drop ( & mut self ) {
557
559
self . emit_stashed_diagnostics ( ) ;
558
560
559
- if ! self . has_errors ( ) {
561
+ if self . err_guars . is_empty ( ) {
560
562
self . flush_delayed ( DelayedBugKind :: Normal )
561
563
}
562
564
@@ -600,15 +602,15 @@ impl DiagCtxt {
600
602
Self {
601
603
inner : Lock :: new ( DiagCtxtInner {
602
604
flags : DiagCtxtFlags { can_emit_warnings : true , ..Default :: default ( ) } ,
603
- lint_err_count : 0 ,
604
- err_count : 0 ,
605
+ err_guars : Vec :: new ( ) ,
606
+ lint_err_guars : Vec :: new ( ) ,
607
+ delayed_bugs : Vec :: new ( ) ,
608
+ good_path_delayed_bugs : Vec :: new ( ) ,
605
609
stashed_err_count : 0 ,
606
610
deduplicated_err_count : 0 ,
607
611
deduplicated_warn_count : 0 ,
608
612
has_printed : false ,
609
613
emitter,
610
- delayed_bugs : Vec :: new ( ) ,
611
- good_path_delayed_bugs : Vec :: new ( ) ,
612
614
suppressed_expected_diag : false ,
613
615
taught_diagnostics : Default :: default ( ) ,
614
616
emitted_diagnostic_codes : Default :: default ( ) ,
@@ -657,14 +659,14 @@ impl DiagCtxt {
657
659
/// the overall count of emitted error diagnostics.
658
660
pub fn reset_err_count ( & self ) {
659
661
let mut inner = self . inner . borrow_mut ( ) ;
660
- inner. lint_err_count = 0 ;
661
- inner. err_count = 0 ;
662
662
inner. stashed_err_count = 0 ;
663
663
inner. deduplicated_err_count = 0 ;
664
664
inner. deduplicated_warn_count = 0 ;
665
665
inner. has_printed = false ;
666
666
667
667
// actually free the underlying memory (which `clear` would not do)
668
+ inner. err_guars = Default :: default ( ) ;
669
+ inner. lint_err_guars = Default :: default ( ) ;
668
670
inner. delayed_bugs = Default :: default ( ) ;
669
671
inner. good_path_delayed_bugs = Default :: default ( ) ;
670
672
inner. taught_diagnostics = Default :: default ( ) ;
@@ -927,7 +929,7 @@ impl DiagCtxt {
927
929
/// This excludes lint errors, delayed bugs, and stashed errors.
928
930
#[ inline]
929
931
pub fn err_count ( & self ) -> usize {
930
- self . inner . borrow ( ) . err_count
932
+ self . inner . borrow ( ) . err_guars . len ( )
931
933
}
932
934
933
935
/// This excludes normal errors, lint errors and delayed bugs. Unless
@@ -941,36 +943,19 @@ impl DiagCtxt {
941
943
942
944
/// This excludes lint errors, delayed bugs, and stashed errors.
943
945
pub fn has_errors ( & self ) -> Option < ErrorGuaranteed > {
944
- self . inner . borrow ( ) . has_errors ( ) . then ( || {
945
- // FIXME(nnethercote) find a way to store an `ErrorGuaranteed`.
946
- #[ allow( deprecated) ]
947
- ErrorGuaranteed :: unchecked_error_guaranteed ( )
948
- } )
946
+ self . inner . borrow ( ) . has_errors ( )
949
947
}
950
948
951
949
/// This excludes delayed bugs and stashed errors. Unless absolutely
952
950
/// necessary, prefer `has_errors` to this method.
953
951
pub fn has_errors_or_lint_errors ( & self ) -> Option < ErrorGuaranteed > {
954
- let inner = self . inner . borrow ( ) ;
955
- let result = inner. has_errors ( ) || inner. lint_err_count > 0 ;
956
- result. then ( || {
957
- // FIXME(nnethercote) find a way to store an `ErrorGuaranteed`.
958
- #[ allow( deprecated) ]
959
- ErrorGuaranteed :: unchecked_error_guaranteed ( )
960
- } )
952
+ self . inner . borrow ( ) . has_errors_or_lint_errors ( )
961
953
}
962
954
963
955
/// This excludes stashed errors. Unless absolutely necessary, prefer
964
956
/// `has_errors` or `has_errors_or_lint_errors` to this method.
965
957
pub fn has_errors_or_lint_errors_or_delayed_bugs ( & self ) -> Option < ErrorGuaranteed > {
966
- let inner = self . inner . borrow ( ) ;
967
- let result =
968
- inner. has_errors ( ) || inner. lint_err_count > 0 || !inner. delayed_bugs . is_empty ( ) ;
969
- result. then ( || {
970
- // FIXME(nnethercote) find a way to store an `ErrorGuaranteed`.
971
- #[ allow( deprecated) ]
972
- ErrorGuaranteed :: unchecked_error_guaranteed ( )
973
- } )
958
+ self . inner . borrow ( ) . has_errors_or_lint_errors_or_delayed_bugs ( )
974
959
}
975
960
976
961
pub fn print_error_count ( & self , registry : & Registry ) {
@@ -1050,7 +1035,7 @@ impl DiagCtxt {
1050
1035
pub fn abort_if_errors ( & self ) {
1051
1036
let mut inner = self . inner . borrow_mut ( ) ;
1052
1037
inner. emit_stashed_diagnostics ( ) ;
1053
- if inner. has_errors ( ) {
1038
+ if ! inner. err_guars . is_empty ( ) {
1054
1039
FatalError . raise ( ) ;
1055
1040
}
1056
1041
}
@@ -1170,8 +1155,21 @@ impl DiagCtxt {
1170
1155
) {
1171
1156
let mut inner = self . inner . borrow_mut ( ) ;
1172
1157
1158
+ // This "error" is an odd duck.
1159
+ // - It's only produce with JSON output.
1160
+ // - It's not emitted the usual way, via `emit_diagnostic`.
1161
+ // - The `$message_type` field is "unused_externs" rather than the usual
1162
+ // "diagnosic".
1163
+ //
1164
+ // We count it as a lint error because it has a lint level. The value
1165
+ // of `loud` (which comes from "unused-externs" or
1166
+ // "unused-externs-silent"), also affects whether it's treated like a
1167
+ // hard error or not.
1173
1168
if loud && lint_level. is_error ( ) {
1174
- inner. lint_err_count += 1 ;
1169
+ // This `unchecked_error_guaranteed` is valid. It is where the
1170
+ // `ErrorGuaranteed` for unused_extern errors originates.
1171
+ #[ allow( deprecated) ]
1172
+ inner. lint_err_guars . push ( ErrorGuaranteed :: unchecked_error_guaranteed ( ) ) ;
1175
1173
inner. panic_if_treat_err_as_bug ( ) ;
1176
1174
}
1177
1175
@@ -1231,7 +1229,7 @@ impl DiagCtxt {
1231
1229
impl DiagCtxtInner {
1232
1230
/// Emit all stashed diagnostics.
1233
1231
fn emit_stashed_diagnostics ( & mut self ) {
1234
- let has_errors = self . has_errors ( ) ;
1232
+ let has_errors = ! self . err_guars . is_empty ( ) ;
1235
1233
for ( _, diag) in std:: mem:: take ( & mut self . stashed_diagnostics ) . into_iter ( ) {
1236
1234
// Decrement the count tracking the stash; emitting will increment it.
1237
1235
if diag. is_error ( ) {
@@ -1293,9 +1291,13 @@ impl DiagCtxtInner {
1293
1291
// when an error is first emitted, also), but maybe there's a case
1294
1292
// in which that's not sound? otherwise this is really inefficient.
1295
1293
let backtrace = std:: backtrace:: Backtrace :: capture ( ) ;
1296
- self . delayed_bugs . push ( DelayedDiagnostic :: with_backtrace ( diagnostic, backtrace) ) ;
1294
+ // This `unchecked_error_guaranteed` is valid. It is where the
1295
+ // `ErrorGuaranteed` for delayed bugs originates.
1297
1296
#[ allow( deprecated) ]
1298
- return Some ( ErrorGuaranteed :: unchecked_error_guaranteed ( ) ) ;
1297
+ let guar = ErrorGuaranteed :: unchecked_error_guaranteed ( ) ;
1298
+ self . delayed_bugs
1299
+ . push ( ( DelayedDiagnostic :: with_backtrace ( diagnostic, backtrace) , guar) ) ;
1300
+ return Some ( guar) ;
1299
1301
}
1300
1302
GoodPathDelayedBug => {
1301
1303
let backtrace = std:: backtrace:: Backtrace :: capture ( ) ;
@@ -1329,7 +1331,6 @@ impl DiagCtxtInner {
1329
1331
!self . emitted_diagnostics . insert ( diagnostic_hash)
1330
1332
} ;
1331
1333
1332
- let level = diagnostic. level ;
1333
1334
let is_error = diagnostic. is_error ( ) ;
1334
1335
let is_lint = diagnostic. is_lint . is_some ( ) ;
1335
1336
@@ -1368,36 +1369,47 @@ impl DiagCtxtInner {
1368
1369
}
1369
1370
1370
1371
if is_error {
1372
+ // This `unchecked_error_guaranteed` is valid. It is where the
1373
+ // `ErrorGuaranteed` for errors and lint errors originates.
1374
+ #[ allow( deprecated) ]
1375
+ let guar = ErrorGuaranteed :: unchecked_error_guaranteed ( ) ;
1376
+ guaranteed = Some ( guar) ;
1371
1377
if is_lint {
1372
- self . lint_err_count += 1 ;
1378
+ self . lint_err_guars . push ( guar ) ;
1373
1379
} else {
1374
- self . err_count += 1 ;
1380
+ self . err_guars . push ( guar ) ;
1375
1381
}
1376
1382
self . panic_if_treat_err_as_bug ( ) ;
1377
1383
}
1378
-
1379
- #[ allow( deprecated) ]
1380
- if level == Level :: Error {
1381
- guaranteed = Some ( ErrorGuaranteed :: unchecked_error_guaranteed ( ) ) ;
1382
- }
1383
1384
} ) ;
1384
1385
1385
1386
guaranteed
1386
1387
}
1387
1388
1388
1389
fn treat_err_as_bug ( & self ) -> bool {
1389
- self . flags . treat_err_as_bug . is_some_and ( |c| self . err_count + self . lint_err_count >= c. get ( ) )
1390
+ self . flags
1391
+ . treat_err_as_bug
1392
+ . is_some_and ( |c| self . err_guars . len ( ) + self . lint_err_guars . len ( ) >= c. get ( ) )
1390
1393
}
1391
1394
1392
1395
// Use this one before incrementing `err_count`.
1393
1396
fn treat_next_err_as_bug ( & self ) -> bool {
1394
1397
self . flags
1395
1398
. treat_err_as_bug
1396
- . is_some_and ( |c| self . err_count + self . lint_err_count + 1 >= c. get ( ) )
1399
+ . is_some_and ( |c| self . err_guars . len ( ) + self . lint_err_guars . len ( ) + 1 >= c. get ( ) )
1400
+ }
1401
+
1402
+ fn has_errors ( & self ) -> Option < ErrorGuaranteed > {
1403
+ self . err_guars . get ( 0 ) . copied ( )
1404
+ }
1405
+
1406
+ fn has_errors_or_lint_errors ( & self ) -> Option < ErrorGuaranteed > {
1407
+ self . has_errors ( ) . or_else ( || self . lint_err_guars . get ( 0 ) . copied ( ) )
1397
1408
}
1398
1409
1399
- fn has_errors ( & self ) -> bool {
1400
- self . err_count > 0
1410
+ fn has_errors_or_lint_errors_or_delayed_bugs ( & self ) -> Option < ErrorGuaranteed > {
1411
+ self . has_errors_or_lint_errors ( )
1412
+ . or_else ( || self . delayed_bugs . get ( 0 ) . map ( |( _, guar) | guar) . copied ( ) )
1401
1413
}
1402
1414
1403
1415
fn failure_note ( & mut self , msg : impl Into < DiagnosticMessage > ) {
@@ -1407,7 +1419,7 @@ impl DiagCtxtInner {
1407
1419
fn flush_delayed ( & mut self , kind : DelayedBugKind ) {
1408
1420
let ( bugs, note1) = match kind {
1409
1421
DelayedBugKind :: Normal => (
1410
- std:: mem:: take ( & mut self . delayed_bugs ) ,
1422
+ std:: mem:: take ( & mut self . delayed_bugs ) . into_iter ( ) . map ( | ( b , _ ) | b ) . collect ( ) ,
1411
1423
"no errors encountered even though delayed bugs were created" ,
1412
1424
) ,
1413
1425
DelayedBugKind :: GoodPath => (
@@ -1472,7 +1484,7 @@ impl DiagCtxtInner {
1472
1484
fn panic_if_treat_err_as_bug ( & self ) {
1473
1485
if self . treat_err_as_bug ( ) {
1474
1486
let n = self . flags . treat_err_as_bug . map ( |c| c. get ( ) ) . unwrap ( ) ;
1475
- assert_eq ! ( n, self . err_count + self . lint_err_count ) ;
1487
+ assert_eq ! ( n, self . err_guars . len ( ) + self . lint_err_guars . len ( ) ) ;
1476
1488
if n == 1 {
1477
1489
panic ! ( "aborting due to `-Z treat-err-as-bug=1`" ) ;
1478
1490
} else {
0 commit comments