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