Skip to content

Commit 6a07f23

Browse files
authored
Rollup merge of #56434 - Zoxc:par-tests, r=michaelwoerister
Improve query cycle errors for parallel queries r? @michaelwoerister
2 parents 6d3501e + 813b484 commit 6a07f23

File tree

4 files changed

+74
-36
lines changed

4 files changed

+74
-36
lines changed

src/librustc/ty/context.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1942,8 +1942,12 @@ pub mod tls {
19421942
/// This is a callback from libsyntax as it cannot access the implicit state
19431943
/// in librustc otherwise
19441944
fn span_debug(span: syntax_pos::Span, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1945-
with(|tcx| {
1946-
write!(f, "{}", tcx.sess.source_map().span_to_string(span))
1945+
with_opt(|tcx| {
1946+
if let Some(tcx) = tcx {
1947+
write!(f, "{}", tcx.sess.source_map().span_to_string(span))
1948+
} else {
1949+
syntax_pos::default_span_debug(span, f)
1950+
}
19471951
})
19481952
}
19491953

src/librustc/ty/query/job.rs

Lines changed: 66 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,11 @@ impl<'tcx> QueryJob<'tcx> {
103103
condvar: Condvar::new(),
104104
});
105105
self.latch.await(&waiter);
106-
107-
match Lrc::get_mut(&mut waiter).unwrap().cycle.get_mut().take() {
106+
// FIXME: Get rid of this lock. We have ownership of the QueryWaiter
107+
// although another thread may still have a Lrc reference so we cannot
108+
// use Lrc::get_mut
109+
let mut cycle = waiter.cycle.lock();
110+
match cycle.take() {
108111
None => Ok(()),
109112
Some(cycle) => Err(cycle)
110113
}
@@ -326,19 +329,17 @@ fn connected_to_root<'tcx>(
326329
query: Lrc<QueryJob<'tcx>>,
327330
visited: &mut FxHashSet<*const QueryJob<'tcx>>
328331
) -> bool {
329-
// This query is connected to the root (it has no query parent), return true
330-
if query.parent.is_none() {
331-
return true;
332-
}
333-
334332
// We already visited this or we're deliberately ignoring it
335333
if visited.contains(&query.as_ptr()) {
336334
return false;
337335
}
338336

339-
visited.insert(query.as_ptr());
337+
// This query is connected to the root (it has no query parent), return true
338+
if query.parent.is_none() {
339+
return true;
340+
}
340341

341-
let mut connected = false;
342+
visited.insert(query.as_ptr());
342343

343344
visit_waiters(query, |_, successor| {
344345
if connected_to_root(successor, visited) {
@@ -349,6 +350,28 @@ fn connected_to_root<'tcx>(
349350
}).is_some()
350351
}
351352

353+
// Deterministically pick an query from a list
354+
#[cfg(parallel_queries)]
355+
fn pick_query<'a, 'tcx, T, F: Fn(&T) -> (Span, Lrc<QueryJob<'tcx>>)>(
356+
tcx: TyCtxt<'_, 'tcx, '_>,
357+
queries: &'a [T],
358+
f: F
359+
) -> &'a T {
360+
// Deterministically pick an entry point
361+
// FIXME: Sort this instead
362+
let mut hcx = tcx.create_stable_hashing_context();
363+
queries.iter().min_by_key(|v| {
364+
let (span, query) = f(v);
365+
let mut stable_hasher = StableHasher::<u64>::new();
366+
query.info.query.hash_stable(&mut hcx, &mut stable_hasher);
367+
// Prefer entry points which have valid spans for nicer error messages
368+
// We add an integer to the tuple ensuring that entry points
369+
// with valid spans are picked first
370+
let span_cmp = if span == DUMMY_SP { 1 } else { 0 };
371+
(span_cmp, stable_hasher.finish())
372+
}).unwrap()
373+
}
374+
352375
/// Looks for query cycles starting from the last query in `jobs`.
353376
/// If a cycle is found, all queries in the cycle is removed from `jobs` and
354377
/// the function return true.
@@ -388,41 +411,52 @@ fn remove_cycle<'tcx>(
388411

389412
// Find the queries in the cycle which are
390413
// connected to queries outside the cycle
391-
let entry_points = stack.iter().filter_map(|query| {
392-
// Mark all the other queries in the cycle as already visited
393-
let mut visited = FxHashSet::from_iter(stack.iter().filter_map(|q| {
394-
if q.1.as_ptr() != query.1.as_ptr() {
395-
Some(q.1.as_ptr())
396-
} else {
414+
let entry_points: Vec<_> = stack.iter().filter_map(|(span, query)| {
415+
if query.parent.is_none() {
416+
// This query is connected to the root (it has no query parent)
417+
Some((*span, query.clone(), None))
418+
} else {
419+
let mut waiters = Vec::new();
420+
// Find all the direct waiters who lead to the root
421+
visit_waiters(query.clone(), |span, waiter| {
422+
// Mark all the other queries in the cycle as already visited
423+
let mut visited = FxHashSet::from_iter(stack.iter().map(|q| q.1.as_ptr()));
424+
425+
if connected_to_root(waiter.clone(), &mut visited) {
426+
waiters.push((span, waiter));
427+
}
428+
429+
None
430+
});
431+
if waiters.is_empty() {
397432
None
433+
} else {
434+
// Deterministically pick one of the waiters to show to the user
435+
let waiter = pick_query(tcx, &waiters, |s| s.clone()).clone();
436+
Some((*span, query.clone(), Some(waiter)))
398437
}
399-
}));
400-
401-
if connected_to_root(query.1.clone(), &mut visited) {
402-
Some(query.1.clone())
403-
} else {
404-
None
405438
}
406-
});
439+
}).collect();
440+
441+
let entry_points: Vec<(Span, Lrc<QueryJob<'tcx>>, Option<(Span, Lrc<QueryJob<'tcx>>)>)>
442+
= entry_points;
407443

408444
// Deterministically pick an entry point
409-
// FIXME: Sort this instead
410-
let mut hcx = tcx.create_stable_hashing_context();
411-
let entry_point = entry_points.min_by_key(|q| {
412-
let mut stable_hasher = StableHasher::<u64>::new();
413-
q.info.query.hash_stable(&mut hcx, &mut stable_hasher);
414-
stable_hasher.finish()
415-
}).unwrap().as_ptr();
445+
let (_, entry_point, usage) = pick_query(tcx, &entry_points, |e| (e.0, e.1.clone()));
416446

417447
// Shift the stack so that our entry point is first
418-
let entry_point_pos = stack.iter().position(|(_, query)| query.as_ptr() == entry_point);
448+
let entry_point_pos = stack.iter().position(|(_, query)| {
449+
query.as_ptr() == entry_point.as_ptr()
450+
});
419451
if let Some(pos) = entry_point_pos {
420-
stack.rotate_right(pos);
452+
stack.rotate_left(pos);
421453
}
422454

455+
let usage = usage.as_ref().map(|(span, query)| (*span, query.info.query.clone()));
456+
423457
// Create the cycle error
424458
let mut error = CycleError {
425-
usage: None,
459+
usage,
426460
cycle: stack.iter().map(|&(s, ref q)| QueryInfo {
427461
span: s,
428462
query: q.info.query.clone(),

src/librustc_driver/test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ fn errors(msgs: &[&str]) -> (Box<dyn Emitter + sync::Send>, usize) {
9898

9999
fn test_env<F>(source_string: &str, args: (Box<dyn Emitter + sync::Send>, usize), body: F)
100100
where
101-
F: FnOnce(Env),
101+
F: FnOnce(Env) + sync::Send,
102102
{
103103
syntax::with_globals(|| {
104104
let mut options = config::Options::default();

src/libsyntax_pos/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -611,7 +611,7 @@ impl serialize::UseSpecializedDecodable for Span {
611611
}
612612
}
613613

614-
fn default_span_debug(span: Span, f: &mut fmt::Formatter) -> fmt::Result {
614+
pub fn default_span_debug(span: Span, f: &mut fmt::Formatter) -> fmt::Result {
615615
f.debug_struct("Span")
616616
.field("lo", &span.lo())
617617
.field("hi", &span.hi())

0 commit comments

Comments
 (0)