• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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