8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
- use errors:: DiagnosticBuilder ;
11
+ use errors:: { Diagnostic , DiagnosticBuilder } ;
12
12
use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher } ;
13
13
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
14
14
use rustc_data_structures:: indexed_vec:: { Idx , IndexVec } ;
@@ -19,6 +19,7 @@ use std::hash::Hash;
19
19
use std:: collections:: hash_map:: Entry ;
20
20
use ty:: { self , TyCtxt } ;
21
21
use util:: common:: { ProfileQueriesMsg , profq_msg} ;
22
+ use parking_lot:: { Mutex , Condvar } ;
22
23
23
24
use ich:: { StableHashingContext , StableHashingContextProvider , Fingerprint } ;
24
25
@@ -70,6 +71,12 @@ struct DepGraphData {
70
71
71
72
colors : DepNodeColorMap ,
72
73
74
+ /// A set of loaded diagnostics which has been emitted.
75
+ emitted_diagnostics : Mutex < FxHashSet < DepNodeIndex > > ,
76
+
77
+ /// Used to wait for diagnostics to be emitted.
78
+ emitted_diagnostics_cond_var : Condvar ,
79
+
73
80
/// When we load, there may be `.o` files, cached mir, or other such
74
81
/// things available to us. If we find that they are not dirty, we
75
82
/// load the path to the file storing those work-products here into
@@ -93,6 +100,8 @@ impl DepGraph {
93
100
previous_work_products : prev_work_products,
94
101
dep_node_debug : Default :: default ( ) ,
95
102
current : Lock :: new ( CurrentDepGraph :: new ( prev_graph_node_count) ) ,
103
+ emitted_diagnostics : Default :: default ( ) ,
104
+ emitted_diagnostics_cond_var : Condvar :: new ( ) ,
96
105
previous : prev_graph,
97
106
colors : DepNodeColorMap :: new ( prev_graph_node_count) ,
98
107
loaded_from_cache : Default :: default ( ) ,
@@ -711,28 +720,18 @@ impl DepGraph {
711
720
} ;
712
721
713
722
// ... emitting any stored diagnostic ...
714
- if did_allocation {
715
- // Only the thread which did the allocation emits the error messages
716
723
717
- // FIXME: Ensure that these are printed before returning for all threads.
718
- // Currently threads where did_allocation = false can continue on
719
- // and emit other diagnostics before these diagnostics are emitted.
720
- // Such diagnostics should be emitted after these.
721
- // See https://github.com/rust-lang/rust/issues/48685
722
- let diagnostics = tcx. queries . on_disk_cache
723
- . load_diagnostics ( tcx, prev_dep_node_index) ;
724
+ let diagnostics = tcx. queries . on_disk_cache
725
+ . load_diagnostics ( tcx, prev_dep_node_index) ;
724
726
725
- if diagnostics. len ( ) > 0 {
726
- let handle = tcx. sess . diagnostic ( ) ;
727
-
728
- // Promote the previous diagnostics to the current session.
729
- tcx. queries . on_disk_cache
730
- . store_diagnostics ( dep_node_index, diagnostics. clone ( ) ) ;
731
-
732
- for diagnostic in diagnostics {
733
- DiagnosticBuilder :: new_diagnostic ( handle, diagnostic) . emit ( ) ;
734
- }
735
- }
727
+ if unlikely ! ( diagnostics. len( ) > 0 ) {
728
+ self . emit_diagnostics (
729
+ tcx,
730
+ data,
731
+ dep_node_index,
732
+ did_allocation,
733
+ diagnostics
734
+ ) ;
736
735
}
737
736
738
737
// ... and finally storing a "Green" entry in the color map.
@@ -748,6 +747,49 @@ impl DepGraph {
748
747
Some ( dep_node_index)
749
748
}
750
749
750
+ /// Atomically emits some loaded diagnotics assuming that this only gets called with
751
+ /// did_allocation set to true on one thread
752
+ #[ cold]
753
+ #[ inline( never) ]
754
+ fn emit_diagnostics < ' tcx > (
755
+ & self ,
756
+ tcx : TyCtxt < ' _ , ' tcx , ' tcx > ,
757
+ data : & DepGraphData ,
758
+ dep_node_index : DepNodeIndex ,
759
+ did_allocation : bool ,
760
+ diagnostics : Vec < Diagnostic > ,
761
+ ) {
762
+ if did_allocation || !cfg ! ( parallel_queries) {
763
+ // Only the thread which did the allocation emits the error messages
764
+ let handle = tcx. sess . diagnostic ( ) ;
765
+
766
+ // Promote the previous diagnostics to the current session.
767
+ tcx. queries . on_disk_cache
768
+ . store_diagnostics ( dep_node_index, diagnostics. clone ( ) ) ;
769
+
770
+ for diagnostic in diagnostics {
771
+ DiagnosticBuilder :: new_diagnostic ( handle, diagnostic) . emit ( ) ;
772
+ }
773
+
774
+ #[ cfg( parallel_queries) ]
775
+ {
776
+ // Mark the diagnostics and emitted and wake up waiters
777
+ data. emitted_diagnostics . lock ( ) . insert ( dep_node_index) ;
778
+ data. emitted_diagnostics_cond_var . notify_all ( ) ;
779
+ }
780
+ } else {
781
+ // The other threads will wait for the diagnostics to be emitted
782
+
783
+ let mut emitted_diagnostics = data. emitted_diagnostics . lock ( ) ;
784
+ loop {
785
+ if emitted_diagnostics. contains ( & dep_node_index) {
786
+ break ;
787
+ }
788
+ data. emitted_diagnostics_cond_var . wait ( & mut emitted_diagnostics) ;
789
+ }
790
+ }
791
+ }
792
+
751
793
// Returns true if the given node has been marked as green during the
752
794
// current compilation session. Used in various assertions
753
795
pub fn is_green ( & self , dep_node : & DepNode ) -> bool {
0 commit comments