Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 367760a

Browse files
committedMar 18, 2025
Avoiding calling queries when collecting active queries
1 parent e8ad42d commit 367760a

File tree

10 files changed

+306
-161
lines changed

10 files changed

+306
-161
lines changed
 

‎compiler/rustc_interface/src/util.rs

+19-19
Original file line numberDiff line numberDiff line change
@@ -188,24 +188,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send,
188188
// On deadlock, creates a new thread and forwards information in thread
189189
// locals to it. The new thread runs the deadlock handler.
190190

191-
// Get a `GlobalCtxt` reference from `CurrentGcx` as we cannot rely on having a
192-
// `TyCtxt` TLS reference here.
193-
let query_map = current_gcx2.access(|gcx| {
194-
tls::enter_context(&tls::ImplicitCtxt::new(gcx), || {
195-
tls::with(|tcx| {
196-
let (query_map, complete) = QueryCtxt::new(tcx).collect_active_jobs();
197-
if !complete {
198-
// There was an unexpected error collecting all active jobs, which we need
199-
// to find cycles to break.
200-
// We want to avoid panicking in the deadlock handler, so we abort instead.
201-
eprintln!("internal compiler error: failed to get query map in deadlock handler, aborting process");
202-
process::abort();
203-
}
204-
query_map
205-
})
206-
})
207-
});
208-
let query_map = FromDyn::from(query_map);
191+
let current_gcx2 = current_gcx2.clone();
209192
let registry = rayon_core::Registry::current();
210193
thread::Builder::new()
211194
.name("rustc query cycle handler".to_string())
@@ -216,7 +199,24 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send,
216199
// otherwise the compiler could just hang,
217200
process::abort();
218201
});
219-
break_query_cycles(query_map.into_inner(), &registry);
202+
203+
// Get a `GlobalCtxt` reference from `CurrentGcx` as we cannot rely on having a
204+
// `TyCtxt` TLS reference here.
205+
current_gcx2.access(|gcx| {
206+
tls::enter_context(&tls::ImplicitCtxt::new(gcx), || {
207+
tls::with(|tcx| {
208+
let (query_map, complete) = QueryCtxt::new(tcx).collect_active_jobs();
209+
if !complete {
210+
// There was an unexpected error collecting all active jobs, which we need
211+
// to find cycles to break.
212+
// We want to avoid panicking in the deadlock handler, so we abort instead.
213+
panic!("failed to get query map in deadlock handler, aborting process");
214+
}
215+
break_query_cycles(query_map, &registry);
216+
})
217+
})
218+
});
219+
220220
on_panic.disable();
221221
})
222222
.unwrap();

‎compiler/rustc_middle/src/query/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ use rustc_index::IndexVec;
3030
use rustc_lint_defs::LintId;
3131
use rustc_macros::rustc_queries;
3232
use rustc_query_system::ich::StableHashingContext;
33-
use rustc_query_system::query::{QueryCache, QueryMode, QueryState, try_get_cached};
33+
use rustc_query_system::query::{
34+
QueryCache, QueryMode, QueryStackDeferred, QueryState, try_get_cached,
35+
};
3436
use rustc_session::Limits;
3537
use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion};
3638
use rustc_session::cstore::{

‎compiler/rustc_middle/src/query/plumbing.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ macro_rules! define_callbacks {
488488
#[derive(Default)]
489489
pub struct QueryStates<'tcx> {
490490
$(
491-
pub $name: QueryState<$($K)*>,
491+
pub $name: QueryState<$($K)*, QueryStackDeferred<'tcx>>,
492492
)*
493493
}
494494

‎compiler/rustc_middle/src/values.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ impl<'tcx> Value<TyCtxt<'tcx>> for Representability {
8888
if info.query.dep_kind == dep_kinds::representability
8989
&& let Some(field_id) = info.query.def_id
9090
&& let Some(field_id) = field_id.as_local()
91-
&& let Some(DefKind::Field) = info.query.def_kind
91+
&& let Some(DefKind::Field) = info.query.info.def_kind
9292
{
9393
let parent_id = tcx.parent(field_id.to_def_id());
9494
let item_id = match tcx.def_kind(parent_id) {
@@ -216,7 +216,7 @@ impl<'tcx, T> Value<TyCtxt<'tcx>> for Result<T, &'_ ty::layout::LayoutError<'_>>
216216
continue;
217217
};
218218
let frame_span =
219-
frame.query.default_span(cycle[(i + 1) % cycle.len()].span);
219+
frame.query.info.default_span(cycle[(i + 1) % cycle.len()].span);
220220
if frame_span.is_dummy() {
221221
continue;
222222
}

‎compiler/rustc_query_impl/src/lib.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ use rustc_middle::ty::TyCtxt;
2626
use rustc_query_system::dep_graph::SerializedDepNodeIndex;
2727
use rustc_query_system::ich::StableHashingContext;
2828
use rustc_query_system::query::{
29-
CycleError, HashResult, QueryCache, QueryConfig, QueryMap, QueryMode, QueryState,
30-
get_query_incr, get_query_non_incr,
29+
CycleError, HashResult, QueryCache, QueryConfig, QueryMap, QueryMode, QueryStackDeferred,
30+
QueryState, get_query_incr, get_query_non_incr,
3131
};
3232
use rustc_query_system::{HandleCycleError, Value};
3333
use rustc_span::{ErrorGuaranteed, Span};
@@ -84,7 +84,10 @@ where
8484
}
8585

8686
#[inline(always)]
87-
fn query_state<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a QueryState<Self::Key>
87+
fn query_state<'a>(
88+
self,
89+
qcx: QueryCtxt<'tcx>,
90+
) -> &'a QueryState<Self::Key, QueryStackDeferred<'tcx>>
8891
where
8992
QueryCtxt<'tcx>: 'a,
9093
{
@@ -93,7 +96,7 @@ where
9396
unsafe {
9497
&*(&qcx.tcx.query_system.states as *const QueryStates<'tcx>)
9598
.byte_add(self.dynamic.query_state)
96-
.cast::<QueryState<Self::Key>>()
99+
.cast::<QueryState<Self::Key, QueryStackDeferred<'tcx>>>()
97100
}
98101
}
99102

‎compiler/rustc_query_impl/src/plumbing.rs

+63-34
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
//! manage the caches, and so forth.
44
55
use std::num::NonZero;
6+
use std::sync::Arc;
67

78
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
8-
use rustc_data_structures::sync::Lock;
9+
use rustc_data_structures::sync::{DynSend, DynSync, Lock};
910
use rustc_data_structures::unord::UnordMap;
1011
use rustc_errors::DiagInner;
1112
use rustc_hashes::Hash64;
@@ -26,8 +27,8 @@ use rustc_middle::ty::{self, TyCtxt};
2627
use rustc_query_system::dep_graph::{DepNodeParams, HasDepContext};
2728
use rustc_query_system::ich::StableHashingContext;
2829
use rustc_query_system::query::{
29-
QueryCache, QueryConfig, QueryContext, QueryJobId, QueryMap, QuerySideEffects, QueryStackFrame,
30-
force_query,
30+
QueryCache, QueryConfig, QueryContext, QueryJobId, QueryMap, QuerySideEffects,
31+
QueryStackDeferred, QueryStackFrame, QueryStackFrameExtra, force_query,
3132
};
3233
use rustc_query_system::{QueryOverflow, QueryOverflowNote};
3334
use rustc_serialize::{Decodable, Encodable};
@@ -68,7 +69,9 @@ impl<'tcx> HasDepContext for QueryCtxt<'tcx> {
6869
}
6970
}
7071

71-
impl QueryContext for QueryCtxt<'_> {
72+
impl<'tcx> QueryContext for QueryCtxt<'tcx> {
73+
type QueryInfo = QueryStackDeferred<'tcx>;
74+
7275
#[inline]
7376
fn next_job_id(self) -> QueryJobId {
7477
QueryJobId(
@@ -84,7 +87,7 @@ impl QueryContext for QueryCtxt<'_> {
8487

8588
/// Returns a query map representing active query jobs and a bool being false
8689
/// if there was an error constructing the map.
87-
fn collect_active_jobs(self) -> (QueryMap, bool) {
90+
fn collect_active_jobs(self) -> (QueryMap<QueryStackDeferred<'tcx>>, bool) {
8891
let mut jobs = QueryMap::default();
8992
let mut complete = true;
9093

@@ -95,6 +98,13 @@ impl QueryContext for QueryCtxt<'_> {
9598
(jobs, complete)
9699
}
97100

101+
fn lift_query_info(
102+
self,
103+
info: &QueryStackDeferred<'tcx>,
104+
) -> rustc_query_system::query::QueryStackFrameExtra {
105+
info.extract()
106+
}
107+
98108
// Interactions with on_disk_cache
99109
fn load_side_effects(self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects {
100110
self.query_system
@@ -168,7 +178,10 @@ impl QueryContext for QueryCtxt<'_> {
168178

169179
self.sess.dcx().emit_fatal(QueryOverflow {
170180
span: info.job.span,
171-
note: QueryOverflowNote { desc: info.query.description, depth },
181+
note: QueryOverflowNote {
182+
desc: self.lift_query_info(&info.query.info).description,
183+
depth,
184+
},
172185
suggested_limit,
173186
crate_name: self.crate_name(LOCAL_CRATE),
174187
});
@@ -307,39 +320,45 @@ macro_rules! should_ever_cache_on_disk {
307320

308321
pub(crate) fn create_query_frame<
309322
'tcx,
310-
K: Copy + Key + for<'a> HashStable<StableHashingContext<'a>>,
323+
K: Copy + DynSend + DynSync + Key + for<'a> HashStable<StableHashingContext<'a>> + 'tcx,
311324
>(
312325
tcx: TyCtxt<'tcx>,
313326
do_describe: fn(TyCtxt<'tcx>, K) -> String,
314327
key: K,
315328
kind: DepKind,
316329
name: &'static str,
317-
) -> QueryStackFrame {
318-
// If reduced queries are requested, we may be printing a query stack due
319-
// to a panic. Avoid using `default_span` and `def_kind` in that case.
320-
let reduce_queries = with_reduced_queries();
321-
322-
// Avoid calling queries while formatting the description
323-
let description = ty::print::with_no_queries!(do_describe(tcx, key));
324-
let description = if tcx.sess.verbose_internals() {
325-
format!("{description} [{name:?}]")
326-
} else {
327-
description
328-
};
329-
let span = if kind == dep_graph::dep_kinds::def_span || reduce_queries {
330-
// The `def_span` query is used to calculate `default_span`,
331-
// so exit to avoid infinite recursion.
332-
None
333-
} else {
334-
Some(key.default_span(tcx))
335-
};
330+
) -> QueryStackFrame<QueryStackDeferred<'tcx>> {
336331
let def_id = key.key_as_def_id();
337-
let def_kind = if kind == dep_graph::dep_kinds::def_kind || reduce_queries {
338-
// Try to avoid infinite recursion.
339-
None
340-
} else {
341-
def_id.and_then(|def_id| def_id.as_local()).map(|def_id| tcx.def_kind(def_id))
332+
333+
let extra = move || {
334+
// If reduced queries are requested, we may be printing a query stack due
335+
// to a panic. Avoid using `default_span` and `def_kind` in that case.
336+
let reduce_queries = with_reduced_queries();
337+
338+
// Avoid calling queries while formatting the description
339+
let description = ty::print::with_no_queries!(do_describe(tcx, key));
340+
let description = if tcx.sess.verbose_internals() {
341+
format!("{description} [{name:?}]")
342+
} else {
343+
description
344+
};
345+
let span = if kind == dep_graph::dep_kinds::def_span || reduce_queries {
346+
// The `def_span` query is used to calculate `default_span`,
347+
// so exit to avoid infinite recursion.
348+
None
349+
} else {
350+
Some(key.default_span(tcx))
351+
};
352+
353+
let def_kind = if kind == dep_graph::dep_kinds::def_kind || reduce_queries {
354+
// Try to avoid infinite recursion.
355+
None
356+
} else {
357+
def_id.and_then(|def_id| def_id.as_local()).map(|def_id| tcx.def_kind(def_id))
358+
};
359+
QueryStackFrameExtra::new(description, span, def_kind)
342360
};
361+
343362
let hash = || {
344363
tcx.with_stable_hashing_context(|mut hcx| {
345364
let mut hasher = StableHasher::new();
@@ -350,7 +369,11 @@ pub(crate) fn create_query_frame<
350369
};
351370
let def_id_for_ty_in_cycle = key.def_id_for_ty_in_cycle();
352371

353-
QueryStackFrame::new(description, span, def_id, def_kind, kind, def_id_for_ty_in_cycle, hash)
372+
// SAFETY: None of the captures in `extra` have destructors that access 'tcx
373+
// as they don't have destructors.
374+
let info = unsafe { QueryStackDeferred::new(Arc::new(extra)) };
375+
376+
QueryStackFrame::new(info, kind, hash, def_id, def_id_for_ty_in_cycle)
354377
}
355378

356379
pub(crate) fn encode_query_results<'a, 'tcx, Q>(
@@ -697,7 +720,11 @@ macro_rules! define_queries {
697720
}
698721
}
699722

700-
pub(crate) fn try_collect_active_jobs<'tcx>(tcx: TyCtxt<'tcx>, qmap: &mut QueryMap, complete: &mut bool) {
723+
pub(crate) fn try_collect_active_jobs<'tcx>(
724+
tcx: TyCtxt<'tcx>,
725+
qmap: &mut QueryMap<QueryStackDeferred<'tcx>>,
726+
complete: &mut bool
727+
) {
701728
let make_query = |tcx, key| {
702729
let kind = rustc_middle::dep_graph::dep_kinds::$name;
703730
let name = stringify!($name);
@@ -777,7 +804,9 @@ macro_rules! define_queries {
777804

778805
// These arrays are used for iteration and can't be indexed by `DepKind`.
779806

780-
const TRY_COLLECT_ACTIVE_JOBS: &[for<'tcx> fn(TyCtxt<'tcx>, &mut QueryMap, &mut bool)] =
807+
const TRY_COLLECT_ACTIVE_JOBS: &[
808+
for<'tcx> fn(TyCtxt<'tcx>, &mut QueryMap<QueryStackDeferred<'tcx>>, &mut bool)
809+
] =
781810
&[$(query_impl::$name::try_collect_active_jobs),*];
782811

783812
const ALLOC_SELF_PROFILE_QUERY_STRINGS: &[

‎compiler/rustc_query_system/src/query/config.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::hash::Hash;
66
use rustc_data_structures::fingerprint::Fingerprint;
77
use rustc_span::ErrorGuaranteed;
88

9+
use super::QueryStackFrameExtra;
910
use crate::dep_graph::{DepKind, DepNode, DepNodeParams, SerializedDepNodeIndex};
1011
use crate::error::HandleCycleError;
1112
use crate::ich::StableHashingContext;
@@ -27,7 +28,7 @@ pub trait QueryConfig<Qcx: QueryContext>: Copy {
2728
fn format_value(self) -> fn(&Self::Value) -> String;
2829

2930
// Don't use this method to access query results, instead use the methods on TyCtxt
30-
fn query_state<'a>(self, tcx: Qcx) -> &'a QueryState<Self::Key>
31+
fn query_state<'a>(self, tcx: Qcx) -> &'a QueryState<Self::Key, Qcx::QueryInfo>
3132
where
3233
Qcx: 'a;
3334

@@ -57,7 +58,7 @@ pub trait QueryConfig<Qcx: QueryContext>: Copy {
5758
fn value_from_cycle_error(
5859
self,
5960
tcx: Qcx::DepContext,
60-
cycle_error: &CycleError,
61+
cycle_error: &CycleError<QueryStackFrameExtra>,
6162
guar: ErrorGuaranteed,
6263
) -> Self::Value;
6364

There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Failed to load comments.