Skip to content

Commit e18d7fc

Browse files
committed
Auto merge of #154402 - Zoxc:query-call-tracking, r=<try>
Add tracking of query call locations
2 parents 3ea2fbc + 3ac1303 commit e18d7fc

33 files changed

Lines changed: 453 additions & 279 deletions

compiler/rustc_interface/src/util.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ pub(crate) fn run_in_thread_pool_with_globals<
184184

185185
use rustc_data_structures::defer;
186186
use rustc_middle::ty::tls;
187-
use rustc_query_impl::break_query_cycles;
187+
use rustc_query_impl::break_query_cycle;
188188

189189
let thread_stack_size = init_stack_size(thread_builder_diag);
190190

@@ -260,7 +260,7 @@ internal compiler error: query cycle handler thread panicked, aborting process";
260260
)
261261
},
262262
);
263-
break_query_cycles(job_map, &registry);
263+
break_query_cycle(job_map, &registry);
264264
})
265265
})
266266
});

compiler/rustc_middle/src/queries.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ use rustc_data_structures::sorted_map::SortedMap;
6060
use rustc_data_structures::steal::Steal;
6161
use rustc_data_structures::svh::Svh;
6262
use rustc_data_structures::unord::{UnordMap, UnordSet};
63-
use rustc_errors::ErrorGuaranteed;
63+
use rustc_errors::{ErrorGuaranteed, catch_fatal_errors};
6464
use rustc_hir as hir;
6565
use rustc_hir::attrs::{EiiDecl, EiiImpl, StrippedCfgItem};
6666
use rustc_hir::def::{DefKind, DocLinkResMap};

compiler/rustc_middle/src/query/inner.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
//! Helper functions that serve as the immediate implementation of
22
//! `tcx.$query(..)` and its variations.
33
4+
use std::panic::Location;
5+
46
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
57

68
use crate::dep_graph;
79
use crate::dep_graph::DepNodeKey;
810
use crate::query::erase::{self, Erasable, Erased};
9-
use crate::query::{EnsureMode, QueryCache, QueryMode, QueryVTable};
11+
use crate::query::{EnsureMode, QueryCache, QueryCallContext, QueryMode, QueryVTable};
1012
use crate::ty::TyCtxt;
1113

1214
/// Checks whether there is already a value for this key in the in-memory
@@ -31,6 +33,7 @@ where
3133
/// Shared implementation of `tcx.$query(..)` and `tcx.at(span).$query(..)`
3234
/// for all queries.
3335
#[inline(always)]
36+
#[track_caller]
3437
pub(crate) fn query_get_at<'tcx, C>(
3538
tcx: TyCtxt<'tcx>,
3639
span: Span,
@@ -40,15 +43,17 @@ pub(crate) fn query_get_at<'tcx, C>(
4043
where
4144
C: QueryCache,
4245
{
46+
let call_context = QueryCallContext { span, location: Some(Location::caller()) };
4347
match try_get_cached(tcx, &query.cache, key) {
4448
Some(value) => value,
45-
None => (query.execute_query_fn)(tcx, span, key, QueryMode::Get).unwrap(),
49+
None => (query.execute_query_fn)(tcx, call_context, key, QueryMode::Get).unwrap(),
4650
}
4751
}
4852

4953
/// Shared implementation of `tcx.ensure_ok().$query(..)` and
5054
/// `tcx.ensure_done().$query(..)` for all queries.
5155
#[inline]
56+
#[track_caller]
5257
pub(crate) fn query_ensure_ok_or_done<'tcx, C>(
5358
tcx: TyCtxt<'tcx>,
5459
query: &'tcx QueryVTable<'tcx, C>,
@@ -57,17 +62,19 @@ pub(crate) fn query_ensure_ok_or_done<'tcx, C>(
5762
) where
5863
C: QueryCache,
5964
{
65+
let call_context = QueryCallContext { span: DUMMY_SP, location: Some(Location::caller()) };
6066
match try_get_cached(tcx, &query.cache, key) {
6167
Some(_value) => {}
6268
None => {
63-
(query.execute_query_fn)(tcx, DUMMY_SP, key, QueryMode::Ensure { ensure_mode });
69+
(query.execute_query_fn)(tcx, call_context, key, QueryMode::Ensure { ensure_mode });
6470
}
6571
}
6672
}
6773

6874
/// Implementation of `tcx.ensure_result().$query(..)` for queries that
6975
/// return `Result<_, ErrorGuaranteed>`.
7076
#[inline]
77+
#[track_caller]
7178
pub(crate) fn query_ensure_result<'tcx, C, T>(
7279
tcx: TyCtxt<'tcx>,
7380
query: &'tcx QueryVTable<'tcx, C>,
@@ -77,6 +84,7 @@ where
7784
C: QueryCache<Value = Erased<Result<T, ErrorGuaranteed>>>,
7885
Result<T, ErrorGuaranteed>: Erasable,
7986
{
87+
let call_context = QueryCallContext { span: DUMMY_SP, location: Some(Location::caller()) };
8088
let convert = |value: Erased<Result<T, ErrorGuaranteed>>| -> Result<(), ErrorGuaranteed> {
8189
match erase::restore_val(value) {
8290
Ok(_) => Ok(()),
@@ -89,7 +97,7 @@ where
8997
None => {
9098
match (query.execute_query_fn)(
9199
tcx,
92-
DUMMY_SP,
100+
call_context,
93101
key,
94102
QueryMode::Ensure { ensure_mode: EnsureMode::Ok },
95103
) {

compiler/rustc_middle/src/query/job.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ use std::num::NonZero;
44
use std::sync::Arc;
55

66
use parking_lot::{Condvar, Mutex};
7-
use rustc_span::Span;
87

9-
use crate::query::Cycle;
8+
use crate::query::{Cycle, QueryCallContext};
109
use crate::ty::TyCtxt;
1110

1211
/// A value uniquely identifying an active query job.
@@ -18,8 +17,8 @@ pub struct QueryJobId(pub NonZero<u64>);
1817
pub struct QueryJob<'tcx> {
1918
pub id: QueryJobId,
2019

21-
/// The span corresponding to the reason for which this query was required.
22-
pub span: Span,
20+
/// The span and call site corresponding to why this query was required.
21+
pub call_context: QueryCallContext,
2322

2423
/// The parent query job which created this job and is implicitly waiting on it.
2524
pub parent: Option<QueryJobId>,
@@ -31,8 +30,8 @@ pub struct QueryJob<'tcx> {
3130
impl<'tcx> QueryJob<'tcx> {
3231
/// Creates a new query job.
3332
#[inline]
34-
pub fn new(id: QueryJobId, span: Span, parent: Option<QueryJobId>) -> Self {
35-
QueryJob { id, span, parent, latch: None }
33+
pub fn new(id: QueryJobId, call_context: QueryCallContext, parent: Option<QueryJobId>) -> Self {
34+
QueryJob { id, call_context, parent, latch: None }
3635
}
3736

3837
pub fn latch(&mut self) -> QueryLatch<'tcx> {
@@ -58,7 +57,7 @@ impl<'tcx> QueryJob<'tcx> {
5857
pub struct QueryWaiter<'tcx> {
5958
pub parent: Option<QueryJobId>,
6059
pub condvar: Condvar,
61-
pub span: Span,
60+
pub call_context: QueryCallContext,
6261
pub cycle: Mutex<Option<Cycle<'tcx>>>,
6362
}
6463

@@ -78,7 +77,7 @@ impl<'tcx> QueryLatch<'tcx> {
7877
&self,
7978
tcx: TyCtxt<'tcx>,
8079
query: Option<QueryJobId>,
81-
span: Span,
80+
call_context: QueryCallContext,
8281
) -> Result<(), Cycle<'tcx>> {
8382
let mut waiters_guard = self.waiters.lock();
8483
let Some(waiters) = &mut *waiters_guard else {
@@ -87,7 +86,7 @@ impl<'tcx> QueryLatch<'tcx> {
8786

8887
let waiter = Arc::new(QueryWaiter {
8988
parent: query,
90-
span,
89+
call_context,
9190
cycle: Mutex::new(None),
9291
condvar: Condvar::new(),
9392
});

compiler/rustc_middle/src/query/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub use self::plumbing::{
88
ActiveKeyStatus, Cycle, EnsureMode, QueryMode, QueryState, QuerySystem, QueryVTable, TyCtxtAt,
99
TyCtxtEnsureDone, TyCtxtEnsureOk, TyCtxtEnsureResult,
1010
};
11-
pub use self::stack::QueryStackFrame;
11+
pub use self::stack::{QueryCallContext, QueryStackFrame};
1212
pub use crate::queries::Providers;
1313
use crate::ty::TyCtxt;
1414

compiler/rustc_middle/src/query/plumbing.rs

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::dep_graph::{DepKind, DepNodeIndex, QuerySideEffect, SerializedDepNode
1313
use crate::ich::StableHashingContext;
1414
use crate::queries::{ExternProviders, Providers, QueryArenas, QueryVTables, TaggedQueryKey};
1515
use crate::query::on_disk_cache::OnDiskCache;
16-
use crate::query::{QueryCache, QueryJob, QueryStackFrame};
16+
use crate::query::{QueryCache, QueryCallContext, QueryJob, QueryStackFrame};
1717
use crate::ty::TyCtxt;
1818

1919
/// For a particular query, keeps track of "active" keys, i.e. keys whose
@@ -130,7 +130,7 @@ pub struct QueryVTable<'tcx, C: QueryCache> {
130130
/// and putting the obtained value into the in-memory cache.
131131
///
132132
/// [^1]: [`TyCtxt`], [`TyCtxtAt`], [`TyCtxtEnsureOk`], [`TyCtxtEnsureDone`]
133-
pub execute_query_fn: fn(TyCtxt<'tcx>, Span, C::Key, QueryMode) -> Option<C::Value>,
133+
pub execute_query_fn: fn(TyCtxt<'tcx>, QueryCallContext, C::Key, QueryMode) -> Option<C::Value>,
134134
}
135135

136136
impl<'tcx, C: QueryCache> fmt::Debug for QueryVTable<'tcx, C> {
@@ -166,6 +166,8 @@ pub struct QuerySystem<'tcx> {
166166
pub extern_providers: ExternProviders,
167167

168168
pub jobs: AtomicU64,
169+
170+
pub cycle_handler_nesting: Lock<u8>,
169171
}
170172

171173
#[derive(Copy, Clone)]
@@ -204,6 +206,7 @@ impl<'tcx> TyCtxt<'tcx> {
204206
/// Returns a transparent wrapper for `TyCtxt` which uses
205207
/// `span` as the location of queries performed through it.
206208
#[inline(always)]
209+
#[track_caller]
207210
pub fn at(self, span: Span) -> TyCtxtAt<'tcx> {
208211
TyCtxtAt { tcx: self, span }
209212
}
@@ -231,6 +234,7 @@ impl<'tcx> TyCtxt<'tcx> {
231234
/// Therefore, this call mode is not appropriate for callers that want to
232235
/// ensure that the query is _never_ executed in the future.
233236
#[inline(always)]
237+
#[track_caller]
234238
pub fn ensure_ok(self) -> TyCtxtEnsureOk<'tcx> {
235239
TyCtxtEnsureOk { tcx: self }
236240
}
@@ -241,6 +245,7 @@ impl<'tcx> TyCtxt<'tcx> {
241245
/// but nothing else. As with `ensure_ok`, this can be more efficient than
242246
/// a normal query call.
243247
#[inline(always)]
248+
#[track_caller]
244249
pub fn ensure_result(self) -> TyCtxtEnsureResult<'tcx> {
245250
TyCtxtEnsureResult { tcx: self }
246251
}
@@ -262,6 +267,7 @@ impl<'tcx> TyCtxt<'tcx> {
262267
///
263268
/// [`Steal`]: rustc_data_structures::steal::Steal
264269
#[inline(always)]
270+
#[track_caller]
265271
pub fn ensure_done(self) -> TyCtxtEnsureDone<'tcx> {
266272
TyCtxtEnsureDone { tcx: self }
267273
}
@@ -431,6 +437,11 @@ macro_rules! define_callbacks {
431437
}
432438
}
433439

440+
/// Calls `self.description` or returns a fallback if there was a fatal error
441+
pub fn catch_description(&self, tcx: TyCtxt<'tcx>) -> String {
442+
catch_fatal_errors(|| self.description(tcx)).unwrap_or_else(|_| format!("<error describing {}>", self.query_name()))
443+
}
444+
434445
/// Returns the default span for this query if `span` is a dummy span.
435446
pub fn default_span(&self, tcx: TyCtxt<'tcx>, span: Span) -> Span {
436447
if !span.is_dummy() {
@@ -449,28 +460,9 @@ macro_rules! define_callbacks {
449460
}
450461
}
451462

452-
pub fn def_kind(&self, tcx: TyCtxt<'tcx>) -> Option<DefKind> {
453-
// This is used to reduce code generation as it
454-
// can be reused for queries with the same key type.
455-
fn inner<'tcx>(key: &impl $crate::query::QueryKey, tcx: TyCtxt<'tcx>)
456-
-> Option<DefKind>
457-
{
458-
key
459-
.key_as_def_id()
460-
.and_then(|def_id| def_id.as_local())
461-
.map(|def_id| tcx.def_kind(def_id))
462-
}
463-
464-
if let TaggedQueryKey::def_kind(..) = self {
465-
// Try to avoid infinite recursion.
466-
return None
467-
}
468-
469-
match self {
470-
$(
471-
TaggedQueryKey::$name(key) => inner(key, tcx),
472-
)*
473-
}
463+
/// Calls `self.default_span` or returns `DUMMY_SP` if there was a fatal error
464+
pub fn catch_default_span(&self, tcx: TyCtxt<'tcx>, span: Span) -> Span {
465+
catch_fatal_errors(|| self.default_span(tcx, span)).unwrap_or(DUMMY_SP)
474466
}
475467
}
476468

@@ -554,6 +546,7 @@ macro_rules! define_callbacks {
554546
$(
555547
$(#[$attr])*
556548
#[inline(always)]
549+
#[track_caller]
557550
#[must_use]
558551
pub fn $name(self, key: maybe_into_query_key!($($K)*)) -> $V {
559552
self.at(DUMMY_SP).$name(key)
@@ -565,6 +558,7 @@ macro_rules! define_callbacks {
565558
$(
566559
$(#[$attr])*
567560
#[inline(always)]
561+
#[track_caller]
568562
pub fn $name(self, key: maybe_into_query_key!($($K)*)) -> $V {
569563
use $crate::query::{erase, inner};
570564

@@ -582,6 +576,7 @@ macro_rules! define_callbacks {
582576
$(
583577
$(#[$attr])*
584578
#[inline(always)]
579+
#[track_caller]
585580
pub fn $name(self, key: maybe_into_query_key!($($K)*)) {
586581
$crate::query::inner::query_ensure_ok_or_done(
587582
self.tcx,
@@ -599,6 +594,7 @@ macro_rules! define_callbacks {
599594
#[cfg($returns_error_guaranteed)]
600595
$(#[$attr])*
601596
#[inline(always)]
597+
#[track_caller]
602598
pub fn $name(
603599
self,
604600
key: maybe_into_query_key!($($K)*),
@@ -616,6 +612,7 @@ macro_rules! define_callbacks {
616612
$(
617613
$(#[$attr])*
618614
#[inline(always)]
615+
#[track_caller]
619616
pub fn $name(self, key: maybe_into_query_key!($($K)*)) {
620617
$crate::query::inner::query_ensure_ok_or_done(
621618
self.tcx,

compiler/rustc_middle/src/query/stack.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
1+
use std::panic::Location;
2+
13
use rustc_span::Span;
24

35
use crate::queries::TaggedQueryKey;
46

7+
#[derive(Clone, Copy, Debug)]
8+
pub struct QueryCallContext {
9+
pub span: Span,
10+
pub location: Option<&'static Location<'static>>,
11+
}
12+
513
/// Description of a frame in the query stack.
614
///
715
/// This is mostly used in case of cycles for error reporting.
816
#[derive(Debug)]
917
pub struct QueryStackFrame<'tcx> {
10-
pub span: Span,
18+
pub call_context: QueryCallContext,
1119

1220
/// The query and key of the query method call that this stack frame
1321
/// corresponds to.

compiler/rustc_query_impl/src/error.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ pub(crate) struct CycleStack {
3030
#[primary_span]
3131
pub span: Span,
3232
pub desc: String,
33+
#[subdiagnostic]
34+
pub location: Option<QueryLocationNote>,
3335
}
3436

3537
#[derive(Subdiagnostic)]
@@ -58,6 +60,14 @@ pub(crate) struct CycleUsage {
5860
#[primary_span]
5961
pub span: Span,
6062
pub usage: String,
63+
#[subdiagnostic]
64+
pub location: Option<QueryLocationNote>,
65+
}
66+
67+
#[derive(Subdiagnostic)]
68+
#[note("at {$location}")]
69+
pub(crate) struct QueryLocationNote {
70+
pub location: String,
6171
}
6272

6373
#[derive(Diagnostic)]
@@ -71,6 +81,8 @@ pub(crate) struct Cycle {
7181
#[subdiagnostic]
7282
pub stack_count: StackCount,
7383
#[subdiagnostic]
84+
pub stack_bottom_location: Option<QueryLocationNote>,
85+
#[subdiagnostic]
7486
pub alias: Option<Alias>,
7587
#[subdiagnostic]
7688
pub cycle_usage: Option<CycleUsage>,
@@ -79,3 +91,23 @@ pub(crate) struct Cycle {
7991
)]
8092
pub note_span: (),
8193
}
94+
95+
#[derive(Diagnostic)]
96+
#[diag("cycle when printing cycle detected when {$stack_bottom}")]
97+
pub(crate) struct NestedCycle {
98+
#[primary_span]
99+
pub span: Span,
100+
pub stack_bottom: String,
101+
#[subdiagnostic]
102+
pub cycle_stack: Vec<CycleStack>,
103+
#[subdiagnostic]
104+
pub stack_count: StackCount,
105+
#[subdiagnostic]
106+
pub stack_bottom_location: Option<QueryLocationNote>,
107+
#[subdiagnostic]
108+
pub cycle_usage: Option<CycleUsage>,
109+
#[note(
110+
"see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information"
111+
)]
112+
pub note_span: (),
113+
}

0 commit comments

Comments
 (0)