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