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