rustc_query_impl/
lib.rs

1//! Support for serializing the dep-graph and reloading it.
2
3// tidy-alphabetical-start
4#![allow(internal_features)]
5#![allow(unused_parens)]
6#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
7#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
8#![doc(rust_logo)]
9#![feature(min_specialization)]
10#![feature(rustc_attrs)]
11#![feature(rustdoc_internals)]
12// tidy-alphabetical-end
13
14use rustc_data_structures::stable_hasher::HashStable;
15use rustc_data_structures::sync::AtomicU64;
16use rustc_middle::arena::Arena;
17use rustc_middle::dep_graph::{self, DepKind, DepKindStruct, DepNodeIndex};
18use rustc_middle::query::erase::{Erase, erase, restore};
19use rustc_middle::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex, OnDiskCache};
20use rustc_middle::query::plumbing::{DynamicQuery, QuerySystem, QuerySystemFns};
21use rustc_middle::query::{
22    AsLocalKey, DynamicQueries, ExternProviders, Providers, QueryCaches, QueryEngine, QueryStates,
23    queries,
24};
25use rustc_middle::ty::TyCtxt;
26use rustc_query_system::dep_graph::SerializedDepNodeIndex;
27use rustc_query_system::ich::StableHashingContext;
28use rustc_query_system::query::{
29    CycleError, HashResult, QueryCache, QueryConfig, QueryMap, QueryMode, QueryState,
30    get_query_incr, get_query_non_incr,
31};
32use rustc_query_system::{HandleCycleError, Value};
33use rustc_span::{ErrorGuaranteed, Span};
34
35use crate::plumbing::{__rust_begin_short_backtrace, encode_all_query_results, try_mark_green};
36use crate::profiling_support::QueryKeyStringCache;
37
38#[macro_use]
39mod plumbing;
40pub use crate::plumbing::{QueryCtxt, query_key_hash_verify_all};
41
42mod profiling_support;
43pub use self::profiling_support::alloc_self_profile_query_strings;
44
45struct DynamicConfig<
46    'tcx,
47    C: QueryCache,
48    const ANON: bool,
49    const DEPTH_LIMIT: bool,
50    const FEEDABLE: bool,
51> {
52    dynamic: &'tcx DynamicQuery<'tcx, C>,
53}
54
55impl<'tcx, C: QueryCache, const ANON: bool, const DEPTH_LIMIT: bool, const FEEDABLE: bool> Copy
56    for DynamicConfig<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE>
57{
58}
59impl<'tcx, C: QueryCache, const ANON: bool, const DEPTH_LIMIT: bool, const FEEDABLE: bool> Clone
60    for DynamicConfig<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE>
61{
62    fn clone(&self) -> Self {
63        DynamicConfig { dynamic: self.dynamic }
64    }
65}
66
67impl<'tcx, C: QueryCache, const ANON: bool, const DEPTH_LIMIT: bool, const FEEDABLE: bool>
68    QueryConfig<QueryCtxt<'tcx>> for DynamicConfig<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE>
69where
70    for<'a> C::Key: HashStable<StableHashingContext<'a>>,
71{
72    type Key = C::Key;
73    type Value = C::Value;
74    type Cache = C;
75
76    #[inline(always)]
77    fn name(self) -> &'static str {
78        self.dynamic.name
79    }
80
81    #[inline(always)]
82    fn cache_on_disk(self, tcx: TyCtxt<'tcx>, key: &Self::Key) -> bool {
83        (self.dynamic.cache_on_disk)(tcx, key)
84    }
85
86    #[inline(always)]
87    fn query_state<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a QueryState<Self::Key>
88    where
89        QueryCtxt<'tcx>: 'a,
90    {
91        // Safety:
92        // This is just manually doing the subfield referencing through pointer math.
93        unsafe {
94            &*(&qcx.tcx.query_system.states as *const QueryStates<'tcx>)
95                .byte_add(self.dynamic.query_state)
96                .cast::<QueryState<Self::Key>>()
97        }
98    }
99
100    #[inline(always)]
101    fn query_cache<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a Self::Cache
102    where
103        'tcx: 'a,
104    {
105        // Safety:
106        // This is just manually doing the subfield referencing through pointer math.
107        unsafe {
108            &*(&qcx.tcx.query_system.caches as *const QueryCaches<'tcx>)
109                .byte_add(self.dynamic.query_cache)
110                .cast::<Self::Cache>()
111        }
112    }
113
114    #[inline(always)]
115    fn execute_query(self, tcx: TyCtxt<'tcx>, key: Self::Key) -> Self::Value {
116        (self.dynamic.execute_query)(tcx, key)
117    }
118
119    #[inline(always)]
120    fn compute(self, qcx: QueryCtxt<'tcx>, key: Self::Key) -> Self::Value {
121        (self.dynamic.compute)(qcx.tcx, key)
122    }
123
124    #[inline(always)]
125    fn try_load_from_disk(
126        self,
127        qcx: QueryCtxt<'tcx>,
128        key: &Self::Key,
129        prev_index: SerializedDepNodeIndex,
130        index: DepNodeIndex,
131    ) -> Option<Self::Value> {
132        if self.dynamic.can_load_from_disk {
133            (self.dynamic.try_load_from_disk)(qcx.tcx, key, prev_index, index)
134        } else {
135            None
136        }
137    }
138
139    #[inline]
140    fn loadable_from_disk(
141        self,
142        qcx: QueryCtxt<'tcx>,
143        key: &Self::Key,
144        index: SerializedDepNodeIndex,
145    ) -> bool {
146        (self.dynamic.loadable_from_disk)(qcx.tcx, key, index)
147    }
148
149    fn value_from_cycle_error(
150        self,
151        tcx: TyCtxt<'tcx>,
152        cycle_error: &CycleError,
153        guar: ErrorGuaranteed,
154    ) -> Self::Value {
155        (self.dynamic.value_from_cycle_error)(tcx, cycle_error, guar)
156    }
157
158    #[inline(always)]
159    fn format_value(self) -> fn(&Self::Value) -> String {
160        self.dynamic.format_value
161    }
162
163    #[inline(always)]
164    fn anon(self) -> bool {
165        ANON
166    }
167
168    #[inline(always)]
169    fn eval_always(self) -> bool {
170        self.dynamic.eval_always
171    }
172
173    #[inline(always)]
174    fn depth_limit(self) -> bool {
175        DEPTH_LIMIT
176    }
177
178    #[inline(always)]
179    fn feedable(self) -> bool {
180        FEEDABLE
181    }
182
183    #[inline(always)]
184    fn dep_kind(self) -> DepKind {
185        self.dynamic.dep_kind
186    }
187
188    #[inline(always)]
189    fn handle_cycle_error(self) -> HandleCycleError {
190        self.dynamic.handle_cycle_error
191    }
192
193    #[inline(always)]
194    fn hash_result(self) -> HashResult<Self::Value> {
195        self.dynamic.hash_result
196    }
197}
198
199/// This is implemented per query. It allows restoring query values from their erased state
200/// and constructing a QueryConfig.
201trait QueryConfigRestored<'tcx> {
202    type RestoredValue;
203    type Config: QueryConfig<QueryCtxt<'tcx>>;
204
205    const NAME: &'static &'static str;
206
207    fn config(tcx: TyCtxt<'tcx>) -> Self::Config;
208    fn restore(value: <Self::Config as QueryConfig<QueryCtxt<'tcx>>>::Value)
209    -> Self::RestoredValue;
210}
211
212pub fn query_system<'a>(
213    local_providers: Providers,
214    extern_providers: ExternProviders,
215    on_disk_cache: Option<OnDiskCache>,
216    incremental: bool,
217) -> QuerySystem<'a> {
218    QuerySystem {
219        states: Default::default(),
220        arenas: Default::default(),
221        caches: Default::default(),
222        dynamic_queries: dynamic_queries(),
223        on_disk_cache,
224        fns: QuerySystemFns {
225            engine: engine(incremental),
226            local_providers,
227            extern_providers,
228            encode_query_results: encode_all_query_results,
229            try_mark_green,
230        },
231        jobs: AtomicU64::new(1),
232    }
233}
234
235rustc_middle::rustc_query_append! { define_queries! }
236
237pub fn provide(providers: &mut rustc_middle::util::Providers) {
238    providers.hooks.alloc_self_profile_query_strings = alloc_self_profile_query_strings;
239    providers.hooks.query_key_hash_verify_all = query_key_hash_verify_all;
240}