Skip to content

Commit aa2efbc

Browse files
authored
Rollup merge of #153492 - Zoxc:querykeyid, r=nnethercote
Add a `TaggedQueryKey` to identify a query instance This adds back a `TaggedQueryKey` enum which represents a query kind and the associated key. This is used to replace `QueryStackDeferred` and `QueryStackFrameExtra` and the associated lifting operation for cycle errors This approach has a couple of benefits: - We only run description queries when printing the query stack trace in the panic handler - The unsafe code for `QueryStackDeferred` is removed - Cycle handles have access to query keys, which may be handy Some further work could be replacing `QueryStackFrame` with `TaggedQueryKey` as the extra information can be derived from it.
2 parents ea77acf + 85967c4 commit aa2efbc

File tree

11 files changed

+140
-221
lines changed

11 files changed

+140
-221
lines changed

Cargo.lock

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4575,7 +4575,6 @@ dependencies = [
45754575
"rustc_macros",
45764576
"rustc_middle",
45774577
"rustc_serialize",
4578-
"rustc_session",
45794578
"rustc_span",
45804579
"rustc_thread_pool",
45814580
"tracing",

compiler/rustc_middle/src/query/job.rs

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,15 @@ use parking_lot::{Condvar, Mutex};
77
use rustc_span::Span;
88

99
use crate::query::plumbing::CycleError;
10-
use crate::query::stack::{QueryStackDeferred, QueryStackFrame, QueryStackFrameExtra};
10+
use crate::query::stack::QueryStackFrame;
1111
use crate::ty::TyCtxt;
1212

1313
/// Represents a span and a query key.
1414
#[derive(Clone, Debug)]
15-
pub struct QueryInfo<I> {
15+
pub struct QueryInfo<'tcx> {
1616
/// The span corresponding to the reason for which this query was required.
1717
pub span: Span,
18-
pub frame: QueryStackFrame<I>,
19-
}
20-
21-
impl<'tcx> QueryInfo<QueryStackDeferred<'tcx>> {
22-
pub(crate) fn lift(&self) -> QueryInfo<QueryStackFrameExtra> {
23-
QueryInfo { span: self.span, frame: self.frame.lift() }
24-
}
18+
pub frame: QueryStackFrame<'tcx>,
2519
}
2620

2721
/// A value uniquely identifying an active query job.
@@ -74,7 +68,7 @@ pub struct QueryWaiter<'tcx> {
7468
pub query: Option<QueryJobId>,
7569
pub condvar: Condvar,
7670
pub span: Span,
77-
pub cycle: Mutex<Option<CycleError<QueryStackDeferred<'tcx>>>>,
71+
pub cycle: Mutex<Option<CycleError<'tcx>>>,
7872
}
7973

8074
#[derive(Clone, Debug)]
@@ -94,7 +88,7 @@ impl<'tcx> QueryLatch<'tcx> {
9488
tcx: TyCtxt<'tcx>,
9589
query: Option<QueryJobId>,
9690
span: Span,
97-
) -> Result<(), CycleError<QueryStackDeferred<'tcx>>> {
91+
) -> Result<(), CycleError<'tcx>> {
9892
let mut waiters_guard = self.waiters.lock();
9993
let Some(waiters) = &mut *waiters_guard else {
10094
return Ok(()); // already complete

compiler/rustc_middle/src/query/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ pub use self::plumbing::{
77
ActiveKeyStatus, CycleError, CycleErrorHandling, EnsureMode, IntoQueryParam, QueryMode,
88
QueryState, TyCtxtAt, TyCtxtEnsureDone, TyCtxtEnsureOk, TyCtxtEnsureResult,
99
};
10-
pub use self::stack::{QueryStackDeferred, QueryStackFrame, QueryStackFrameExtra};
10+
pub use self::stack::QueryStackFrame;
1111
pub use crate::queries::Providers;
1212
use crate::ty::TyCtxt;
1313

compiler/rustc_middle/src/query/plumbing.rs

Lines changed: 70 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ pub use sealed::IntoQueryParam;
1212

1313
use crate::dep_graph::{DepKind, DepNodeIndex, SerializedDepNodeIndex};
1414
use crate::ich::StableHashingContext;
15-
use crate::queries::{ExternProviders, Providers, QueryArenas, QueryVTables};
15+
use crate::queries::{ExternProviders, Providers, QueryArenas, QueryVTables, TaggedQueryKey};
1616
use crate::query::on_disk_cache::OnDiskCache;
17-
use crate::query::stack::{QueryStackDeferred, QueryStackFrame, QueryStackFrameExtra};
17+
use crate::query::stack::QueryStackFrame;
1818
use crate::query::{QueryCache, QueryInfo, QueryJob};
1919
use crate::ty::TyCtxt;
2020

@@ -60,19 +60,10 @@ pub enum CycleErrorHandling {
6060
}
6161

6262
#[derive(Clone, Debug)]
63-
pub struct CycleError<I = QueryStackFrameExtra> {
63+
pub struct CycleError<'tcx> {
6464
/// The query and related span that uses the cycle.
65-
pub usage: Option<(Span, QueryStackFrame<I>)>,
66-
pub cycle: Vec<QueryInfo<I>>,
67-
}
68-
69-
impl<'tcx> CycleError<QueryStackDeferred<'tcx>> {
70-
pub fn lift(&self) -> CycleError<QueryStackFrameExtra> {
71-
CycleError {
72-
usage: self.usage.as_ref().map(|(span, frame)| (*span, frame.lift())),
73-
cycle: self.cycle.iter().map(|info| info.lift()).collect(),
74-
}
75-
}
65+
pub usage: Option<(Span, QueryStackFrame<'tcx>)>,
66+
pub cycle: Vec<QueryInfo<'tcx>>,
7667
}
7768

7869
#[derive(Debug)]
@@ -139,16 +130,12 @@ pub struct QueryVTable<'tcx, C: QueryCache> {
139130
pub value_from_cycle_error: fn(
140131
tcx: TyCtxt<'tcx>,
141132
key: C::Key,
142-
cycle_error: CycleError,
133+
cycle_error: CycleError<'tcx>,
143134
guar: ErrorGuaranteed,
144135
) -> C::Value,
145136
pub format_value: fn(&C::Value) -> String,
146137

147-
/// Formats a human-readable description of this query and its key, as
148-
/// specified by the `desc` query modifier.
149-
///
150-
/// Used when reporting query cycle errors and similar problems.
151-
pub description_fn: fn(TyCtxt<'tcx>, C::Key) -> String,
138+
pub create_tagged_key: fn(C::Key) -> TaggedQueryKey<'tcx>,
152139

153140
/// Function pointer that is called by the query methods on [`TyCtxt`] and
154141
/// friends[^1], after they have checked the in-memory cache and found no
@@ -523,6 +510,69 @@ macro_rules! define_callbacks {
523510
}
524511
)*
525512

513+
/// Identifies a query by kind and key. This is in contrast to `QueryJobId` which is just a number.
514+
#[allow(non_camel_case_types)]
515+
#[derive(Clone, Debug)]
516+
pub enum TaggedQueryKey<'tcx> {
517+
$(
518+
$name($name::Key<'tcx>),
519+
)*
520+
}
521+
522+
impl<'tcx> TaggedQueryKey<'tcx> {
523+
/// Formats a human-readable description of this query and its key, as
524+
/// specified by the `desc` query modifier.
525+
///
526+
/// Used when reporting query cycle errors and similar problems.
527+
pub fn description(&self, tcx: TyCtxt<'tcx>) -> String {
528+
let (name, description) = ty::print::with_no_queries!(match self {
529+
$(
530+
TaggedQueryKey::$name(key) => (stringify!($name), _description_fns::$name(tcx, *key)),
531+
)*
532+
});
533+
if tcx.sess.verbose_internals() {
534+
format!("{description} [{name:?}]")
535+
} else {
536+
description
537+
}
538+
}
539+
540+
/// Returns the default span for this query if `span` is a dummy span.
541+
pub fn default_span(&self, tcx: TyCtxt<'tcx>, span: Span) -> Span {
542+
if !span.is_dummy() {
543+
return span
544+
}
545+
if let TaggedQueryKey::def_span(..) = self {
546+
// The `def_span` query is used to calculate `default_span`,
547+
// so exit to avoid infinite recursion.
548+
return DUMMY_SP
549+
}
550+
match self {
551+
$(
552+
TaggedQueryKey::$name(key) => crate::query::QueryKey::default_span(key, tcx),
553+
)*
554+
}
555+
}
556+
557+
pub fn def_kind(&self, tcx: TyCtxt<'tcx>) -> Option<DefKind> {
558+
// This is used to reduce code generation as it
559+
// can be reused for queries with the same key type.
560+
fn inner<'tcx>(key: &impl crate::query::QueryKey, tcx: TyCtxt<'tcx>) -> Option<DefKind> {
561+
key.key_as_def_id().and_then(|def_id| def_id.as_local()).map(|def_id| tcx.def_kind(def_id))
562+
}
563+
564+
if let TaggedQueryKey::def_kind(..) = self {
565+
// Try to avoid infinite recursion.
566+
return None
567+
}
568+
match self {
569+
$(
570+
TaggedQueryKey::$name(key) => inner(key, tcx),
571+
)*
572+
}
573+
}
574+
}
575+
526576
/// Holds a `QueryVTable` for each query.
527577
pub struct QueryVTables<'tcx> {
528578
$(
Lines changed: 3 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,106 +1,18 @@
11
use std::fmt::Debug;
2-
use std::marker::PhantomData;
3-
use std::mem::transmute;
4-
use std::sync::Arc;
52

6-
use rustc_data_structures::sync::{DynSend, DynSync};
7-
use rustc_hir::def::DefKind;
8-
use rustc_span::Span;
93
use rustc_span::def_id::DefId;
104

115
use crate::dep_graph::DepKind;
6+
use crate::queries::TaggedQueryKey;
127

138
/// Description of a frame in the query stack.
149
///
1510
/// This is mostly used in case of cycles for error reporting.
1611
#[derive(Clone, Debug)]
17-
pub struct QueryStackFrame<I> {
18-
/// This field initially stores a `QueryStackDeferred` during collection,
19-
/// but can later be changed to `QueryStackFrameExtra` containing concrete information
20-
/// by calling `lift`. This is done so that collecting query does not need to invoke
21-
/// queries, instead `lift` will call queries in a more appropriate location.
22-
pub info: I,
23-
12+
pub struct QueryStackFrame<'tcx> {
13+
pub tagged_key: TaggedQueryKey<'tcx>,
2414
pub dep_kind: DepKind,
2515
pub def_id: Option<DefId>,
2616
/// A def-id that is extracted from a `Ty` in a query key
2717
pub def_id_for_ty_in_cycle: Option<DefId>,
2818
}
29-
30-
impl<'tcx> QueryStackFrame<QueryStackDeferred<'tcx>> {
31-
#[inline]
32-
pub fn new(
33-
info: QueryStackDeferred<'tcx>,
34-
dep_kind: DepKind,
35-
def_id: Option<DefId>,
36-
def_id_for_ty_in_cycle: Option<DefId>,
37-
) -> Self {
38-
Self { info, def_id, dep_kind, def_id_for_ty_in_cycle }
39-
}
40-
41-
pub fn lift(&self) -> QueryStackFrame<QueryStackFrameExtra> {
42-
QueryStackFrame {
43-
info: self.info.extract(),
44-
dep_kind: self.dep_kind,
45-
def_id: self.def_id,
46-
def_id_for_ty_in_cycle: self.def_id_for_ty_in_cycle,
47-
}
48-
}
49-
}
50-
51-
#[derive(Clone, Debug)]
52-
pub struct QueryStackFrameExtra {
53-
pub description: String,
54-
pub span: Option<Span>,
55-
pub def_kind: Option<DefKind>,
56-
}
57-
58-
impl QueryStackFrameExtra {
59-
#[inline]
60-
pub fn new(description: String, span: Option<Span>, def_kind: Option<DefKind>) -> Self {
61-
Self { description, span, def_kind }
62-
}
63-
64-
// FIXME(eddyb) Get more valid `Span`s on queries.
65-
#[inline]
66-
pub fn default_span(&self, span: Span) -> Span {
67-
if !span.is_dummy() {
68-
return span;
69-
}
70-
self.span.unwrap_or(span)
71-
}
72-
}
73-
74-
/// Track a 'side effect' for a particular query.
75-
/// This is used to hold a closure which can create `QueryStackFrameExtra`.
76-
#[derive(Clone)]
77-
pub struct QueryStackDeferred<'tcx> {
78-
_dummy: PhantomData<&'tcx ()>,
79-
80-
// `extract` may contain references to 'tcx, but we can't tell drop checking that it won't
81-
// access it in the destructor.
82-
extract: Arc<dyn Fn() -> QueryStackFrameExtra + DynSync + DynSend>,
83-
}
84-
85-
impl<'tcx> QueryStackDeferred<'tcx> {
86-
pub fn new<C: Copy + DynSync + DynSend + 'tcx>(
87-
context: C,
88-
extract: fn(C) -> QueryStackFrameExtra,
89-
) -> Self {
90-
let extract: Arc<dyn Fn() -> QueryStackFrameExtra + DynSync + DynSend + 'tcx> =
91-
Arc::new(move || extract(context));
92-
// SAFETY: The `extract` closure does not access 'tcx in its destructor as the only
93-
// captured variable is `context` which is Copy and cannot have a destructor.
94-
Self { _dummy: PhantomData, extract: unsafe { transmute(extract) } }
95-
}
96-
97-
pub fn extract(&self) -> QueryStackFrameExtra {
98-
(self.extract)()
99-
}
100-
}
101-
102-
impl<'tcx> Debug for QueryStackDeferred<'tcx> {
103-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104-
f.write_str("QueryStackDeferred")
105-
}
106-
}

compiler/rustc_query_impl/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ rustc_index = { path = "../rustc_index" }
1414
rustc_macros = { path = "../rustc_macros" }
1515
rustc_middle = { path = "../rustc_middle" }
1616
rustc_serialize = { path = "../rustc_serialize" }
17-
rustc_session = { path = "../rustc_session" }
1817
rustc_span = { path = "../rustc_span" }
1918
rustc_thread_pool = { path = "../rustc_thread_pool" }
2019
tracing = "0.1"

compiler/rustc_query_impl/src/execution.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ pub fn collect_active_jobs_from_all_queries<'tcx>(
4848
let mut complete = true;
4949

5050
for_each_query_vtable!(ALL, tcx, |query| {
51-
let res = gather_active_jobs(query, tcx, require_complete, &mut job_map_out);
51+
let res = gather_active_jobs(query, require_complete, &mut job_map_out);
5252
if res.is_none() {
5353
complete = false;
5454
}
@@ -66,7 +66,6 @@ pub fn collect_active_jobs_from_all_queries<'tcx>(
6666
/// grep for.)
6767
fn gather_active_jobs<'tcx, C>(
6868
query: &'tcx QueryVTable<'tcx, C>,
69-
tcx: TyCtxt<'tcx>,
7069
require_complete: bool,
7170
job_map_out: &mut QueryJobMap<'tcx>, // Out-param; job info is gathered into this map
7271
) -> Option<()>
@@ -113,7 +112,7 @@ where
113112
// Call `make_frame` while we're not holding a `state.active` lock as `make_frame` may call
114113
// queries leading to a deadlock.
115114
for (key, job) in active {
116-
let frame = crate::plumbing::create_deferred_query_stack_frame(tcx, query, key);
115+
let frame = crate::plumbing::create_query_stack_frame(query, key);
117116
job_map_out.insert(job.id, QueryJobInfo { frame, job });
118117
}
119118

@@ -126,9 +125,9 @@ fn mk_cycle<'tcx, C: QueryCache>(
126125
query: &'tcx QueryVTable<'tcx, C>,
127126
tcx: TyCtxt<'tcx>,
128127
key: C::Key,
129-
cycle_error: CycleError,
128+
cycle_error: CycleError<'tcx>,
130129
) -> C::Value {
131-
let error = report_cycle(tcx.sess, &cycle_error);
130+
let error = report_cycle(tcx, &cycle_error);
132131
match query.cycle_error_handling {
133132
CycleErrorHandling::Error => {
134133
let guar = error.emit();
@@ -231,7 +230,7 @@ fn cycle_error<'tcx, C: QueryCache>(
231230
.expect("failed to collect active queries");
232231

233232
let error = find_cycle_in_stack(try_execute, job_map, &current_query_job(), span);
234-
(mk_cycle(query, tcx, key, error.lift()), None)
233+
(mk_cycle(query, tcx, key, error), None)
235234
}
236235

237236
#[inline(always)]
@@ -275,7 +274,7 @@ fn wait_for_query<'tcx, C: QueryCache>(
275274

276275
(v, Some(index))
277276
}
278-
Err(cycle) => (mk_cycle(query, tcx, key, cycle.lift()), None),
277+
Err(cycle) => (mk_cycle(query, tcx, key, cycle), None),
279278
}
280279
}
281280

0 commit comments

Comments
 (0)