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