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