1- use errors:: DiagnosticBuilder ;
1+ use errors:: { Diagnostic , DiagnosticBuilder } ;
22use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher } ;
33use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
44use rustc_data_structures:: indexed_vec:: { Idx , IndexVec } ;
@@ -9,6 +9,7 @@ use std::hash::Hash;
99use std:: collections:: hash_map:: Entry ;
1010use ty:: { self , TyCtxt } ;
1111use util:: common:: { ProfileQueriesMsg , profq_msg} ;
12+ use parking_lot:: { Mutex , Condvar } ;
1213
1314use ich:: { StableHashingContext , StableHashingContextProvider , Fingerprint } ;
1415
@@ -60,6 +61,12 @@ struct DepGraphData {
6061
6162 colors : DepNodeColorMap ,
6263
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+
6370 /// When we load, there may be `.o` files, cached mir, or other such
6471 /// things available to us. If we find that they are not dirty, we
6572 /// load the path to the file storing those work-products here into
@@ -83,6 +90,8 @@ impl DepGraph {
8390 previous_work_products : prev_work_products,
8491 dep_node_debug : Default :: default ( ) ,
8592 current : Lock :: new ( CurrentDepGraph :: new ( prev_graph_node_count) ) ,
93+ emitted_diagnostics : Default :: default ( ) ,
94+ emitted_diagnostics_cond_var : Condvar :: new ( ) ,
8695 previous : prev_graph,
8796 colors : DepNodeColorMap :: new ( prev_graph_node_count) ,
8897 loaded_from_cache : Default :: default ( ) ,
@@ -718,28 +727,18 @@ impl DepGraph {
718727 } ;
719728
720729 // ... 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) ;
731730
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 ) ;
734733
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+ ) ;
743742 }
744743
745744 // ... and finally storing a "Green" entry in the color map.
@@ -755,6 +754,49 @@ impl DepGraph {
755754 Some ( dep_node_index)
756755 }
757756
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+
758800 // Returns true if the given node has been marked as green during the
759801 // current compilation session. Used in various assertions
760802 pub fn is_green ( & self , dep_node : & DepNode ) -> bool {
0 commit comments