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