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