Skip to content

Commit f23b63c

Browse files
committed
Auto merge of rust-lang#57066 - Zoxc:graph-race, r=michaelwoerister
Fix race condition when emitting stored diagnostics r? @michaelwoerister
2 parents cd3d580 + b2dfd96 commit f23b63c

File tree

1 file changed

+63
-21
lines changed

1 file changed

+63
-21
lines changed

src/librustc/dep_graph/graph.rs

Lines changed: 63 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use errors::DiagnosticBuilder;
1+
use errors::{Diagnostic, DiagnosticBuilder};
22
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
33
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
44
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
@@ -9,6 +9,7 @@ use std::hash::Hash;
99
use std::collections::hash_map::Entry;
1010
use ty::{self, TyCtxt};
1111
use util::common::{ProfileQueriesMsg, profq_msg};
12+
use parking_lot::{Mutex, Condvar};
1213

1314
use 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

Comments
 (0)