@@ -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
@@ -608,12 +610,10 @@ impl<'a> DiagCtxtHandle<'a> {
608610 // FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic
609611 // if/when we have a more robust macro-friendly replacement for `(span, key)` as a key.
610612 // See the PR for a discussion.
611- self . inner
612- . borrow_mut ( )
613- . stashed_diagnostics
614- . entry ( key)
615- . or_default ( )
616- . insert ( span. with_parent ( None ) , ( diag, guar) ) ;
613+ self . inner . borrow_mut ( ) . stashed_diagnostics . entry ( key) . or_default ( ) . insert (
614+ span. with_parent ( None ) ,
615+ ( diag, guar. map ( |guar| ( guar, std:: thread:: current ( ) . id ( ) ) ) ) ,
616+ ) ;
617617
618618 guar
619619 }
@@ -714,6 +714,27 @@ impl<'a> DiagCtxtHandle<'a> {
714714 . sum :: < usize > ( )
715715 }
716716
717+ /// The number of errors that have been emitted on the *current thread*.
718+ ///
719+ /// Like [`DiagCtxtHandle::err_count`], but only counts errors whose recorded
720+ /// emitting thread is the calling thread. It is meant for code that takes a
721+ /// before/after delta to detect whether a unit of work emitted an error, and
722+ /// must not be misled by errors emitted on other threads at the same time
723+ /// (#154260). In serial compilation it is equivalent to taking a delta of
724+ /// `err_count`.
725+ pub fn err_count_on_current_thread ( & self ) -> usize {
726+ let inner = self . inner . borrow ( ) ;
727+ let current = std:: thread:: current ( ) . id ( ) ;
728+ inner. err_guars . iter ( ) . filter ( |( _, thread) | * thread == current) . count ( )
729+ + inner. lint_err_guars . iter ( ) . filter ( |( _, thread) | * thread == current) . count ( )
730+ + inner
731+ . stashed_diagnostics
732+ . values ( )
733+ . flat_map ( |stashed| stashed. values ( ) )
734+ . filter ( |( _, guar) | matches ! ( guar, Some ( ( _, thread) ) if * thread == current) )
735+ . count ( )
736+ }
737+
717738 /// This excludes lint errors and delayed bugs. Unless absolutely
718739 /// necessary, prefer `has_errors` to this method.
719740 pub fn has_errors_excluding_lint_errors ( & self ) -> Option < ErrorGuaranteed > {
@@ -879,7 +900,8 @@ impl<'a> DiagCtxtHandle<'a> {
879900 // This `unchecked_error_guaranteed` is valid. It is where the
880901 // `ErrorGuaranteed` for unused_extern errors originates.
881902 #[ allow( deprecated) ]
882- inner. lint_err_guars . push ( ErrorGuaranteed :: unchecked_error_guaranteed ( ) ) ;
903+ let guar = ErrorGuaranteed :: unchecked_error_guaranteed ( ) ;
904+ inner. lint_err_guars . push ( ( guar, std:: thread:: current ( ) . id ( ) ) ) ;
883905 inner. panic_if_treat_err_as_bug ( ) ;
884906 }
885907
@@ -1347,13 +1369,17 @@ impl DiagCtxtInner {
13471369 // `ErrorGuaranteed` for errors and lint errors originates.
13481370 #[ allow( deprecated) ]
13491371 let guar = ErrorGuaranteed :: unchecked_error_guaranteed ( ) ;
1372+ // Record which thread emitted the error so that
1373+ // `err_count_on_current_thread` can attribute it correctly when
1374+ // the mono item graph is collected in parallel (#154260).
1375+ let thread = std:: thread:: current ( ) . id ( ) ;
13501376 if is_lint {
1351- self . lint_err_guars . push ( guar) ;
1377+ self . lint_err_guars . push ( ( guar, thread ) ) ;
13521378 } else {
13531379 if let Some ( taint) = taint {
13541380 taint. set ( Some ( guar) ) ;
13551381 }
1356- self . err_guars . push ( guar) ;
1382+ self . err_guars . push ( ( guar, thread ) ) ;
13571383 }
13581384 self . panic_if_treat_err_as_bug ( ) ;
13591385 Some ( guar)
@@ -1377,28 +1403,30 @@ impl DiagCtxtInner {
13771403 }
13781404
13791405 fn has_errors_excluding_lint_errors ( & self ) -> Option < ErrorGuaranteed > {
1380- self . err_guars . get ( 0 ) . copied ( ) . or_else ( || {
1406+ self . err_guars . get ( 0 ) . map ( | ( guar , _ ) | * guar ) . or_else ( || {
13811407 if let Some ( ( _diag, guar) ) = self
13821408 . stashed_diagnostics
13831409 . values ( )
13841410 . flat_map ( |stashed_diagnostics| stashed_diagnostics. values ( ) )
13851411 . find ( |( diag, guar) | guar. is_some ( ) && diag. is_lint . is_none ( ) )
13861412 {
1387- * guar
1413+ ( * guar) . map ( | ( guar , _ ) | guar )
13881414 } else {
13891415 None
13901416 }
13911417 } )
13921418 }
13931419
13941420 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- || {
1421+ self . err_guars
1422+ . get ( 0 )
1423+ . map ( |( guar, _) | * guar)
1424+ . or_else ( || self . lint_err_guars . get ( 0 ) . map ( |( guar, _) | * guar) )
1425+ . or_else ( || {
13971426 self . stashed_diagnostics . values ( ) . find_map ( |stashed_diagnostics| {
1398- stashed_diagnostics. values ( ) . find_map ( |( _, guar) | * guar)
1427+ stashed_diagnostics. values ( ) . find_map ( |( _, guar) | ( * guar) . map ( | ( guar , _ ) | guar ) )
13991428 } )
1400- } ,
1401- )
1429+ } )
14021430 }
14031431
14041432 fn has_errors_or_delayed_bugs ( & self ) -> Option < ErrorGuaranteed > {
0 commit comments