Skip to main content

rustc_query_impl/
plumbing.rs

1//! The implementation of the query system itself. This defines the macros that
2//! generate the actual methods on tcx which find and execute the provider,
3//! manage the caches, and so forth.
4
5use 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::{QueryJobMap, find_dep_kind_root};
35
36fn depth_limit_error<'tcx>(tcx: TyCtxt<'tcx>, job: QueryJobId) {
37    let job_map =
38        collect_active_jobs_from_all_queries(tcx, true).expect("failed to collect active queries");
39    let (info, depth) = find_dep_kind_root(job, job_map);
40
41    let suggested_limit = match tcx.recursion_limit() {
42        Limit(0) => Limit(2),
43        limit => limit * 2,
44    };
45
46    tcx.sess.dcx().emit_fatal(QueryOverflow {
47        span: info.job.span,
48        note: QueryOverflowNote { desc: info.frame.info.extract().description, depth },
49        suggested_limit,
50        crate_name: tcx.crate_name(LOCAL_CRATE),
51    });
52}
53
54#[inline]
55pub(crate) fn next_job_id<'tcx>(tcx: TyCtxt<'tcx>) -> QueryJobId {
56    QueryJobId(
57        NonZero::new(tcx.query_system.jobs.fetch_add(1, std::sync::atomic::Ordering::Relaxed))
58            .unwrap(),
59    )
60}
61
62#[inline]
63pub(crate) fn current_query_job<'tcx>(tcx: TyCtxt<'tcx>) -> Option<QueryJobId> {
64    tls::with_related_context(tcx, |icx| icx.query)
65}
66
67/// Executes a job by changing the `ImplicitCtxt` to point to the
68/// new query job while it executes.
69#[inline(always)]
70pub(crate) fn start_query<'tcx, R>(
71    tcx: TyCtxt<'tcx>,
72    token: QueryJobId,
73    depth_limit: bool,
74    compute: impl FnOnce() -> R,
75) -> R {
76    // The `TyCtxt` stored in TLS has the same global interner lifetime
77    // as `self`, so we use `with_related_context` to relate the 'tcx lifetimes
78    // when accessing the `ImplicitCtxt`.
79    tls::with_related_context(tcx, move |current_icx| {
80        if depth_limit && !tcx.recursion_limit().value_within_limit(current_icx.query_depth) {
81            depth_limit_error(tcx, token);
82        }
83
84        // Update the `ImplicitCtxt` to point to our new query job.
85        let new_icx = ImplicitCtxt {
86            tcx,
87            query: Some(token),
88            query_depth: current_icx.query_depth + depth_limit as usize,
89            task_deps: current_icx.task_deps,
90        };
91
92        // Use the `ImplicitCtxt` while we execute the query.
93        tls::enter_context(&new_icx, compute)
94    })
95}
96
97/// Returns a map of currently active query jobs, collected from all queries.
98///
99/// If `require_complete` is `true`, this function locks all shards of the
100/// query results to produce a complete map, which always returns `Ok`.
101/// Otherwise, it may return an incomplete map as an error if any shard
102/// lock cannot be acquired.
103///
104/// Prefer passing `false` to `require_complete` to avoid potential deadlocks,
105/// especially when called from within a deadlock handler, unless a
106/// complete map is needed and no deadlock is possible at this call site.
107pub fn collect_active_jobs_from_all_queries<'tcx>(
108    tcx: TyCtxt<'tcx>,
109    require_complete: bool,
110) -> Result<QueryJobMap<'tcx>, QueryJobMap<'tcx>> {
111    let mut job_map_out = QueryJobMap::default();
112    let mut complete = true;
113
114    for gather_fn in crate::PER_QUERY_GATHER_ACTIVE_JOBS_FNS.iter() {
115        if gather_fn(tcx, require_complete, &mut job_map_out).is_none() {
116            complete = false;
117        }
118    }
119
120    if complete { Ok(job_map_out) } else { Err(job_map_out) }
121}
122
123pub(super) fn try_mark_green<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> bool {
124    tcx.dep_graph.try_mark_green(tcx, dep_node).is_some()
125}
126
127pub(super) fn encode_all_query_results<'tcx>(
128    tcx: TyCtxt<'tcx>,
129    encoder: &mut CacheEncoder<'_, 'tcx>,
130    query_result_index: &mut EncodedDepNodeIndex,
131) {
132    for encode in super::ENCODE_QUERY_RESULTS.iter().copied().flatten() {
133        encode(tcx, encoder, query_result_index);
134    }
135}
136
137pub fn query_key_hash_verify_all<'tcx>(tcx: TyCtxt<'tcx>) {
138    if tcx.sess.opts.unstable_opts.incremental_verify_ich || truecfg!(debug_assertions) {
139        tcx.sess.time("query_key_hash_verify_all", || {
140            for verify in super::QUERY_KEY_HASH_VERIFY.iter() {
141                verify(tcx);
142            }
143        })
144    }
145}
146
147macro_rules! cycle_error_handling {
148    ([]) => {{
149        rustc_middle::query::CycleErrorHandling::Error
150    }};
151    ([(cycle_fatal) $($rest:tt)*]) => {{
152        rustc_middle::query::CycleErrorHandling::Fatal
153    }};
154    ([(cycle_stash) $($rest:tt)*]) => {{
155        rustc_middle::query::CycleErrorHandling::Stash
156    }};
157    ([(cycle_delay_bug) $($rest:tt)*]) => {{
158        rustc_middle::query::CycleErrorHandling::DelayBug
159    }};
160    ([$other:tt $($modifiers:tt)*]) => {
161        cycle_error_handling!([$($modifiers)*])
162    };
163}
164
165macro_rules! is_anon {
166    ([]) => {{
167        false
168    }};
169    ([(anon) $($rest:tt)*]) => {{
170        true
171    }};
172    ([$other:tt $($modifiers:tt)*]) => {
173        is_anon!([$($modifiers)*])
174    };
175}
176
177macro_rules! is_eval_always {
178    ([]) => {{
179        false
180    }};
181    ([(eval_always) $($rest:tt)*]) => {{
182        true
183    }};
184    ([$other:tt $($modifiers:tt)*]) => {
185        is_eval_always!([$($modifiers)*])
186    };
187}
188
189macro_rules! is_depth_limit {
190    ([]) => {{
191        false
192    }};
193    ([(depth_limit) $($rest:tt)*]) => {{
194        true
195    }};
196    ([$other:tt $($modifiers:tt)*]) => {
197        is_depth_limit!([$($modifiers)*])
198    };
199}
200
201macro_rules! is_feedable {
202    ([]) => {{
203        false
204    }};
205    ([(feedable) $($rest:tt)*]) => {{
206        true
207    }};
208    ([$other:tt $($modifiers:tt)*]) => {
209        is_feedable!([$($modifiers)*])
210    };
211}
212
213macro_rules! hash_result {
214    ([][$V:ty]) => {{
215        Some(|hcx, result| {
216            let result = rustc_middle::query::erase::restore_val::<$V>(*result);
217            rustc_middle::dep_graph::hash_result(hcx, &result)
218        })
219    }};
220    ([(no_hash) $($rest:tt)*][$V:ty]) => {{
221        None
222    }};
223    ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
224        hash_result!([$($modifiers)*][$($args)*])
225    };
226}
227
228macro_rules! call_provider {
229    ([][$tcx:expr, $name:ident, $key:expr]) => {{
230        ($tcx.query_system.local_providers.$name)($tcx, $key)
231    }};
232    ([(separate_provide_extern) $($rest:tt)*][$tcx:expr, $name:ident, $key:expr]) => {{
233        if let Some(key) = $key.as_local_key() {
234            ($tcx.query_system.local_providers.$name)($tcx, key)
235        } else {
236            ($tcx.query_system.extern_providers.$name)($tcx, $key)
237        }
238    }};
239    ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
240        call_provider!([$($modifiers)*][$($args)*])
241    };
242}
243
244/// Expands to one of two token trees, depending on whether the current query
245/// has the `cache_on_disk_if` modifier.
246macro_rules! if_cache_on_disk {
247    ([] $yes:tt $no:tt) => {
248        $no
249    };
250    // The `cache_on_disk_if` modifier generates a synthetic `(cache_on_disk)`,
251    // modifier, for use by this macro and similar macros.
252    ([(cache_on_disk) $($rest:tt)*] $yes:tt $no:tt) => {
253        $yes
254    };
255    ([$other:tt $($modifiers:tt)*] $yes:tt $no:tt) => {
256        if_cache_on_disk!([$($modifiers)*] $yes $no)
257    };
258}
259
260/// Conditionally expands to some token trees, if the current query has the
261/// `cache_on_disk_if` modifier.
262macro_rules! item_if_cache_on_disk {
263    ([] $($item:tt)*) => {};
264    ([(cache_on_disk) $($rest:tt)*] $($item:tt)*) => {
265        $($item)*
266    };
267    ([$other:tt $($modifiers:tt)*] $($item:tt)*) => {
268        item_if_cache_on_disk! { [$($modifiers)*] $($item)* }
269    };
270}
271
272/// The deferred part of a deferred query stack frame.
273fn mk_query_stack_frame_extra<'tcx, Cache>(
274    (tcx, vtable, key): (TyCtxt<'tcx>, &'tcx QueryVTable<'tcx, Cache>, Cache::Key),
275) -> QueryStackFrameExtra
276where
277    Cache: QueryCache,
278    Cache::Key: QueryKey,
279{
280    let def_id = key.key_as_def_id();
281
282    // If reduced queries are requested, we may be printing a query stack due
283    // to a panic. Avoid using `default_span` and `def_kind` in that case.
284    let reduce_queries = with_reduced_queries();
285
286    // Avoid calling queries while formatting the description
287    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));
288    let description = if tcx.sess.verbose_internals() {
289        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{1} [{0:?}]", vtable.name,
                description))
    })format!("{description} [{name:?}]", name = vtable.name)
290    } else {
291        description
292    };
293    let span = if vtable.dep_kind == DepKind::def_span || reduce_queries {
294        // The `def_span` query is used to calculate `default_span`,
295        // so exit to avoid infinite recursion.
296        None
297    } else {
298        Some(key.default_span(tcx))
299    };
300
301    let def_kind = if vtable.dep_kind == DepKind::def_kind || reduce_queries {
302        // Try to avoid infinite recursion.
303        None
304    } else {
305        def_id.and_then(|def_id| def_id.as_local()).map(|def_id| tcx.def_kind(def_id))
306    };
307    QueryStackFrameExtra::new(description, span, def_kind)
308}
309
310pub(crate) fn create_deferred_query_stack_frame<'tcx, C>(
311    tcx: TyCtxt<'tcx>,
312    vtable: &'tcx QueryVTable<'tcx, C>,
313    key: C::Key,
314) -> QueryStackFrame<QueryStackDeferred<'tcx>>
315where
316    C: QueryCache,
317    C::Key: QueryKey + DynSend + DynSync,
318    QueryVTable<'tcx, C>: DynSync,
319{
320    let kind = vtable.dep_kind;
321
322    let def_id: Option<DefId> = key.key_as_def_id();
323    let def_id_for_ty_in_cycle: Option<DefId> = key.def_id_for_ty_in_cycle();
324
325    let info = QueryStackDeferred::new((tcx, vtable, key), mk_query_stack_frame_extra);
326    QueryStackFrame::new(info, kind, def_id, def_id_for_ty_in_cycle)
327}
328
329pub(crate) fn encode_query_results_inner<'a, 'tcx, C, V>(
330    tcx: TyCtxt<'tcx>,
331    query: &'tcx QueryVTable<'tcx, C>,
332    encoder: &mut CacheEncoder<'a, 'tcx>,
333    query_result_index: &mut EncodedDepNodeIndex,
334) where
335    C: QueryCache<Value = Erased<V>>,
336    V: Erasable + Encodable<CacheEncoder<'a, 'tcx>>,
337{
338    let _timer = tcx.prof.generic_activity_with_arg("encode_query_results_for", query.name);
339
340    if !all_inactive(&query.state) {
    ::core::panicking::panic("assertion failed: all_inactive(&query.state)")
};assert!(all_inactive(&query.state));
341    query.cache.iter(&mut |key, value, dep_node| {
342        if query.will_cache_on_disk_for_key(tcx, key) {
343            let dep_node = SerializedDepNodeIndex::new(dep_node.index());
344
345            // Record position of the cache entry.
346            query_result_index.push((dep_node, AbsoluteBytePos::new(encoder.position())));
347
348            // Encode the type check tables with the `SerializedDepNodeIndex`
349            // as tag.
350            encoder.encode_tagged(dep_node, &erase::restore_val::<V>(*value));
351        }
352    });
353}
354
355pub(crate) fn query_key_hash_verify<'tcx, C: QueryCache>(
356    query: &'tcx QueryVTable<'tcx, C>,
357    tcx: TyCtxt<'tcx>,
358) {
359    let _timer = tcx.prof.generic_activity_with_arg("query_key_hash_verify_for", query.name);
360
361    let cache = &query.cache;
362    let mut map = UnordMap::with_capacity(cache.len());
363    cache.iter(&mut |key, _, _| {
364        let node = DepNode::construct(tcx, query.dep_kind, key);
365        if let Some(other_key) = map.insert(node, *key) {
366            ::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!(
367                "query key:\n\
368                `{:?}`\n\
369                and key:\n\
370                `{:?}`\n\
371                mapped to the same dep node:\n\
372                {:?}",
373                key,
374                other_key,
375                node
376            );
377        }
378    });
379}
380
381/// Implementation of [`DepKindVTable::try_load_from_on_disk_cache`] for queries.
382pub(crate) fn try_load_from_on_disk_cache_inner<'tcx, C: QueryCache>(
383    query: &'tcx QueryVTable<'tcx, C>,
384    tcx: TyCtxt<'tcx>,
385    dep_node: DepNode,
386) {
387    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));
388
389    let key = C::Key::try_recover_key(tcx, &dep_node).unwrap_or_else(|| {
390        {
    ::core::panicking::panic_fmt(format_args!("Failed to recover key for {1:?} with key fingerprint {0}",
            dep_node.key_fingerprint, dep_node));
}panic!(
391            "Failed to recover key for {dep_node:?} with key fingerprint {}",
392            dep_node.key_fingerprint
393        )
394    });
395    if query.will_cache_on_disk_for_key(tcx, &key) {
396        // Call `tcx.$query(key)` for its side-effect of loading the disk-cached
397        // value into memory.
398        (query.call_query_method_fn)(tcx, key);
399    }
400}
401
402pub(crate) fn loadable_from_disk<'tcx>(tcx: TyCtxt<'tcx>, id: SerializedDepNodeIndex) -> bool {
403    if let Some(cache) = tcx.query_system.on_disk_cache.as_ref() {
404        cache.loadable_from_disk(id)
405    } else {
406        false
407    }
408}
409
410pub(crate) fn try_load_from_disk<'tcx, V>(
411    tcx: TyCtxt<'tcx>,
412    prev_index: SerializedDepNodeIndex,
413    index: DepNodeIndex,
414) -> Option<V>
415where
416    V: for<'a> Decodable<CacheDecoder<'a, 'tcx>>,
417{
418    let on_disk_cache = tcx.query_system.on_disk_cache.as_ref()?;
419
420    let prof_timer = tcx.prof.incr_cache_loading();
421
422    // The call to `with_query_deserialization` enforces that no new `DepNodes`
423    // are created during deserialization. See the docs of that method for more
424    // details.
425    let value = tcx
426        .dep_graph
427        .with_query_deserialization(|| on_disk_cache.try_load_query_result(tcx, prev_index));
428
429    prof_timer.finish_with_query_invocation_id(index.into());
430
431    value
432}
433
434/// Implementation of [`DepKindVTable::force_from_dep_node`] for queries.
435pub(crate) fn force_from_dep_node_inner<'tcx, C: QueryCache>(
436    query: &'tcx QueryVTable<'tcx, C>,
437    tcx: TyCtxt<'tcx>,
438    dep_node: DepNode,
439) -> bool {
440    // We must avoid ever having to call `force_from_dep_node()` for a
441    // `DepNode::codegen_unit`:
442    // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we
443    // would always end up having to evaluate the first caller of the
444    // `codegen_unit` query that *is* reconstructible. This might very well be
445    // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just
446    // to re-trigger calling the `codegen_unit` query with the right key. At
447    // that point we would already have re-done all the work we are trying to
448    // avoid doing in the first place.
449    // The solution is simple: Just explicitly call the `codegen_unit` query for
450    // each CGU, right after partitioning. This way `try_mark_green` will always
451    // hit the cache instead of having to go through `force_from_dep_node`.
452    // This assertion makes sure, we actually keep applying the solution above.
453    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!(
454        dep_node.kind != DepKind::codegen_unit,
455        "calling force_from_dep_node() on dep_kinds::codegen_unit"
456    );
457
458    if let Some(key) = C::Key::try_recover_key(tcx, &dep_node) {
459        force_query(query, tcx, key, dep_node);
460        true
461    } else {
462        false
463    }
464}
465
466// Note: `$K` and `$V` are unused but present so this can be called by `rustc_with_all_queries`.
467macro_rules! define_queries {
468    (
469        $(
470            $(#[$attr:meta])*
471            [$($modifiers:tt)*] fn $name:ident($K:ty) -> $V:ty,
472        )*
473    ) => {
474
475        pub(crate) mod query_impl { $(pub(crate) mod $name {
476            use super::super::*;
477            use ::rustc_middle::query::erase::{self, Erased};
478
479            // It seems to be important that every query has its own monomorphic
480            // copy of `execute_query_incr` and `execute_query_non_incr`.
481            // Trying to inline these wrapper functions into their generic
482            // "inner" helpers tends to break `tests/run-make/short-ice`.
483
484            pub(crate) mod execute_query_incr {
485                use super::*;
486
487                // Adding `__rust_end_short_backtrace` marker to backtraces so that we emit the frames
488                // when `RUST_BACKTRACE=1`, add a new mod with `$name` here is to allow duplicate naming
489                #[inline(never)]
490                pub(crate) fn __rust_end_short_backtrace<'tcx>(
491                    tcx: TyCtxt<'tcx>,
492                    span: Span,
493                    key: queries::$name::Key<'tcx>,
494                    mode: QueryMode,
495                ) -> Option<Erased<queries::$name::Value<'tcx>>> {
496                    #[cfg(debug_assertions)]
497                    let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered();
498                    execution::execute_query_incr_inner(
499                        &tcx.query_system.query_vtables.$name,
500                        tcx,
501                        span,
502                        key,
503                        mode
504                    )
505                }
506            }
507
508            pub(crate) mod execute_query_non_incr {
509                use super::*;
510
511                #[inline(never)]
512                pub(crate) fn __rust_end_short_backtrace<'tcx>(
513                    tcx: TyCtxt<'tcx>,
514                    span: Span,
515                    key: queries::$name::Key<'tcx>,
516                    __mode: QueryMode,
517                ) -> Option<Erased<queries::$name::Value<'tcx>>> {
518                    Some(execution::execute_query_non_incr_inner(
519                        &tcx.query_system.query_vtables.$name,
520                        tcx,
521                        span,
522                        key,
523                    ))
524                }
525            }
526
527            /// Defines an `invoke_provider` function that calls the query's provider,
528            /// to be used as a function pointer in the query's vtable.
529            ///
530            /// To mark a short-backtrace boundary, the function's actual name
531            /// (after demangling) must be `__rust_begin_short_backtrace`.
532            mod invoke_provider_fn {
533                use super::*;
534                use ::rustc_middle::queries::$name::{Key, Value, provided_to_erased};
535
536                #[inline(never)]
537                pub(crate) fn __rust_begin_short_backtrace<'tcx>(
538                    tcx: TyCtxt<'tcx>,
539                    key: Key<'tcx>,
540                ) -> Erased<Value<'tcx>> {
541                    #[cfg(debug_assertions)]
542                    let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered();
543
544                    // Call the actual provider function for this query.
545                    let provided_value = call_provider!([$($modifiers)*][tcx, $name, key]);
546
547                    rustc_middle::ty::print::with_reduced_queries!({
548                        tracing::trace!(?provided_value);
549                    });
550
551                    // Erase the returned value, because `QueryVTable` uses erased values.
552                    // For queries with `arena_cache`, this also arena-allocates the value.
553                    provided_to_erased(tcx, provided_value)
554                }
555            }
556
557            pub(crate) fn make_query_vtable<'tcx>(incremental: bool)
558                -> QueryVTable<'tcx, queries::$name::Cache<'tcx>>
559            {
560                QueryVTable {
561                    name: stringify!($name),
562                    anon: is_anon!([$($modifiers)*]),
563                    eval_always: is_eval_always!([$($modifiers)*]),
564                    depth_limit: is_depth_limit!([$($modifiers)*]),
565                    feedable: is_feedable!([$($modifiers)*]),
566                    dep_kind: dep_graph::DepKind::$name,
567                    cycle_error_handling: cycle_error_handling!([$($modifiers)*]),
568                    state: Default::default(),
569                    cache: Default::default(),
570                    will_cache_on_disk_for_key_fn: if_cache_on_disk!([$($modifiers)*] {
571                        Some(::rustc_middle::queries::_cache_on_disk_if_fns::$name)
572                    } {
573                        None
574                    }),
575                    call_query_method_fn: |tcx, key| {
576                        // Call the query method for its side-effect of loading a value
577                        // from disk-cache; the caller doesn't need the value.
578                        let _ = tcx.$name(key);
579                    },
580                    invoke_provider_fn: self::invoke_provider_fn::__rust_begin_short_backtrace,
581                    try_load_from_disk_fn: if_cache_on_disk!([$($modifiers)*] {
582                        Some(|tcx, key, prev_index, index| {
583                            // Check the `cache_on_disk_if` condition for this key.
584                            if !::rustc_middle::queries::_cache_on_disk_if_fns::$name(tcx, key) {
585                                return None;
586                            }
587
588                            let value: queries::$name::ProvidedValue<'tcx> =
589                                $crate::plumbing::try_load_from_disk(tcx, prev_index, index)?;
590
591                            // Arena-alloc the value if appropriate, and erase it.
592                            Some(queries::$name::provided_to_erased(tcx, value))
593                        })
594                    } {
595                        None
596                    }),
597                    is_loadable_from_disk_fn: if_cache_on_disk!([$($modifiers)*] {
598                        Some(|tcx, key, index| -> bool {
599                            ::rustc_middle::queries::_cache_on_disk_if_fns::$name(tcx, key) &&
600                                $crate::plumbing::loadable_from_disk(tcx, index)
601                        })
602                    } {
603                        None
604                    }),
605                    value_from_cycle_error: |tcx, cycle, guar| {
606                        let result: queries::$name::Value<'tcx> = Value::from_cycle_error(tcx, cycle, guar);
607                        erase::erase_val(result)
608                    },
609                    hash_result: hash_result!([$($modifiers)*][queries::$name::Value<'tcx>]),
610                    format_value: |value| format!("{:?}", erase::restore_val::<queries::$name::Value<'tcx>>(*value)),
611                    description_fn: $crate::queries::_description_fns::$name,
612                    execute_query_fn: if incremental {
613                        query_impl::$name::execute_query_incr::__rust_end_short_backtrace
614                    } else {
615                        query_impl::$name::execute_query_non_incr::__rust_end_short_backtrace
616                    },
617                }
618            }
619
620            /// Marker type that implements [`GetQueryVTable`] for this query.
621            pub(crate) enum VTableGetter {}
622
623            impl<'tcx> GetQueryVTable<'tcx> for VTableGetter {
624                type Cache = rustc_middle::queries::$name::Cache<'tcx>;
625
626                #[inline(always)]
627                fn query_vtable(tcx: TyCtxt<'tcx>) -> &'tcx QueryVTable<'tcx, Self::Cache> {
628                    &tcx.query_system.query_vtables.$name
629                }
630            }
631
632            /// Internal per-query plumbing for collecting the set of active jobs for this query.
633            ///
634            /// Should only be called through `PER_QUERY_GATHER_ACTIVE_JOBS_FNS`.
635            pub(crate) fn gather_active_jobs<'tcx>(
636                tcx: TyCtxt<'tcx>,
637                require_complete: bool,
638                job_map_out: &mut QueryJobMap<'tcx>,
639            ) -> Option<()> {
640                let make_frame = |tcx: TyCtxt<'tcx>, key| {
641                    let vtable = &tcx.query_system.query_vtables.$name;
642                    $crate::plumbing::create_deferred_query_stack_frame(tcx, vtable, key)
643                };
644
645                // Call `gather_active_jobs_inner` to do the actual work.
646                let res = crate::execution::gather_active_jobs_inner(
647                    &tcx.query_system.query_vtables.$name.state,
648                    tcx,
649                    make_frame,
650                    require_complete,
651                    job_map_out,
652                );
653
654                // this can be called during unwinding, and the function has a `try_`-prefix, so
655                // don't `unwrap()` here, just manually check for `None` and do best-effort error
656                // reporting.
657                if res.is_none() {
658                    tracing::warn!(
659                        "Failed to collect active jobs for query with name `{}`!",
660                        stringify!($name)
661                    );
662                }
663                res
664            }
665
666            pub(crate) fn alloc_self_profile_query_strings<'tcx>(
667                tcx: TyCtxt<'tcx>,
668                string_cache: &mut QueryKeyStringCache
669            ) {
670                $crate::profiling_support::alloc_self_profile_query_strings_for_query_cache(
671                    tcx,
672                    stringify!($name),
673                    &tcx.query_system.query_vtables.$name.cache,
674                    string_cache,
675                )
676            }
677
678            item_if_cache_on_disk! { [$($modifiers)*]
679                pub(crate) fn encode_query_results<'tcx>(
680                    tcx: TyCtxt<'tcx>,
681                    encoder: &mut CacheEncoder<'_, 'tcx>,
682                    query_result_index: &mut EncodedDepNodeIndex
683                ) {
684                    $crate::plumbing::encode_query_results_inner(
685                        tcx,
686                        &tcx.query_system.query_vtables.$name,
687                        encoder,
688                        query_result_index,
689                    )
690                }
691            }
692
693            pub(crate) fn query_key_hash_verify<'tcx>(tcx: TyCtxt<'tcx>) {
694                $crate::plumbing::query_key_hash_verify(
695                    &tcx.query_system.query_vtables.$name,
696                    tcx,
697                )
698            }
699        })*}
700
701        pub fn make_query_vtables<'tcx>(incremental: bool) -> queries::QueryVTables<'tcx> {
702            queries::QueryVTables {
703                $(
704                    $name: query_impl::$name::make_query_vtable(incremental),
705                )*
706            }
707        }
708
709        // These arrays are used for iteration and can't be indexed by `DepKind`.
710
711        /// Used by `collect_active_jobs_from_all_queries` to iterate over all
712        /// queries, and gather the active jobs for each query.
713        ///
714        /// (We arbitrarily use the word "gather" when collecting the jobs for
715        /// each individual query, so that we have distinct function names to
716        /// grep for.)
717        const PER_QUERY_GATHER_ACTIVE_JOBS_FNS: &[
718            for<'tcx> fn(
719                tcx: TyCtxt<'tcx>,
720                require_complete: bool,
721                job_map_out: &mut QueryJobMap<'tcx>,
722            ) -> Option<()>
723        ] = &[
724            $( $crate::query_impl::$name::gather_active_jobs ),*
725        ];
726
727        const ALLOC_SELF_PROFILE_QUERY_STRINGS: &[
728            for<'tcx> fn(TyCtxt<'tcx>, &mut QueryKeyStringCache)
729        ] = &[$(query_impl::$name::alloc_self_profile_query_strings),*];
730
731        const ENCODE_QUERY_RESULTS: &[
732            Option<for<'tcx> fn(
733                TyCtxt<'tcx>,
734                &mut CacheEncoder<'_, 'tcx>,
735                &mut EncodedDepNodeIndex)
736            >
737        ] = &[
738            $(
739                if_cache_on_disk!([$($modifiers)*] {
740                    Some(query_impl::$name::encode_query_results)
741                } {
742                    None
743                })
744            ),*
745        ];
746
747        const QUERY_KEY_HASH_VERIFY: &[
748            for<'tcx> fn(TyCtxt<'tcx>)
749        ] = &[$(query_impl::$name::query_key_hash_verify),*];
750
751        /// Declares a dep-kind vtable constructor for each query.
752        mod _dep_kind_vtable_ctors_for_queries {
753            use ::rustc_middle::dep_graph::DepKindVTable;
754            use $crate::dep_kind_vtables::make_dep_kind_vtable_for_query;
755
756            $(
757                /// `DepKindVTable` constructor for this query.
758                pub(crate) fn $name<'tcx>() -> DepKindVTable<'tcx> {
759                    use $crate::query_impl::$name::VTableGetter;
760                    make_dep_kind_vtable_for_query::<VTableGetter>(
761                        is_anon!([$($modifiers)*]),
762                        is_eval_always!([$($modifiers)*]),
763                    )
764                }
765            )*
766        }
767    }
768}