1use std::num::NonZero;
6
7use rustc_data_structures::sync::{DynSend, DynSync};
8use rustc_data_structures::unord::UnordMap;
9use rustc_hir::def_id::DefId;
10use rustc_hir::limit::Limit;
11use rustc_index::Idx;
12use rustc_middle::bug;
13#[expect(unused_imports, reason = "used by doc comments")]
14use rustc_middle::dep_graph::DepKindVTable;
15use rustc_middle::dep_graph::{DepKind, DepNode, DepNodeIndex, DepNodeKey, SerializedDepNodeIndex};
16use rustc_middle::query::erase::{Erasable, Erased};
17use rustc_middle::query::on_disk_cache::{
18 AbsoluteBytePos, CacheDecoder, CacheEncoder, EncodedDepNodeIndex,
19};
20use rustc_middle::query::plumbing::QueryVTable;
21use rustc_middle::query::{
22 QueryCache, QueryJobId, QueryKey, QueryStackDeferred, QueryStackFrame, QueryStackFrameExtra,
23 erase,
24};
25use rustc_middle::ty::codec::TyEncoder;
26use rustc_middle::ty::print::with_reduced_queries;
27use rustc_middle::ty::tls::{self, ImplicitCtxt};
28use rustc_middle::ty::{self, TyCtxt};
29use rustc_serialize::{Decodable, Encodable};
30use rustc_span::def_id::LOCAL_CRATE;
31
32use crate::error::{QueryOverflow, QueryOverflowNote};
33use crate::execution::{all_inactive, force_query};
34use crate::job::find_dep_kind_root;
35use crate::{GetQueryVTable, collect_active_jobs_from_all_queries};
36
37fn depth_limit_error<'tcx>(tcx: TyCtxt<'tcx>, job: QueryJobId) {
38 let job_map =
39 collect_active_jobs_from_all_queries(tcx, true).expect("failed to collect active queries");
40 let (info, depth) = find_dep_kind_root(job, job_map);
41
42 let suggested_limit = match tcx.recursion_limit() {
43 Limit(0) => Limit(2),
44 limit => limit * 2,
45 };
46
47 tcx.sess.dcx().emit_fatal(QueryOverflow {
48 span: info.job.span,
49 note: QueryOverflowNote { desc: info.frame.info.extract().description, depth },
50 suggested_limit,
51 crate_name: tcx.crate_name(LOCAL_CRATE),
52 });
53}
54
55#[inline]
56pub(crate) fn next_job_id<'tcx>(tcx: TyCtxt<'tcx>) -> QueryJobId {
57 QueryJobId(
58 NonZero::new(tcx.query_system.jobs.fetch_add(1, std::sync::atomic::Ordering::Relaxed))
59 .unwrap(),
60 )
61}
62
63#[inline]
64pub(crate) fn current_query_job<'tcx>(tcx: TyCtxt<'tcx>) -> Option<QueryJobId> {
65 tls::with_related_context(tcx, |icx| icx.query)
66}
67
68#[inline(always)]
71pub(crate) fn start_query<'tcx, R>(
72 tcx: TyCtxt<'tcx>,
73 token: QueryJobId,
74 depth_limit: bool,
75 compute: impl FnOnce() -> R,
76) -> R {
77 tls::with_related_context(tcx, move |current_icx| {
81 if depth_limit && !tcx.recursion_limit().value_within_limit(current_icx.query_depth) {
82 depth_limit_error(tcx, token);
83 }
84
85 let new_icx = ImplicitCtxt {
87 tcx,
88 query: Some(token),
89 query_depth: current_icx.query_depth + depth_limit as usize,
90 task_deps: current_icx.task_deps,
91 };
92
93 tls::enter_context(&new_icx, compute)
95 })
96}
97
98pub(super) fn try_mark_green<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> bool {
99 tcx.dep_graph.try_mark_green(tcx, dep_node).is_some()
100}
101
102fn mk_query_stack_frame_extra<'tcx, Cache>(
104 (tcx, vtable, key): (TyCtxt<'tcx>, &'tcx QueryVTable<'tcx, Cache>, Cache::Key),
105) -> QueryStackFrameExtra
106where
107 Cache: QueryCache,
108 Cache::Key: QueryKey,
109{
110 let def_id = key.key_as_def_id();
111
112 let reduce_queries = with_reduced_queries();
115
116 let description = {
{
let _guard = ReducedQueriesGuard::new();
{
let _guard = ForcedImplGuard::new();
{
let _guard = NoTrimmedGuard::new();
{
let _guard = NoVisibleGuard::new();
(vtable.description_fn)(tcx, key)
}
}
}
}
}ty::print::with_no_queries!((vtable.description_fn)(tcx, key));
118 let description = if tcx.sess.verbose_internals() {
119 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{1} [{0:?}]", vtable.name,
description))
})format!("{description} [{name:?}]", name = vtable.name)
120 } else {
121 description
122 };
123 let span = if vtable.dep_kind == DepKind::def_span || reduce_queries {
124 None
127 } else {
128 Some(key.default_span(tcx))
129 };
130
131 let def_kind = if vtable.dep_kind == DepKind::def_kind || reduce_queries {
132 None
134 } else {
135 def_id.and_then(|def_id| def_id.as_local()).map(|def_id| tcx.def_kind(def_id))
136 };
137 QueryStackFrameExtra::new(description, span, def_kind)
138}
139
140pub(crate) fn create_deferred_query_stack_frame<'tcx, C>(
141 tcx: TyCtxt<'tcx>,
142 vtable: &'tcx QueryVTable<'tcx, C>,
143 key: C::Key,
144) -> QueryStackFrame<QueryStackDeferred<'tcx>>
145where
146 C: QueryCache<Key: QueryKey + DynSend + DynSync>,
147 QueryVTable<'tcx, C>: DynSync,
148{
149 let kind = vtable.dep_kind;
150
151 let def_id: Option<DefId> = key.key_as_def_id();
152 let def_id_for_ty_in_cycle: Option<DefId> = key.def_id_for_ty_in_cycle();
153
154 let info = QueryStackDeferred::new((tcx, vtable, key), mk_query_stack_frame_extra);
155 QueryStackFrame::new(info, kind, def_id, def_id_for_ty_in_cycle)
156}
157
158pub(crate) fn encode_query_results<'a, 'tcx, C, V>(
159 tcx: TyCtxt<'tcx>,
160 query: &'tcx QueryVTable<'tcx, C>,
161 encoder: &mut CacheEncoder<'a, 'tcx>,
162 query_result_index: &mut EncodedDepNodeIndex,
163) where
164 C: QueryCache<Value = Erased<V>>,
165 V: Erasable + Encodable<CacheEncoder<'a, 'tcx>>,
166{
167 let _timer = tcx.prof.generic_activity_with_arg("encode_query_results_for", query.name);
168
169 if !all_inactive(&query.state) {
::core::panicking::panic("assertion failed: all_inactive(&query.state)")
};assert!(all_inactive(&query.state));
170 query.cache.iter(&mut |key, value, dep_node| {
171 if query.will_cache_on_disk_for_key(tcx, key) {
172 let dep_node = SerializedDepNodeIndex::new(dep_node.index());
173
174 query_result_index.push((dep_node, AbsoluteBytePos::new(encoder.position())));
176
177 encoder.encode_tagged(dep_node, &erase::restore_val::<V>(*value));
180 }
181 });
182}
183
184pub(crate) fn query_key_hash_verify<'tcx, C: QueryCache>(
185 query: &'tcx QueryVTable<'tcx, C>,
186 tcx: TyCtxt<'tcx>,
187) {
188 let _timer = tcx.prof.generic_activity_with_arg("query_key_hash_verify_for", query.name);
189
190 let cache = &query.cache;
191 let mut map = UnordMap::with_capacity(cache.len());
192 cache.iter(&mut |key, _, _| {
193 let node = DepNode::construct(tcx, query.dep_kind, key);
194 if let Some(other_key) = map.insert(node, *key) {
195 ::rustc_middle::util::bug::bug_fmt(format_args!("query key:\n`{0:?}`\nand key:\n`{1:?}`\nmapped to the same dep node:\n{2:?}",
key, other_key, node));bug!(
196 "query key:\n\
197 `{:?}`\n\
198 and key:\n\
199 `{:?}`\n\
200 mapped to the same dep node:\n\
201 {:?}",
202 key,
203 other_key,
204 node
205 );
206 }
207 });
208}
209
210pub(crate) fn promote_from_disk_inner<'tcx, Q: GetQueryVTable<'tcx>>(
212 tcx: TyCtxt<'tcx>,
213 dep_node: DepNode,
214) {
215 let query = Q::query_vtable(tcx);
216 if true {
if !tcx.dep_graph.is_green(&dep_node) {
::core::panicking::panic("assertion failed: tcx.dep_graph.is_green(&dep_node)")
};
};debug_assert!(tcx.dep_graph.is_green(&dep_node));
217
218 let key = <Q::Cache as QueryCache>::Key::try_recover_key(tcx, &dep_node).unwrap_or_else(|| {
219 {
::core::panicking::panic_fmt(format_args!("Failed to recover key for {1:?} with key fingerprint {0}",
dep_node.key_fingerprint, dep_node));
}panic!(
220 "Failed to recover key for {dep_node:?} with key fingerprint {}",
221 dep_node.key_fingerprint
222 )
223 });
224 if query.will_cache_on_disk_for_key(tcx, &key) {
225 (query.call_query_method_fn)(tcx, key);
228 }
229}
230
231pub(crate) fn loadable_from_disk<'tcx>(tcx: TyCtxt<'tcx>, id: SerializedDepNodeIndex) -> bool {
232 if let Some(cache) = tcx.query_system.on_disk_cache.as_ref() {
233 cache.loadable_from_disk(id)
234 } else {
235 false
236 }
237}
238
239pub(crate) fn try_load_from_disk<'tcx, V>(
240 tcx: TyCtxt<'tcx>,
241 prev_index: SerializedDepNodeIndex,
242 index: DepNodeIndex,
243) -> Option<V>
244where
245 V: for<'a> Decodable<CacheDecoder<'a, 'tcx>>,
246{
247 let on_disk_cache = tcx.query_system.on_disk_cache.as_ref()?;
248
249 let prof_timer = tcx.prof.incr_cache_loading();
250
251 let value = tcx
255 .dep_graph
256 .with_query_deserialization(|| on_disk_cache.try_load_query_result(tcx, prev_index));
257
258 prof_timer.finish_with_query_invocation_id(index.into());
259
260 value
261}
262
263pub(crate) fn force_from_dep_node_inner<'tcx, Q: GetQueryVTable<'tcx>>(
265 tcx: TyCtxt<'tcx>,
266 dep_node: DepNode,
267 _prev_index: SerializedDepNodeIndex,
269) -> bool {
270 let query = Q::query_vtable(tcx);
271
272 if true {
if !(dep_node.kind != DepKind::codegen_unit) {
{
::core::panicking::panic_fmt(format_args!("calling force_from_dep_node() on dep_kinds::codegen_unit"));
}
};
};debug_assert!(
286 dep_node.kind != DepKind::codegen_unit,
287 "calling force_from_dep_node() on dep_kinds::codegen_unit"
288 );
289
290 if let Some(key) = <Q::Cache as QueryCache>::Key::try_recover_key(tcx, &dep_node) {
291 force_query(query, tcx, key, dep_node);
292 true
293 } else {
294 false
295 }
296}
297
298macro_rules! define_queries {
299 (
300 queries {
303 $(
304 $(#[$attr:meta])*
305 fn $name:ident($K:ty) -> $V:ty
306 {
307 anon: $anon:literal,
309 arena_cache: $arena_cache:literal,
310 cache_on_disk: $cache_on_disk:literal,
311 cycle_error_handling: $cycle_error_handling:ident,
312 depth_limit: $depth_limit:literal,
313 eval_always: $eval_always:literal,
314 feedable: $feedable:literal,
315 no_hash: $no_hash:literal,
316 return_result_from_ensure_ok: $return_result_from_ensure_ok:literal,
317 separate_provide_extern: $separate_provide_extern:literal,
318 }
319 )*
320 }
321 non_queries { $($_:tt)* }
323 ) => {
324 pub(crate) mod query_impl { $(pub(crate) mod $name {
325 use super::super::*;
326 use ::rustc_middle::query::erase::{self, Erased};
327
328 pub(crate) mod execute_query_incr {
334 use super::*;
335
336 #[inline(never)]
339 pub(crate) fn __rust_end_short_backtrace<'tcx>(
340 tcx: TyCtxt<'tcx>,
341 span: Span,
342 key: queries::$name::Key<'tcx>,
343 mode: QueryMode,
344 ) -> Option<Erased<queries::$name::Value<'tcx>>> {
345 #[cfg(debug_assertions)]
346 let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered();
347 execution::execute_query_incr_inner(
348 &tcx.query_system.query_vtables.$name,
349 tcx,
350 span,
351 key,
352 mode
353 )
354 }
355 }
356
357 pub(crate) mod execute_query_non_incr {
358 use super::*;
359
360 #[inline(never)]
361 pub(crate) fn __rust_end_short_backtrace<'tcx>(
362 tcx: TyCtxt<'tcx>,
363 span: Span,
364 key: queries::$name::Key<'tcx>,
365 __mode: QueryMode,
366 ) -> Option<Erased<queries::$name::Value<'tcx>>> {
367 Some(execution::execute_query_non_incr_inner(
368 &tcx.query_system.query_vtables.$name,
369 tcx,
370 span,
371 key,
372 ))
373 }
374 }
375
376 mod invoke_provider_fn {
382 use super::*;
383 use ::rustc_middle::queries::$name::{Key, Value, provided_to_erased};
384
385 #[inline(never)]
386 pub(crate) fn __rust_begin_short_backtrace<'tcx>(
387 tcx: TyCtxt<'tcx>,
388 key: Key<'tcx>,
389 ) -> Erased<Value<'tcx>> {
390 #[cfg(debug_assertions)]
391 let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered();
392
393 #[cfg($separate_provide_extern)]
396 let provided_value = if let Some(local_key) = key.as_local_key() {
397 (tcx.query_system.local_providers.$name)(tcx, local_key)
398 } else {
399 (tcx.query_system.extern_providers.$name)(tcx, key)
400 };
401
402 #[cfg(not($separate_provide_extern))]
403 let provided_value = (tcx.query_system.local_providers.$name)(tcx, key);
404
405 rustc_middle::ty::print::with_reduced_queries!({
406 tracing::trace!(?provided_value);
407 });
408
409 provided_to_erased(tcx, provided_value)
412 }
413 }
414
415 pub(crate) fn make_query_vtable<'tcx>(incremental: bool)
416 -> QueryVTable<'tcx, queries::$name::Cache<'tcx>>
417 {
418 QueryVTable {
419 name: stringify!($name),
420 anon: $anon,
421 eval_always: $eval_always,
422 depth_limit: $depth_limit,
423 feedable: $feedable,
424 dep_kind: dep_graph::DepKind::$name,
425 cycle_error_handling:
426 rustc_middle::query::CycleErrorHandling::$cycle_error_handling,
427 state: Default::default(),
428 cache: Default::default(),
429
430 #[cfg($cache_on_disk)]
431 will_cache_on_disk_for_key_fn:
432 Some(rustc_middle::queries::_cache_on_disk_if_fns::$name),
433 #[cfg(not($cache_on_disk))]
434 will_cache_on_disk_for_key_fn: None,
435
436 call_query_method_fn: |tcx, key| {
437 let _ = tcx.$name(key);
440 },
441 invoke_provider_fn: self::invoke_provider_fn::__rust_begin_short_backtrace,
442
443 #[cfg($cache_on_disk)]
444 try_load_from_disk_fn: Some(|tcx, key, prev_index, index| {
445 if !rustc_middle::queries::_cache_on_disk_if_fns::$name(tcx, key) {
447 return None;
448 }
449
450 let value: queries::$name::ProvidedValue<'tcx> =
451 $crate::plumbing::try_load_from_disk(tcx, prev_index, index)?;
452
453 Some(queries::$name::provided_to_erased(tcx, value))
455 }),
456 #[cfg(not($cache_on_disk))]
457 try_load_from_disk_fn: None,
458
459 #[cfg($cache_on_disk)]
460 is_loadable_from_disk_fn: Some(|tcx, key, index| -> bool {
461 rustc_middle::queries::_cache_on_disk_if_fns::$name(tcx, key) &&
462 $crate::plumbing::loadable_from_disk(tcx, index)
463 }),
464 #[cfg(not($cache_on_disk))]
465 is_loadable_from_disk_fn: None,
466
467 value_from_cycle_error: |tcx, cycle, guar| {
468 let result: queries::$name::Value<'tcx> =
469 FromCycleError::from_cycle_error(tcx, cycle, guar);
470 erase::erase_val(result)
471 },
472
473 #[cfg($no_hash)]
474 hash_value_fn: None,
475 #[cfg(not($no_hash))]
476 hash_value_fn: Some(|hcx, erased_value: &erase::Erased<queries::$name::Value<'tcx>>| {
477 let value = erase::restore_val(*erased_value);
478 rustc_middle::dep_graph::hash_result(hcx, &value)
479 }),
480
481 format_value: |value| format!("{:?}", erase::restore_val::<queries::$name::Value<'tcx>>(*value)),
482 description_fn: $crate::queries::_description_fns::$name,
483 execute_query_fn: if incremental {
484 query_impl::$name::execute_query_incr::__rust_end_short_backtrace
485 } else {
486 query_impl::$name::execute_query_non_incr::__rust_end_short_backtrace
487 },
488 }
489 }
490
491 pub(crate) enum VTableGetter {}
493
494 impl<'tcx> GetQueryVTable<'tcx> for VTableGetter {
495 type Cache = rustc_middle::queries::$name::Cache<'tcx>;
496
497 #[inline(always)]
498 fn query_vtable(tcx: TyCtxt<'tcx>) -> &'tcx QueryVTable<'tcx, Self::Cache> {
499 &tcx.query_system.query_vtables.$name
500 }
501 }
502 })*}
503
504 pub fn make_query_vtables<'tcx>(incremental: bool) -> queries::QueryVTables<'tcx> {
505 queries::QueryVTables {
506 $(
507 $name: query_impl::$name::make_query_vtable(incremental),
508 )*
509 }
510 }
511
512 pub fn collect_active_jobs_from_all_queries<'tcx>(
523 tcx: TyCtxt<'tcx>,
524 require_complete: bool,
525 ) -> Result<QueryJobMap<'tcx>, QueryJobMap<'tcx>> {
526 let mut job_map_out = QueryJobMap::default();
527 let mut complete = true;
528
529 $(
530 let res = crate::execution::gather_active_jobs(
531 &tcx.query_system.query_vtables.$name,
532 tcx,
533 require_complete,
534 &mut job_map_out,
535 );
536 if res.is_none() {
537 complete = false;
538 }
539 )*
540
541 if complete { Ok(job_map_out) } else { Err(job_map_out) }
542 }
543
544 pub fn alloc_self_profile_query_strings(tcx: TyCtxt<'_>) {
552 if !tcx.prof.enabled() {
553 return;
554 }
555
556 let _prof_timer = tcx.sess.prof.generic_activity("self_profile_alloc_query_strings");
557
558 let mut string_cache = QueryKeyStringCache::new();
559
560 $(
561 $crate::profiling_support::alloc_self_profile_query_strings_for_query_cache(
562 tcx,
563 stringify!($name),
564 &tcx.query_system.query_vtables.$name.cache,
565 &mut string_cache,
566 );
567 )*
568
569 tcx.sess.prof.store_query_cache_hits();
570 }
571
572 fn encode_all_query_results<'tcx>(
573 tcx: TyCtxt<'tcx>,
574 encoder: &mut CacheEncoder<'_, 'tcx>,
575 query_result_index: &mut EncodedDepNodeIndex,
576 ) {
577 $(
578 #[cfg($cache_on_disk)]
579 {
580 $crate::plumbing::encode_query_results(
581 tcx,
582 &tcx.query_system.query_vtables.$name,
583 encoder,
584 query_result_index,
585 )
586 }
587 )*
588 }
589
590 pub fn query_key_hash_verify_all<'tcx>(tcx: TyCtxt<'tcx>) {
591 if tcx.sess.opts.unstable_opts.incremental_verify_ich || cfg!(debug_assertions) {
592 tcx.sess.time("query_key_hash_verify_all", || {
593 $(
594 $crate::plumbing::query_key_hash_verify(
595 &tcx.query_system.query_vtables.$name,
596 tcx
597 );
598 )*
599 })
600 }
601 }
602 }
603}