1
- use errors:: DiagnosticBuilder ;
1
+ use errors:: { Diagnostic , DiagnosticBuilder } ;
2
2
use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher } ;
3
3
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
4
4
use rustc_data_structures:: indexed_vec:: { Idx , IndexVec } ;
@@ -9,6 +9,7 @@ use std::hash::Hash;
9
9
use std:: collections:: hash_map:: Entry ;
10
10
use ty:: { self , TyCtxt } ;
11
11
use util:: common:: { ProfileQueriesMsg , profq_msg} ;
12
+ use parking_lot:: { Mutex , Condvar } ;
12
13
13
14
use ich:: { StableHashingContext , StableHashingContextProvider , Fingerprint } ;
14
15
@@ -60,6 +61,12 @@ struct DepGraphData {
60
61
61
62
colors : DepNodeColorMap ,
62
63
64
+ /// A set of loaded diagnostics which has been emitted.
65
+ emitted_diagnostics : Mutex < FxHashSet < DepNodeIndex > > ,
66
+
67
+ /// Used to wait for diagnostics to be emitted.
68
+ emitted_diagnostics_cond_var : Condvar ,
69
+
63
70
/// When we load, there may be `.o` files, cached mir, or other such
64
71
/// things available to us. If we find that they are not dirty, we
65
72
/// load the path to the file storing those work-products here into
@@ -83,6 +90,8 @@ impl DepGraph {
83
90
previous_work_products : prev_work_products,
84
91
dep_node_debug : Default :: default ( ) ,
85
92
current : Lock :: new ( CurrentDepGraph :: new ( prev_graph_node_count) ) ,
93
+ emitted_diagnostics : Default :: default ( ) ,
94
+ emitted_diagnostics_cond_var : Condvar :: new ( ) ,
86
95
previous : prev_graph,
87
96
colors : DepNodeColorMap :: new ( prev_graph_node_count) ,
88
97
loaded_from_cache : Default :: default ( ) ,
@@ -718,28 +727,18 @@ impl DepGraph {
718
727
} ;
719
728
720
729
// ... emitting any stored diagnostic ...
721
- if did_allocation {
722
- // Only the thread which did the allocation emits the error messages
723
-
724
- // FIXME: Ensure that these are printed before returning for all threads.
725
- // Currently threads where did_allocation = false can continue on
726
- // and emit other diagnostics before these diagnostics are emitted.
727
- // Such diagnostics should be emitted after these.
728
- // See https://github.com/rust-lang/rust/issues/48685
729
- let diagnostics = tcx. queries . on_disk_cache
730
- . load_diagnostics ( tcx, prev_dep_node_index) ;
731
730
732
- if diagnostics. len ( ) > 0 {
733
- let handle = tcx . sess . diagnostic ( ) ;
731
+ let diagnostics = tcx . queries . on_disk_cache
732
+ . load_diagnostics ( tcx , prev_dep_node_index ) ;
734
733
735
- // Promote the previous diagnostics to the current session.
736
- tcx . queries . on_disk_cache
737
- . store_diagnostics ( dep_node_index , diagnostics . clone ( ) . into ( ) ) ;
738
-
739
- for diagnostic in diagnostics {
740
- DiagnosticBuilder :: new_diagnostic ( handle , diagnostic ) . emit ( ) ;
741
- }
742
- }
734
+ if unlikely ! ( diagnostics. len ( ) > 0 ) {
735
+ self . emit_diagnostics (
736
+ tcx ,
737
+ data ,
738
+ dep_node_index ,
739
+ did_allocation ,
740
+ diagnostics
741
+ ) ;
743
742
}
744
743
745
744
// ... and finally storing a "Green" entry in the color map.
@@ -755,6 +754,49 @@ impl DepGraph {
755
754
Some ( dep_node_index)
756
755
}
757
756
757
+ /// Atomically emits some loaded diagnotics assuming that this only gets called with
758
+ /// did_allocation set to true on one thread
759
+ #[ cold]
760
+ #[ inline( never) ]
761
+ fn emit_diagnostics < ' tcx > (
762
+ & self ,
763
+ tcx : TyCtxt < ' _ , ' tcx , ' tcx > ,
764
+ data : & DepGraphData ,
765
+ dep_node_index : DepNodeIndex ,
766
+ did_allocation : bool ,
767
+ diagnostics : Vec < Diagnostic > ,
768
+ ) {
769
+ if did_allocation || !cfg ! ( parallel_queries) {
770
+ // Only the thread which did the allocation emits the error messages
771
+ let handle = tcx. sess . diagnostic ( ) ;
772
+
773
+ // Promote the previous diagnostics to the current session.
774
+ tcx. queries . on_disk_cache
775
+ . store_diagnostics ( dep_node_index, diagnostics. clone ( ) . into ( ) ) ;
776
+
777
+ for diagnostic in diagnostics {
778
+ DiagnosticBuilder :: new_diagnostic ( handle, diagnostic) . emit ( ) ;
779
+ }
780
+
781
+ #[ cfg( parallel_queries) ]
782
+ {
783
+ // Mark the diagnostics and emitted and wake up waiters
784
+ data. emitted_diagnostics . lock ( ) . insert ( dep_node_index) ;
785
+ data. emitted_diagnostics_cond_var . notify_all ( ) ;
786
+ }
787
+ } else {
788
+ // The other threads will wait for the diagnostics to be emitted
789
+
790
+ let mut emitted_diagnostics = data. emitted_diagnostics . lock ( ) ;
791
+ loop {
792
+ if emitted_diagnostics. contains ( & dep_node_index) {
793
+ break ;
794
+ }
795
+ data. emitted_diagnostics_cond_var . wait ( & mut emitted_diagnostics) ;
796
+ }
797
+ }
798
+ }
799
+
758
800
// Returns true if the given node has been marked as green during the
759
801
// current compilation session. Used in various assertions
760
802
pub fn is_green ( & self , dep_node : & DepNode ) -> bool {
0 commit comments