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