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, QueryStackDeferred,
30    QueryState, 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>(
88        self,
89        qcx: QueryCtxt<'tcx>,
90    ) -> &'a QueryState<Self::Key, QueryStackDeferred<'tcx>>
91    where
92        QueryCtxt<'tcx>: 'a,
93    {
94        // Safety:
95        // This is just manually doing the subfield referencing through pointer math.
96        unsafe {
97            &*(&qcx.tcx.query_system.states as *const QueryStates<'tcx>)
98                .byte_add(self.dynamic.query_state)
99                .cast::<QueryState<Self::Key, QueryStackDeferred<'tcx>>>()
100        }
101    }
102
103    #[inline(always)]
104    fn query_cache<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a Self::Cache
105    where
106        'tcx: 'a,
107    {
108        // Safety:
109        // This is just manually doing the subfield referencing through pointer math.
110        unsafe {
111            &*(&qcx.tcx.query_system.caches as *const QueryCaches<'tcx>)
112                .byte_add(self.dynamic.query_cache)
113                .cast::<Self::Cache>()
114        }
115    }
116
117    #[inline(always)]
118    fn execute_query(self, tcx: TyCtxt<'tcx>, key: Self::Key) -> Self::Value {
119        (self.dynamic.execute_query)(tcx, key)
120    }
121
122    #[inline(always)]
123    fn compute(self, qcx: QueryCtxt<'tcx>, key: Self::Key) -> Self::Value {
124        (self.dynamic.compute)(qcx.tcx, key)
125    }
126
127    #[inline(always)]
128    fn try_load_from_disk(
129        self,
130        qcx: QueryCtxt<'tcx>,
131        key: &Self::Key,
132        prev_index: SerializedDepNodeIndex,
133        index: DepNodeIndex,
134    ) -> Option<Self::Value> {
135        if self.dynamic.can_load_from_disk {
136            (self.dynamic.try_load_from_disk)(qcx.tcx, key, prev_index, index)
137        } else {
138            None
139        }
140    }
141
142    #[inline]
143    fn loadable_from_disk(
144        self,
145        qcx: QueryCtxt<'tcx>,
146        key: &Self::Key,
147        index: SerializedDepNodeIndex,
148    ) -> bool {
149        (self.dynamic.loadable_from_disk)(qcx.tcx, key, index)
150    }
151
152    fn value_from_cycle_error(
153        self,
154        tcx: TyCtxt<'tcx>,
155        cycle_error: &CycleError,
156        guar: ErrorGuaranteed,
157    ) -> Self::Value {
158        (self.dynamic.value_from_cycle_error)(tcx, cycle_error, guar)
159    }
160
161    #[inline(always)]
162    fn format_value(self) -> fn(&Self::Value) -> String {
163        self.dynamic.format_value
164    }
165
166    #[inline(always)]
167    fn anon(self) -> bool {
168        ANON
169    }
170
171    #[inline(always)]
172    fn eval_always(self) -> bool {
173        self.dynamic.eval_always
174    }
175
176    #[inline(always)]
177    fn depth_limit(self) -> bool {
178        DEPTH_LIMIT
179    }
180
181    #[inline(always)]
182    fn feedable(self) -> bool {
183        FEEDABLE
184    }
185
186    #[inline(always)]
187    fn dep_kind(self) -> DepKind {
188        self.dynamic.dep_kind
189    }
190
191    #[inline(always)]
192    fn handle_cycle_error(self) -> HandleCycleError {
193        self.dynamic.handle_cycle_error
194    }
195
196    #[inline(always)]
197    fn hash_result(self) -> HashResult<Self::Value> {
198        self.dynamic.hash_result
199    }
200}
201
202/// This is implemented per query. It allows restoring query values from their erased state
203/// and constructing a QueryConfig.
204trait QueryConfigRestored<'tcx> {
205    type RestoredValue;
206    type Config: QueryConfig<QueryCtxt<'tcx>>;
207
208    const NAME: &'static &'static str;
209
210    fn config(tcx: TyCtxt<'tcx>) -> Self::Config;
211    fn restore(value: <Self::Config as QueryConfig<QueryCtxt<'tcx>>>::Value)
212    -> Self::RestoredValue;
213}
214
215pub fn query_system<'a>(
216    local_providers: Providers,
217    extern_providers: ExternProviders,
218    on_disk_cache: Option<OnDiskCache>,
219    incremental: bool,
220) -> QuerySystem<'a> {
221    QuerySystem {
222        states: Default::default(),
223        arenas: Default::default(),
224        caches: Default::default(),
225        dynamic_queries: dynamic_queries(),
226        on_disk_cache,
227        fns: QuerySystemFns {
228            engine: engine(incremental),
229            local_providers,
230            extern_providers,
231            encode_query_results: encode_all_query_results,
232            try_mark_green,
233        },
234        jobs: AtomicU64::new(1),
235    }
236}
237
238rustc_middle::rustc_query_append! { define_queries! }
239
240pub fn provide(providers: &mut rustc_middle::util::Providers) {
241    providers.hooks.alloc_self_profile_query_strings = alloc_self_profile_query_strings;
242    providers.hooks.query_key_hash_verify_all = query_key_hash_verify_all;
243}