Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions compiler/rustc_interface/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,20 +249,22 @@ internal compiler error: query cycle handler thread panicked, aborting process";
tls::enter_context(&tls::ImplicitCtxt::new(gcx), || {
tls::with(|tcx| {
// Accessing session globals is sound as they outlive `GlobalCtxt`.
// They are needed to hash query keys containing spans or symbols.
let job_map = rustc_span::set_session_globals_then(
// They are needed to hash query keys containing spans or symbols,
// and to print query descriptions while breaking the cycle, so the
// whole cycle search runs inside this scope.
rustc_span::set_session_globals_then(
unsafe { &*(session_globals as *const SessionGlobals) },
|| {
// Ensure there were no errors collecting all active jobs.
// We need the complete map to ensure we find a cycle to
// break.
collect_active_query_jobs(
let job_map = collect_active_query_jobs(
tcx,
CollectActiveJobsKind::FullNoContention,
)
);
break_query_cycle(tcx, job_map, &registry);
},
);
break_query_cycle(job_map, &registry);
})
})
});
Expand Down
52 changes: 45 additions & 7 deletions compiler/rustc_query_impl/src/job.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,11 @@ fn connected_to_root<'tcx>(
}

/// Processes a found query cycle into a `Cycle`
fn process_cycle<'tcx>(job_map: &QueryJobMap<'tcx>, stack: Vec<(Span, QueryJobId)>) -> Cycle<'tcx> {
fn process_cycle<'tcx>(
tcx: TyCtxt<'tcx>,
job_map: &QueryJobMap<'tcx>,
stack: Vec<(Span, QueryJobId)>,
) -> Cycle<'tcx> {
// The stack is a vector of pairs of spans and queries; reverse it so that
// the earlier entries require later entries
let (mut spans, queries): (Vec<_>, Vec<_>) = stack.into_iter().rev().unzip();
Expand Down Expand Up @@ -277,11 +281,40 @@ fn process_cycle<'tcx>(job_map: &QueryJobMap<'tcx>, stack: Vec<(Span, QueryJobId
})
.collect::<Vec<EntryPoint>>();

// Pick an entry point, preferring ones with waiters
// The query jobs in the cycle carry no useful span of their own here (it is
// `DUMMY_SP`), but the cycle stack records, for each query, its incoming edge:
// the span where its predecessor in the cycle requested it.
let stack_span = |query: QueryJobId| {
stack.iter().find(|(_, q)| *q == query).map_or(DUMMY_SP, |&(span, _)| span)
};

// Pick an entry point using a deterministic total order. The parallel
// deadlock handler collects active query jobs in a nondeterministic order,
// so both the order of `entry_points` and the original `entry_points[0]`
// fallback are racy, which made the reported cycle anchor change from run to
// run.
//
// For the recursive-definition cycles these errors come from, the entry
// point with the latest incoming-edge span is the query the single-threaded
// path anchors at (the one entered first), so ordering by that span keeps
// the parallel output matching the committed `.stderr`. Span ties prefer an
// entry point with an outside waiter, so the "cycle used when ..." note is
// still produced, and any remaining ties are broken by the query's stable
// description so the choice stays deterministic across runs even if two
// entry points share a span.
let description = |query: QueryJobId| job_map.tagged_key_of(query).description(tcx);
let entry_point = entry_points
.iter()
.find(|entry_point| entry_point.query_waiting_on_cycle.is_some())
.unwrap_or(&entry_points[0]);
.max_by(|a, b| {
let (sa, sb) = (stack_span(a.query_in_cycle), stack_span(b.query_in_cycle));
(sa.lo(), sa.hi())
.cmp(&(sb.lo(), sb.hi()))
.then_with(|| {
a.query_waiting_on_cycle.is_some().cmp(&b.query_waiting_on_cycle.is_some())
})
.then_with(|| description(a.query_in_cycle).cmp(&description(b.query_in_cycle)))
})
.expect("a query cycle must have at least one entry point");

// Shift the stack so that our entry point is first
let entry_point_pos = stack.iter().position(|(_, query)| *query == entry_point.query_in_cycle);
Expand All @@ -306,6 +339,7 @@ fn process_cycle<'tcx>(job_map: &QueryJobMap<'tcx>, stack: Vec<(Span, QueryJobId
/// Looks for a query cycle starting at `query`.
/// Returns a waiter to resume if a cycle is found.
fn find_and_process_cycle<'tcx>(
tcx: TyCtxt<'tcx>,
job_map: &QueryJobMap<'tcx>,
query: QueryJobId,
) -> Option<Arc<QueryWaiter<'tcx>>> {
Expand All @@ -315,7 +349,7 @@ fn find_and_process_cycle<'tcx>(
find_cycle(job_map, query, DUMMY_SP, &mut stack, &mut visited)
{
// Create the cycle error
let error = process_cycle(job_map, stack);
let error = process_cycle(tcx, job_map, stack);

// We unwrap `resumable` here since there must always be one
// edge which is resumable / waited using a query latch
Expand All @@ -341,12 +375,16 @@ fn find_and_process_cycle<'tcx>(
/// There may be multiple cycles involved in a deadlock, but this only breaks one at a time so
/// there will be multiple rounds through the deadlock handler if multiple cycles are present.
#[allow(rustc::potential_query_instability)]
pub fn break_query_cycle<'tcx>(job_map: QueryJobMap<'tcx>, registry: &rustc_thread_pool::Registry) {
pub fn break_query_cycle<'tcx>(
tcx: TyCtxt<'tcx>,
job_map: QueryJobMap<'tcx>,
registry: &rustc_thread_pool::Registry,
) {
// Look for a cycle starting at each query job
let waiter = job_map
.map
.keys()
.find_map(|query| find_and_process_cycle(&job_map, *query))
.find_map(|query| find_and_process_cycle(tcx, &job_map, *query))
.expect("unable to find a query cycle");

// Mark the thread we're about to wake up as unblocked.
Expand Down
6 changes: 3 additions & 3 deletions tests/ui/consts/recursive-zst-static.default.stderr
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
error[E0080]: encountered static that tried to access itself during initialization
--> $DIR/recursive-zst-static.rs:10:18
--> $DIR/recursive-zst-static.rs:9:18
|
LL | static FOO: () = FOO;
| ^^^ evaluation of `FOO` failed here

error[E0391]: cycle detected when evaluating initializer of static `A`
--> $DIR/recursive-zst-static.rs:13:1
--> $DIR/recursive-zst-static.rs:12:1
|
LL | static A: () = B;
| ^^^^^^^^^^^^
|
note: ...which requires evaluating initializer of static `B`...
--> $DIR/recursive-zst-static.rs:14:1
--> $DIR/recursive-zst-static.rs:13:1
|
LL | static B: () = A;
| ^^^^^^^^^^^^
Expand Down
1 change: 0 additions & 1 deletion tests/ui/consts/recursive-zst-static.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//@ revisions: default unleash
//@[unleash]compile-flags: -Zunleash-the-miri-inside-of-you
//@ ignore-parallel-frontend query cycle
// This test ensures that we do not allow ZST statics to initialize themselves without ever
// actually creating a value of that type. This is important, as the ZST may have private fields
// that users can reasonably expect to only get initialized by their own code. Thus unsafe code
Expand Down
6 changes: 3 additions & 3 deletions tests/ui/consts/recursive-zst-static.unleash.stderr
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
error[E0080]: encountered static that tried to access itself during initialization
--> $DIR/recursive-zst-static.rs:10:18
--> $DIR/recursive-zst-static.rs:9:18
|
LL | static FOO: () = FOO;
| ^^^ evaluation of `FOO` failed here

error[E0391]: cycle detected when evaluating initializer of static `A`
--> $DIR/recursive-zst-static.rs:13:1
--> $DIR/recursive-zst-static.rs:12:1
|
LL | static A: () = B;
| ^^^^^^^^^^^^
|
note: ...which requires evaluating initializer of static `B`...
--> $DIR/recursive-zst-static.rs:14:1
--> $DIR/recursive-zst-static.rs:13:1
|
LL | static B: () = A;
| ^^^^^^^^^^^^
Expand Down
1 change: 0 additions & 1 deletion tests/ui/cycle-trait/issue-12511.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
trait T1 : T2 {
//~^ ERROR cycle detected
}
//@ ignore-parallel-frontend query cycle
trait T2 : T1 {
}

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/cycle-trait/issue-12511.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ LL | trait T1 : T2 {
| ^^
|
note: ...which requires computing the super predicates of `T2`...
--> $DIR/issue-12511.rs:5:12
--> $DIR/issue-12511.rs:4:12
|
LL | trait T2 : T1 {
| ^^
Expand Down
26 changes: 13 additions & 13 deletions tests/ui/delegation/unsupported.current.stderr
Original file line number Diff line number Diff line change
@@ -1,43 +1,43 @@
error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:29:5: 29:24>::opaque_ret::{anon_assoc#0}`
--> $DIR/unsupported.rs:30:25
error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:28:5: 28:24>::opaque_ret::{anon_assoc#0}`
--> $DIR/unsupported.rs:29:25
|
LL | reuse to_reuse::opaque_ret;
| ^^^^^^^^^^
|
note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process...
--> $DIR/unsupported.rs:30:25
--> $DIR/unsupported.rs:29:25
|
LL | reuse to_reuse::opaque_ret;
| ^^^^^^^^^^
= note: ...which again requires computing type of `opaque::<impl at $DIR/unsupported.rs:29:5: 29:24>::opaque_ret::{anon_assoc#0}`, completing the cycle
note: cycle used when checking assoc item `opaque::<impl at $DIR/unsupported.rs:29:5: 29:24>::opaque_ret` is compatible with trait definition
--> $DIR/unsupported.rs:30:25
= note: ...which again requires computing type of `opaque::<impl at $DIR/unsupported.rs:28:5: 28:24>::opaque_ret::{anon_assoc#0}`, completing the cycle
note: cycle used when checking assoc item `opaque::<impl at $DIR/unsupported.rs:28:5: 28:24>::opaque_ret` is compatible with trait definition
--> $DIR/unsupported.rs:29:25
|
LL | reuse to_reuse::opaque_ret;
| ^^^^^^^^^^
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information

error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:32:5: 32:25>::opaque_ret::{anon_assoc#0}`
--> $DIR/unsupported.rs:33:24
error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:31:5: 31:25>::opaque_ret::{anon_assoc#0}`
--> $DIR/unsupported.rs:32:24
|
LL | reuse ToReuse::opaque_ret;
| ^^^^^^^^^^
|
note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process...
--> $DIR/unsupported.rs:33:24
--> $DIR/unsupported.rs:32:24
|
LL | reuse ToReuse::opaque_ret;
| ^^^^^^^^^^
= note: ...which again requires computing type of `opaque::<impl at $DIR/unsupported.rs:32:5: 32:25>::opaque_ret::{anon_assoc#0}`, completing the cycle
note: cycle used when checking assoc item `opaque::<impl at $DIR/unsupported.rs:32:5: 32:25>::opaque_ret` is compatible with trait definition
--> $DIR/unsupported.rs:33:24
= note: ...which again requires computing type of `opaque::<impl at $DIR/unsupported.rs:31:5: 31:25>::opaque_ret::{anon_assoc#0}`, completing the cycle
note: cycle used when checking assoc item `opaque::<impl at $DIR/unsupported.rs:31:5: 31:25>::opaque_ret` is compatible with trait definition
--> $DIR/unsupported.rs:32:24
|
LL | reuse ToReuse::opaque_ret;
| ^^^^^^^^^^
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information

error: delegation self type is not specified
--> $DIR/unsupported.rs:54:18
--> $DIR/unsupported.rs:53:18
|
LL | reuse Trait::foo;
| ^^^
Expand Down
26 changes: 13 additions & 13 deletions tests/ui/delegation/unsupported.next.stderr
Original file line number Diff line number Diff line change
@@ -1,43 +1,43 @@
error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:29:5: 29:24>::opaque_ret::{anon_assoc#0}`
--> $DIR/unsupported.rs:30:25
error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:28:5: 28:24>::opaque_ret::{anon_assoc#0}`
--> $DIR/unsupported.rs:29:25
|
LL | reuse to_reuse::opaque_ret;
| ^^^^^^^^^^
|
note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process...
--> $DIR/unsupported.rs:30:25
--> $DIR/unsupported.rs:29:25
|
LL | reuse to_reuse::opaque_ret;
| ^^^^^^^^^^
= note: ...which again requires computing type of `opaque::<impl at $DIR/unsupported.rs:29:5: 29:24>::opaque_ret::{anon_assoc#0}`, completing the cycle
note: cycle used when checking assoc item `opaque::<impl at $DIR/unsupported.rs:29:5: 29:24>::opaque_ret` is compatible with trait definition
--> $DIR/unsupported.rs:30:25
= note: ...which again requires computing type of `opaque::<impl at $DIR/unsupported.rs:28:5: 28:24>::opaque_ret::{anon_assoc#0}`, completing the cycle
note: cycle used when checking assoc item `opaque::<impl at $DIR/unsupported.rs:28:5: 28:24>::opaque_ret` is compatible with trait definition
--> $DIR/unsupported.rs:29:25
|
LL | reuse to_reuse::opaque_ret;
| ^^^^^^^^^^
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information

error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:32:5: 32:25>::opaque_ret::{anon_assoc#0}`
--> $DIR/unsupported.rs:33:24
error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:31:5: 31:25>::opaque_ret::{anon_assoc#0}`
--> $DIR/unsupported.rs:32:24
|
LL | reuse ToReuse::opaque_ret;
| ^^^^^^^^^^
|
note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process...
--> $DIR/unsupported.rs:33:24
--> $DIR/unsupported.rs:32:24
|
LL | reuse ToReuse::opaque_ret;
| ^^^^^^^^^^
= note: ...which again requires computing type of `opaque::<impl at $DIR/unsupported.rs:32:5: 32:25>::opaque_ret::{anon_assoc#0}`, completing the cycle
note: cycle used when checking assoc item `opaque::<impl at $DIR/unsupported.rs:32:5: 32:25>::opaque_ret` is compatible with trait definition
--> $DIR/unsupported.rs:33:24
= note: ...which again requires computing type of `opaque::<impl at $DIR/unsupported.rs:31:5: 31:25>::opaque_ret::{anon_assoc#0}`, completing the cycle
note: cycle used when checking assoc item `opaque::<impl at $DIR/unsupported.rs:31:5: 31:25>::opaque_ret` is compatible with trait definition
--> $DIR/unsupported.rs:32:24
|
LL | reuse ToReuse::opaque_ret;
| ^^^^^^^^^^
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information

error: delegation self type is not specified
--> $DIR/unsupported.rs:54:18
--> $DIR/unsupported.rs:53:18
|
LL | reuse Trait::foo;
| ^^^
Expand Down
1 change: 0 additions & 1 deletion tests/ui/delegation/unsupported.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
//@ check-fail
//@ ignore-parallel-frontend query cycle
// Next solver revision included because of trait-system-refactor-initiative#234.
// If we end up in a query cycle, it should be okay as long as results are the same.

Expand Down
1 change: 0 additions & 1 deletion tests/ui/infinite/infinite-trait-alias-recursion.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#![feature(trait_alias)]
//@ ignore-parallel-frontend query cycle
trait T1 = T2;
//~^ ERROR cycle detected when computing the implied predicates of `T1`

Expand Down
8 changes: 4 additions & 4 deletions tests/ui/infinite/infinite-trait-alias-recursion.stderr
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
error[E0391]: cycle detected when computing the implied predicates of `T1`
--> $DIR/infinite-trait-alias-recursion.rs:3:12
--> $DIR/infinite-trait-alias-recursion.rs:2:12
|
LL | trait T1 = T2;
| ^^
|
note: ...which requires computing the implied predicates of `T2`...
--> $DIR/infinite-trait-alias-recursion.rs:6:12
--> $DIR/infinite-trait-alias-recursion.rs:5:12
|
LL | trait T2 = T3;
| ^^
note: ...which requires computing the implied predicates of `T3`...
--> $DIR/infinite-trait-alias-recursion.rs:8:12
--> $DIR/infinite-trait-alias-recursion.rs:7:12
|
LL | trait T3 = T1 + T3;
| ^^
= note: ...which again requires computing the implied predicates of `T1`, completing the cycle
= note: trait aliases cannot be recursive
note: cycle used when checking that `T1` is well-formed
--> $DIR/infinite-trait-alias-recursion.rs:3:1
--> $DIR/infinite-trait-alias-recursion.rs:2:1
|
LL | trait T1 = T2;
| ^^^^^^^^
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
error[E0271]: type mismatch resolving `X3 normalizes-to _`
--> $DIR/infinite-type-alias-mutual-recursion.rs:12:1
--> $DIR/infinite-type-alias-mutual-recursion.rs:11:1
|
LL | type X1 = X2;
| ^^^^^^^ types differ

error[E0271]: type mismatch resolving `X1 normalizes-to _`
--> $DIR/infinite-type-alias-mutual-recursion.rs:16:1
--> $DIR/infinite-type-alias-mutual-recursion.rs:15:1
|
LL | type X2 = X3;
| ^^^^^^^ types differ

error[E0271]: type mismatch resolving `X2 normalizes-to _`
--> $DIR/infinite-type-alias-mutual-recursion.rs:19:1
--> $DIR/infinite-type-alias-mutual-recursion.rs:18:1
|
LL | type X3 = X1;
| ^^^^^^^ types differ
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
error[E0275]: overflow normalizing the type alias `X2`
--> $DIR/infinite-type-alias-mutual-recursion.rs:12:1
--> $DIR/infinite-type-alias-mutual-recursion.rs:11:1
|
LL | type X1 = X2;
| ^^^^^^^
|
= note: in case this is a recursive type alias, consider using a struct, enum, or union instead

error[E0275]: overflow normalizing the type alias `X3`
--> $DIR/infinite-type-alias-mutual-recursion.rs:16:1
--> $DIR/infinite-type-alias-mutual-recursion.rs:15:1
|
LL | type X2 = X3;
| ^^^^^^^
|
= note: in case this is a recursive type alias, consider using a struct, enum, or union instead

error[E0275]: overflow normalizing the type alias `X1`
--> $DIR/infinite-type-alias-mutual-recursion.rs:19:1
--> $DIR/infinite-type-alias-mutual-recursion.rs:18:1
|
LL | type X3 = X1;
| ^^^^^^^
Expand Down
Loading
Loading