@@ -24,6 +24,7 @@ use std::io::Write;
2424use std:: num:: NonZero ;
2525use std:: ops:: DerefMut ;
2626use std:: path:: { Path , PathBuf } ;
27+ use std:: thread:: ThreadId ;
2728use std:: { assert_matches, fmt, panic} ;
2829
2930use Level :: * ;
@@ -297,11 +298,12 @@ impl<'a> std::ops::Deref for DiagCtxtHandle<'a> {
297298struct DiagCtxtInner {
298299 flags : DiagCtxtFlags ,
299300
300- /// The error guarantees from all emitted errors. The length gives the error count.
301- err_guars : Vec < ErrorGuaranteed > ,
302- /// The error guarantee from all emitted lint errors. The length gives the
303- /// lint error count.
304- lint_err_guars : Vec < ErrorGuaranteed > ,
301+ /// The error guarantees from all emitted errors, each paired with the
302+ /// thread that emitted it. The length gives the error count.
303+ err_guars : Vec < ( ErrorGuaranteed , ThreadId ) > ,
304+ /// The error guarantee from all emitted lint errors, each paired with the
305+ /// thread that emitted it. The length gives the lint error count.
306+ lint_err_guars : Vec < ( ErrorGuaranteed , ThreadId ) > ,
305307 /// The delayed bugs and their error guarantees.
306308 delayed_bugs : Vec < ( DelayedDiagInner , ErrorGuaranteed ) > ,
307309
@@ -343,7 +345,7 @@ struct DiagCtxtInner {
343345 /// `emit_stashed_diagnostics` by the time the `DiagCtxtInner` is dropped,
344346 /// otherwise an assertion failure will occur.
345347 stashed_diagnostics :
346- FxIndexMap < StashKey , FxIndexMap < Span , ( DiagInner , Option < ErrorGuaranteed > ) > > ,
348+ FxIndexMap < StashKey , FxIndexMap < Span , ( DiagInner , Option < ErrorGuaranteed > , ThreadId ) > > ,
347349
348350 future_breakage_diagnostics : Vec < DiagInner > ,
349351
@@ -613,7 +615,7 @@ impl<'a> DiagCtxtHandle<'a> {
613615 . stashed_diagnostics
614616 . entry ( key)
615617 . or_default ( )
616- . insert ( span. with_parent ( None ) , ( diag, guar) ) ;
618+ . insert ( span. with_parent ( None ) , ( diag, guar, std :: thread :: current ( ) . id ( ) ) ) ;
617619
618620 guar
619621 }
@@ -623,7 +625,7 @@ impl<'a> DiagCtxtHandle<'a> {
623625 /// error.
624626 pub fn steal_non_err ( self , span : Span , key : StashKey ) -> Option < Diag < ' a , ( ) > > {
625627 // FIXME(#120456) - is `swap_remove` correct?
626- let ( diag, guar) = self . inner . borrow_mut ( ) . stashed_diagnostics . get_mut ( & key) . and_then (
628+ let ( diag, guar, _ ) = self . inner . borrow_mut ( ) . stashed_diagnostics . get_mut ( & key) . and_then (
627629 |stashed_diagnostics| stashed_diagnostics. swap_remove ( & span. with_parent ( None ) ) ,
628630 ) ?;
629631 assert ! ( !diag. is_error( ) ) ;
@@ -648,7 +650,7 @@ impl<'a> DiagCtxtHandle<'a> {
648650 let err = self . inner . borrow_mut ( ) . stashed_diagnostics . get_mut ( & key) . and_then (
649651 |stashed_diagnostics| stashed_diagnostics. swap_remove ( & span. with_parent ( None ) ) ,
650652 ) ;
651- err. map ( |( err, guar) | {
653+ err. map ( |( err, guar, _ ) | {
652654 // The use of `::<ErrorGuaranteed>` is safe because level is `Level::Error`.
653655 assert_eq ! ( err. level, Error ) ;
654656 assert ! ( guar. is_some( ) ) ;
@@ -673,7 +675,7 @@ impl<'a> DiagCtxtHandle<'a> {
673675 |stashed_diagnostics| stashed_diagnostics. swap_remove ( & span. with_parent ( None ) ) ,
674676 ) ;
675677 match old_err {
676- Some ( ( old_err, guar) ) => {
678+ Some ( ( old_err, guar, _ ) ) => {
677679 assert_eq ! ( old_err. level, Error ) ;
678680 assert ! ( guar. is_some( ) ) ;
679681 // Because `old_err` has already been counted, it can only be
@@ -710,7 +712,27 @@ impl<'a> DiagCtxtHandle<'a> {
710712 + inner
711713 . stashed_diagnostics
712714 . values ( )
713- . map ( |a| a. values ( ) . filter ( |( _, guar) | guar. is_some ( ) ) . count ( ) )
715+ . map ( |a| a. values ( ) . filter ( |( _, guar, _) | guar. is_some ( ) ) . count ( ) )
716+ . sum :: < usize > ( )
717+ }
718+
719+ /// The number of errors that have been emitted on the *current thread*.
720+ ///
721+ /// Like [`DiagCtxtHandle::err_count`], but only counts errors whose recorded
722+ /// emitting thread is the calling thread.
723+ pub fn err_count_on_current_thread ( & self ) -> usize {
724+ let inner = self . inner . borrow ( ) ;
725+ let current = std:: thread:: current ( ) . id ( ) ;
726+ inner. err_guars . iter ( ) . filter ( |( _, thread) | * thread == current) . count ( )
727+ + inner. lint_err_guars . iter ( ) . filter ( |( _, thread) | * thread == current) . count ( )
728+ + inner
729+ . stashed_diagnostics
730+ . values ( )
731+ . map ( |a| {
732+ a. values ( )
733+ . filter ( |( _, guar, thread) | guar. is_some ( ) && * thread == current)
734+ . count ( )
735+ } )
714736 . sum :: < usize > ( )
715737 }
716738
@@ -879,7 +901,8 @@ impl<'a> DiagCtxtHandle<'a> {
879901 // This `unchecked_error_guaranteed` is valid. It is where the
880902 // `ErrorGuaranteed` for unused_extern errors originates.
881903 #[ allow( deprecated) ]
882- inner. lint_err_guars . push ( ErrorGuaranteed :: unchecked_error_guaranteed ( ) ) ;
904+ let guar = ErrorGuaranteed :: unchecked_error_guaranteed ( ) ;
905+ inner. lint_err_guars . push ( ( guar, std:: thread:: current ( ) . id ( ) ) ) ;
883906 inner. panic_if_treat_err_as_bug ( ) ;
884907 }
885908
@@ -1178,7 +1201,7 @@ impl DiagCtxtInner {
11781201 let mut guar = None ;
11791202 let has_errors = !self . err_guars . is_empty ( ) ;
11801203 for ( _, stashed_diagnostics) in std:: mem:: take ( & mut self . stashed_diagnostics ) . into_iter ( ) {
1181- for ( _, ( diag, _guar) ) in stashed_diagnostics {
1204+ for ( _, ( diag, _guar, _thread ) ) in stashed_diagnostics {
11821205 if !diag. is_error ( ) {
11831206 // Unless they're forced, don't flush stashed warnings when
11841207 // there are errors, to avoid causing warning overload. The
@@ -1347,13 +1370,14 @@ impl DiagCtxtInner {
13471370 // `ErrorGuaranteed` for errors and lint errors originates.
13481371 #[ allow( deprecated) ]
13491372 let guar = ErrorGuaranteed :: unchecked_error_guaranteed ( ) ;
1373+ let thread = std:: thread:: current ( ) . id ( ) ;
13501374 if is_lint {
1351- self . lint_err_guars . push ( guar) ;
1375+ self . lint_err_guars . push ( ( guar, thread ) ) ;
13521376 } else {
13531377 if let Some ( taint) = taint {
13541378 taint. set ( Some ( guar) ) ;
13551379 }
1356- self . err_guars . push ( guar) ;
1380+ self . err_guars . push ( ( guar, thread ) ) ;
13571381 }
13581382 self . panic_if_treat_err_as_bug ( ) ;
13591383 Some ( guar)
@@ -1377,12 +1401,12 @@ impl DiagCtxtInner {
13771401 }
13781402
13791403 fn has_errors_excluding_lint_errors ( & self ) -> Option < ErrorGuaranteed > {
1380- self . err_guars . get ( 0 ) . copied ( ) . or_else ( || {
1381- if let Some ( ( _diag, guar) ) = self
1404+ self . err_guars . get ( 0 ) . map ( | ( guar , _ ) | * guar ) . or_else ( || {
1405+ if let Some ( ( _diag, guar, _ ) ) = self
13821406 . stashed_diagnostics
13831407 . values ( )
13841408 . flat_map ( |stashed_diagnostics| stashed_diagnostics. values ( ) )
1385- . find ( |( diag, guar) | guar. is_some ( ) && diag. is_lint . is_none ( ) )
1409+ . find ( |( diag, guar, _ ) | guar. is_some ( ) && diag. is_lint . is_none ( ) )
13861410 {
13871411 * guar
13881412 } else {
@@ -1392,13 +1416,15 @@ impl DiagCtxtInner {
13921416 }
13931417
13941418 fn has_errors ( & self ) -> Option < ErrorGuaranteed > {
1395- self . err_guars . get ( 0 ) . copied ( ) . or_else ( || self . lint_err_guars . get ( 0 ) . copied ( ) ) . or_else (
1396- || {
1419+ self . err_guars
1420+ . get ( 0 )
1421+ . map ( |( guar, _) | * guar)
1422+ . or_else ( || self . lint_err_guars . get ( 0 ) . map ( |( guar, _) | * guar) )
1423+ . or_else ( || {
13971424 self . stashed_diagnostics . values ( ) . find_map ( |stashed_diagnostics| {
1398- stashed_diagnostics. values ( ) . find_map ( |( _, guar) | * guar)
1425+ stashed_diagnostics. values ( ) . find_map ( |( _, guar, _ ) | * guar)
13991426 } )
1400- } ,
1401- )
1427+ } )
14021428 }
14031429
14041430 fn has_errors_or_delayed_bugs ( & self ) -> Option < ErrorGuaranteed > {
0 commit comments