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