1 use crate::dep_graph;
2 use crate::dep_graph::DepKind;
3 use crate::query::on_disk_cache::CacheEncoder;
4 use crate::query::on_disk_cache::EncodedDepNodeIndex;
5 use crate::query::on_disk_cache::OnDiskCache;
6 use crate::query::{
7 DynamicQueries, ExternProviders, Providers, QueryArenas, QueryCaches, QueryEngine, QueryStates,
8 };
9 use crate::ty::TyCtxt;
10 use field_offset::FieldOffset;
11 use measureme::StringId;
12 use rustc_data_structures::fx::FxHashMap;
13 use rustc_data_structures::sync::AtomicU64;
14 use rustc_hir::def::DefKind;
15 use rustc_hir::def_id::{DefId, LocalDefId};
16 use rustc_hir::hir_id::OwnerId;
17 use rustc_query_system::dep_graph::DepNodeIndex;
18 use rustc_query_system::dep_graph::SerializedDepNodeIndex;
19 pub(crate) use rustc_query_system::query::QueryJobId;
20 use rustc_query_system::query::*;
21 use rustc_query_system::HandleCycleError;
22 use rustc_span::{Span, DUMMY_SP};
23 use std::ops::Deref;
24
25 pub struct QueryKeyStringCache {
26 pub def_id_cache: FxHashMap<DefId, StringId>,
27 }
28
29 impl QueryKeyStringCache {
new() -> QueryKeyStringCache30 pub fn new() -> QueryKeyStringCache {
31 QueryKeyStringCache { def_id_cache: Default::default() }
32 }
33 }
34
35 pub struct DynamicQuery<'tcx, C: QueryCache> {
36 pub name: &'static str,
37 pub eval_always: bool,
38 pub dep_kind: DepKind,
39 pub handle_cycle_error: HandleCycleError,
40 pub query_state: FieldOffset<QueryStates<'tcx>, QueryState<C::Key, DepKind>>,
41 pub query_cache: FieldOffset<QueryCaches<'tcx>, C>,
42 pub cache_on_disk: fn(tcx: TyCtxt<'tcx>, key: &C::Key) -> bool,
43 pub execute_query: fn(tcx: TyCtxt<'tcx>, k: C::Key) -> C::Value,
44 pub compute: fn(tcx: TyCtxt<'tcx>, key: C::Key) -> C::Value,
45 pub can_load_from_disk: bool,
46 pub try_load_from_disk: fn(
47 tcx: TyCtxt<'tcx>,
48 key: &C::Key,
49 prev_index: SerializedDepNodeIndex,
50 index: DepNodeIndex,
51 ) -> Option<C::Value>,
52 pub loadable_from_disk:
53 fn(tcx: TyCtxt<'tcx>, key: &C::Key, index: SerializedDepNodeIndex) -> bool,
54 pub hash_result: HashResult<C::Value>,
55 pub value_from_cycle_error: fn(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> C::Value,
56 pub format_value: fn(&C::Value) -> String,
57 }
58
59 pub struct QuerySystemFns<'tcx> {
60 pub engine: QueryEngine,
61 pub local_providers: Providers,
62 pub extern_providers: ExternProviders,
63 pub encode_query_results: fn(
64 tcx: TyCtxt<'tcx>,
65 encoder: &mut CacheEncoder<'_, 'tcx>,
66 query_result_index: &mut EncodedDepNodeIndex,
67 ),
68 pub try_mark_green: fn(tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool,
69 }
70
71 pub struct QuerySystem<'tcx> {
72 pub states: QueryStates<'tcx>,
73 pub arenas: QueryArenas<'tcx>,
74 pub caches: QueryCaches<'tcx>,
75 pub dynamic_queries: DynamicQueries<'tcx>,
76
77 /// This provides access to the incremental compilation on-disk cache for query results.
78 /// Do not access this directly. It is only meant to be used by
79 /// `DepGraph::try_mark_green()` and the query infrastructure.
80 /// This is `None` if we are not incremental compilation mode
81 pub on_disk_cache: Option<OnDiskCache<'tcx>>,
82
83 pub fns: QuerySystemFns<'tcx>,
84
85 pub jobs: AtomicU64,
86 }
87
88 #[derive(Copy, Clone)]
89 pub struct TyCtxtAt<'tcx> {
90 pub tcx: TyCtxt<'tcx>,
91 pub span: Span,
92 }
93
94 impl<'tcx> Deref for TyCtxtAt<'tcx> {
95 type Target = TyCtxt<'tcx>;
96 #[inline(always)]
deref(&self) -> &Self::Target97 fn deref(&self) -> &Self::Target {
98 &self.tcx
99 }
100 }
101
102 #[derive(Copy, Clone)]
103 pub struct TyCtxtEnsure<'tcx> {
104 pub tcx: TyCtxt<'tcx>,
105 }
106
107 #[derive(Copy, Clone)]
108 pub struct TyCtxtEnsureWithValue<'tcx> {
109 pub tcx: TyCtxt<'tcx>,
110 }
111
112 impl<'tcx> TyCtxt<'tcx> {
113 /// Returns a transparent wrapper for `TyCtxt`, which ensures queries
114 /// are executed instead of just returning their results.
115 #[inline(always)]
ensure(self) -> TyCtxtEnsure<'tcx>116 pub fn ensure(self) -> TyCtxtEnsure<'tcx> {
117 TyCtxtEnsure { tcx: self }
118 }
119
120 /// Returns a transparent wrapper for `TyCtxt`, which ensures queries
121 /// are executed instead of just returning their results.
122 ///
123 /// This version verifies that the computed result exists in the cache before returning.
124 #[inline(always)]
ensure_with_value(self) -> TyCtxtEnsureWithValue<'tcx>125 pub fn ensure_with_value(self) -> TyCtxtEnsureWithValue<'tcx> {
126 TyCtxtEnsureWithValue { tcx: self }
127 }
128
129 /// Returns a transparent wrapper for `TyCtxt` which uses
130 /// `span` as the location of queries performed through it.
131 #[inline(always)]
at(self, span: Span) -> TyCtxtAt<'tcx>132 pub fn at(self, span: Span) -> TyCtxtAt<'tcx> {
133 TyCtxtAt { tcx: self, span }
134 }
135
try_mark_green(self, dep_node: &dep_graph::DepNode) -> bool136 pub fn try_mark_green(self, dep_node: &dep_graph::DepNode) -> bool {
137 (self.query_system.fns.try_mark_green)(self, dep_node)
138 }
139 }
140
141 #[inline]
query_get_at<'tcx, Cache>( tcx: TyCtxt<'tcx>, execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>, query_cache: &Cache, span: Span, key: Cache::Key, ) -> Cache::Value where Cache: QueryCache,142 pub fn query_get_at<'tcx, Cache>(
143 tcx: TyCtxt<'tcx>,
144 execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>,
145 query_cache: &Cache,
146 span: Span,
147 key: Cache::Key,
148 ) -> Cache::Value
149 where
150 Cache: QueryCache,
151 {
152 let key = key.into_query_param();
153 match try_get_cached(tcx, query_cache, &key) {
154 Some(value) => value,
155 None => execute_query(tcx, span, key, QueryMode::Get).unwrap(),
156 }
157 }
158
159 #[inline]
query_ensure<'tcx, Cache>( tcx: TyCtxt<'tcx>, execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>, query_cache: &Cache, key: Cache::Key, check_cache: bool, ) where Cache: QueryCache,160 pub fn query_ensure<'tcx, Cache>(
161 tcx: TyCtxt<'tcx>,
162 execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>,
163 query_cache: &Cache,
164 key: Cache::Key,
165 check_cache: bool,
166 ) where
167 Cache: QueryCache,
168 {
169 let key = key.into_query_param();
170 if try_get_cached(tcx, query_cache, &key).is_none() {
171 execute_query(tcx, DUMMY_SP, key, QueryMode::Ensure { check_cache });
172 }
173 }
174
175 macro_rules! query_helper_param_ty {
176 (DefId) => { impl IntoQueryParam<DefId> };
177 (LocalDefId) => { impl IntoQueryParam<LocalDefId> };
178 ($K:ty) => { $K };
179 }
180
181 macro_rules! query_if_arena {
182 ([] $arena:tt $no_arena:tt) => {
183 $no_arena
184 };
185 ([(arena_cache) $($rest:tt)*] $arena:tt $no_arena:tt) => {
186 $arena
187 };
188 ([$other:tt $($modifiers:tt)*]$($args:tt)*) => {
189 query_if_arena!([$($modifiers)*]$($args)*)
190 };
191 }
192
193 /// If `separate_provide_if_extern`, then the key can be projected to its
194 /// local key via `<$K as AsLocalKey>::LocalKey`.
195 macro_rules! local_key_if_separate_extern {
196 ([] $($K:tt)*) => {
197 $($K)*
198 };
199 ([(separate_provide_extern) $($rest:tt)*] $($K:tt)*) => {
200 <$($K)* as AsLocalKey>::LocalKey
201 };
202 ([$other:tt $($modifiers:tt)*] $($K:tt)*) => {
203 local_key_if_separate_extern!([$($modifiers)*] $($K)*)
204 };
205 }
206
207 macro_rules! separate_provide_extern_decl {
208 ([][$name:ident]) => {
209 ()
210 };
211 ([(separate_provide_extern) $($rest:tt)*][$name:ident]) => {
212 for<'tcx> fn(
213 TyCtxt<'tcx>,
214 queries::$name::Key<'tcx>,
215 ) -> queries::$name::ProvidedValue<'tcx>
216 };
217 ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
218 separate_provide_extern_decl!([$($modifiers)*][$($args)*])
219 };
220 }
221
222 macro_rules! separate_provide_extern_default {
223 ([][$name:ident]) => {
224 ()
225 };
226 ([(separate_provide_extern) $($rest:tt)*][$name:ident]) => {
227 |_, key| bug!(
228 "`tcx.{}({:?})` unsupported by its crate; \
229 perhaps the `{}` query was never assigned a provider function",
230 stringify!($name),
231 key,
232 stringify!($name),
233 )
234 };
235 ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
236 separate_provide_extern_default!([$($modifiers)*][$($args)*])
237 };
238 }
239
240 macro_rules! define_callbacks {
241 (
242 $($(#[$attr:meta])*
243 [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => {
244
245 #[allow(unused_lifetimes)]
246 pub mod queries {
247 $(pub mod $name {
248 use super::super::*;
249
250 pub type Key<'tcx> = $($K)*;
251 pub type Value<'tcx> = $V;
252
253 pub type LocalKey<'tcx> = local_key_if_separate_extern!([$($modifiers)*] $($K)*);
254
255 /// This type alias specifies the type returned from query providers and the type
256 /// used for decoding. For regular queries this is the declared returned type `V`,
257 /// but `arena_cache` will use `<V as Deref>::Target` instead.
258 pub type ProvidedValue<'tcx> = query_if_arena!(
259 [$($modifiers)*]
260 (<$V as Deref>::Target)
261 ($V)
262 );
263
264 /// This function takes `ProvidedValue` and coverts it to an erased `Value` by
265 /// allocating it on an arena if the query has the `arena_cache` modifier. The
266 /// value is then erased and returned. This will happen when computing the query
267 /// using a provider or decoding a stored result.
268 #[inline(always)]
269 pub fn provided_to_erased<'tcx>(
270 _tcx: TyCtxt<'tcx>,
271 value: ProvidedValue<'tcx>,
272 ) -> Erase<Value<'tcx>> {
273 erase(query_if_arena!([$($modifiers)*]
274 {
275 if mem::needs_drop::<ProvidedValue<'tcx>>() {
276 &*_tcx.query_system.arenas.$name.alloc(value)
277 } else {
278 &*_tcx.arena.dropless.alloc(value)
279 }
280 }
281 (value)
282 ))
283 }
284
285 pub type Storage<'tcx> = <
286 <$($K)* as keys::Key>::CacheSelector as CacheSelector<'tcx, Erase<$V>>
287 >::Cache;
288
289 // Ensure that keys grow no larger than 64 bytes
290 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
291 const _: () = {
292 if mem::size_of::<Key<'static>>() > 64 {
293 panic!("{}", concat!(
294 "the query `",
295 stringify!($name),
296 "` has a key type `",
297 stringify!($($K)*),
298 "` that is too large"
299 ));
300 }
301 };
302
303 // Ensure that values grow no larger than 64 bytes
304 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
305 const _: () = {
306 if mem::size_of::<Value<'static>>() > 64 {
307 panic!("{}", concat!(
308 "the query `",
309 stringify!($name),
310 "` has a value type `",
311 stringify!($V),
312 "` that is too large"
313 ));
314 }
315 };
316 })*
317 }
318
319 pub struct QueryArenas<'tcx> {
320 $($(#[$attr])* pub $name: query_if_arena!([$($modifiers)*]
321 (WorkerLocal<TypedArena<<$V as Deref>::Target>>)
322 ()
323 ),)*
324 }
325
326 impl Default for QueryArenas<'_> {
327 fn default() -> Self {
328 Self {
329 $($name: query_if_arena!([$($modifiers)*]
330 (WorkerLocal::new(|_| Default::default()))
331 ()
332 ),)*
333 }
334 }
335 }
336
337 #[derive(Default)]
338 pub struct QueryCaches<'tcx> {
339 $($(#[$attr])* pub $name: queries::$name::Storage<'tcx>,)*
340 }
341
342 impl<'tcx> TyCtxtEnsure<'tcx> {
343 $($(#[$attr])*
344 #[inline(always)]
345 pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
346 query_ensure(
347 self.tcx,
348 self.tcx.query_system.fns.engine.$name,
349 &self.tcx.query_system.caches.$name,
350 key.into_query_param(),
351 false,
352 );
353 })*
354 }
355
356 impl<'tcx> TyCtxtEnsureWithValue<'tcx> {
357 $($(#[$attr])*
358 #[inline(always)]
359 pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
360 query_ensure(
361 self.tcx,
362 self.tcx.query_system.fns.engine.$name,
363 &self.tcx.query_system.caches.$name,
364 key.into_query_param(),
365 true,
366 );
367 })*
368 }
369
370 impl<'tcx> TyCtxt<'tcx> {
371 $($(#[$attr])*
372 #[inline(always)]
373 #[must_use]
374 pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V
375 {
376 self.at(DUMMY_SP).$name(key)
377 })*
378 }
379
380 impl<'tcx> TyCtxtAt<'tcx> {
381 $($(#[$attr])*
382 #[inline(always)]
383 pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V
384 {
385 restore::<$V>(query_get_at(
386 self.tcx,
387 self.tcx.query_system.fns.engine.$name,
388 &self.tcx.query_system.caches.$name,
389 self.span,
390 key.into_query_param(),
391 ))
392 })*
393 }
394
395 pub struct DynamicQueries<'tcx> {
396 $(
397 pub $name: DynamicQuery<'tcx, queries::$name::Storage<'tcx>>,
398 )*
399 }
400
401 #[derive(Default)]
402 pub struct QueryStates<'tcx> {
403 $(
404 pub $name: QueryState<$($K)*, DepKind>,
405 )*
406 }
407
408 pub struct Providers {
409 $(pub $name: for<'tcx> fn(
410 TyCtxt<'tcx>,
411 queries::$name::LocalKey<'tcx>,
412 ) -> queries::$name::ProvidedValue<'tcx>,)*
413 }
414
415 pub struct ExternProviders {
416 $(pub $name: separate_provide_extern_decl!([$($modifiers)*][$name]),)*
417 }
418
419 impl Default for Providers {
420 fn default() -> Self {
421 Providers {
422 $($name: |_, key| bug!(
423 "`tcx.{}({:?})` is not supported for this key;\n\
424 hint: Queries can be either made to the local crate, or the external crate. \
425 This error means you tried to use it for one that's not supported.\n\
426 If that's not the case, {} was likely never assigned to a provider function.\n",
427 stringify!($name),
428 key,
429 stringify!($name),
430 ),)*
431 }
432 }
433 }
434
435 impl Default for ExternProviders {
436 fn default() -> Self {
437 ExternProviders {
438 $($name: separate_provide_extern_default!([$($modifiers)*][$name]),)*
439 }
440 }
441 }
442
443 impl Copy for Providers {}
444 impl Clone for Providers {
445 fn clone(&self) -> Self { *self }
446 }
447
448 impl Copy for ExternProviders {}
449 impl Clone for ExternProviders {
450 fn clone(&self) -> Self { *self }
451 }
452
453 pub struct QueryEngine {
454 $(pub $name: for<'tcx> fn(
455 TyCtxt<'tcx>,
456 Span,
457 queries::$name::Key<'tcx>,
458 QueryMode,
459 ) -> Option<Erase<$V>>,)*
460 }
461 };
462 }
463
464 macro_rules! hash_result {
465 ([]) => {{
466 Some(dep_graph::hash_result)
467 }};
468 ([(no_hash) $($rest:tt)*]) => {{
469 None
470 }};
471 ([$other:tt $($modifiers:tt)*]) => {
472 hash_result!([$($modifiers)*])
473 };
474 }
475
476 macro_rules! define_feedable {
477 ($($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => {
478 $(impl<'tcx, K: IntoQueryParam<$($K)*> + Copy> TyCtxtFeed<'tcx, K> {
479 $(#[$attr])*
480 #[inline(always)]
481 pub fn $name(self, value: queries::$name::ProvidedValue<'tcx>) {
482 let key = self.key().into_query_param();
483
484 let tcx = self.tcx;
485 let erased = queries::$name::provided_to_erased(tcx, value);
486 let value = restore::<$V>(erased);
487 let cache = &tcx.query_system.caches.$name;
488
489 let hasher: Option<fn(&mut StableHashingContext<'_>, &_) -> _> = hash_result!([$($modifiers)*]);
490 match try_get_cached(tcx, cache, &key) {
491 Some(old) => {
492 let old = restore::<$V>(old);
493 if let Some(hasher) = hasher {
494 let (value_hash, old_hash): (Fingerprint, Fingerprint) = tcx.with_stable_hashing_context(|mut hcx|
495 (hasher(&mut hcx, &value), hasher(&mut hcx, &old))
496 );
497 if old_hash != value_hash {
498 // We have an inconsistency. This can happen if one of the two
499 // results is tainted by errors. In this case, delay a bug to
500 // ensure compilation is doomed, and keep the `old` value.
501 tcx.sess.delay_span_bug(DUMMY_SP, format!(
502 "Trying to feed an already recorded value for query {} key={key:?}:\n\
503 old value: {old:?}\nnew value: {value:?}",
504 stringify!($name),
505 ));
506 }
507 } else {
508 // The query is `no_hash`, so we have no way to perform a sanity check.
509 // If feeding the same value multiple times needs to be supported,
510 // the query should not be marked `no_hash`.
511 bug!(
512 "Trying to feed an already recorded value for query {} key={key:?}:\nold value: {old:?}\nnew value: {value:?}",
513 stringify!($name),
514 )
515 }
516 }
517 None => {
518 let dep_node = dep_graph::DepNode::construct(tcx, dep_graph::DepKind::$name, &key);
519 let dep_node_index = tcx.dep_graph.with_feed_task(
520 dep_node,
521 tcx,
522 key,
523 &value,
524 hash_result!([$($modifiers)*]),
525 );
526 cache.complete(key, erased, dep_node_index);
527 }
528 }
529 }
530 })*
531 }
532 }
533
534 // Each of these queries corresponds to a function pointer field in the
535 // `Providers` struct for requesting a value of that type, and a method
536 // on `tcx: TyCtxt` (and `tcx.at(span)`) for doing that request in a way
537 // which memoizes and does dep-graph tracking, wrapping around the actual
538 // `Providers` that the driver creates (using several `rustc_*` crates).
539 //
540 // The result type of each query must implement `Clone`, and additionally
541 // `ty::query::values::Value`, which produces an appropriate placeholder
542 // (error) value if the query resulted in a query cycle.
543 // Queries marked with `fatal_cycle` do not need the latter implementation,
544 // as they will raise an fatal error on query cycles instead.
545
546 mod sealed {
547 use super::{DefId, LocalDefId, OwnerId};
548
549 /// An analogue of the `Into` trait that's intended only for query parameters.
550 ///
551 /// This exists to allow queries to accept either `DefId` or `LocalDefId` while requiring that the
552 /// user call `to_def_id` to convert between them everywhere else.
553 pub trait IntoQueryParam<P> {
into_query_param(self) -> P554 fn into_query_param(self) -> P;
555 }
556
557 impl<P> IntoQueryParam<P> for P {
558 #[inline(always)]
into_query_param(self) -> P559 fn into_query_param(self) -> P {
560 self
561 }
562 }
563
564 impl<'a, P: Copy> IntoQueryParam<P> for &'a P {
565 #[inline(always)]
into_query_param(self) -> P566 fn into_query_param(self) -> P {
567 *self
568 }
569 }
570
571 impl IntoQueryParam<LocalDefId> for OwnerId {
572 #[inline(always)]
into_query_param(self) -> LocalDefId573 fn into_query_param(self) -> LocalDefId {
574 self.def_id
575 }
576 }
577
578 impl IntoQueryParam<DefId> for LocalDefId {
579 #[inline(always)]
into_query_param(self) -> DefId580 fn into_query_param(self) -> DefId {
581 self.to_def_id()
582 }
583 }
584
585 impl IntoQueryParam<DefId> for OwnerId {
586 #[inline(always)]
into_query_param(self) -> DefId587 fn into_query_param(self) -> DefId {
588 self.to_def_id()
589 }
590 }
591 }
592
593 pub use sealed::IntoQueryParam;
594
595 impl<'tcx> TyCtxt<'tcx> {
def_kind(self, def_id: impl IntoQueryParam<DefId>) -> DefKind596 pub fn def_kind(self, def_id: impl IntoQueryParam<DefId>) -> DefKind {
597 let def_id = def_id.into_query_param();
598 self.opt_def_kind(def_id)
599 .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id))
600 }
601 }
602
603 impl<'tcx> TyCtxtAt<'tcx> {
def_kind(self, def_id: impl IntoQueryParam<DefId>) -> DefKind604 pub fn def_kind(self, def_id: impl IntoQueryParam<DefId>) -> DefKind {
605 let def_id = def_id.into_query_param();
606 self.opt_def_kind(def_id)
607 .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id))
608 }
609 }
610