]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_query_impl/src/plumbing.rs
New upstream version 1.69.0+dfsg1
[rustc.git] / compiler / rustc_query_impl / src / plumbing.rs
1 //! The implementation of the query system itself. This defines the macros that
2 //! generate the actual methods on tcx which find and execute the provider,
3 //! manage the caches, and so forth.
4
5 use crate::on_disk_cache::{CacheDecoder, CacheEncoder, EncodedDepNodeIndex};
6 use crate::profiling_support::QueryKeyStringCache;
7 use crate::{on_disk_cache, Queries};
8 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
9 use rustc_data_structures::sync::{AtomicU64, Lock};
10 use rustc_errors::{Diagnostic, Handler};
11 use rustc_middle::dep_graph::{
12 self, DepKind, DepKindStruct, DepNode, DepNodeIndex, SerializedDepNodeIndex,
13 };
14 use rustc_middle::query::Key;
15 use rustc_middle::ty::tls::{self, ImplicitCtxt};
16 use rustc_middle::ty::{self, TyCtxt};
17 use rustc_query_system::dep_graph::{DepNodeParams, HasDepContext};
18 use rustc_query_system::ich::StableHashingContext;
19 use rustc_query_system::query::{
20 force_query, QueryConfig, QueryContext, QueryJobId, QueryMap, QuerySideEffects, QueryStackFrame,
21 };
22 use rustc_query_system::{LayoutOfDepth, QueryOverflow, Value};
23 use rustc_serialize::Decodable;
24 use rustc_session::Limit;
25 use rustc_span::def_id::LOCAL_CRATE;
26 use std::any::Any;
27 use std::num::NonZeroU64;
28 use thin_vec::ThinVec;
29
30 #[derive(Copy, Clone)]
31 pub struct QueryCtxt<'tcx> {
32 pub tcx: TyCtxt<'tcx>,
33 pub queries: &'tcx Queries<'tcx>,
34 }
35
36 impl<'tcx> std::ops::Deref for QueryCtxt<'tcx> {
37 type Target = TyCtxt<'tcx>;
38
39 #[inline]
40 fn deref(&self) -> &Self::Target {
41 &self.tcx
42 }
43 }
44
45 impl<'tcx> HasDepContext for QueryCtxt<'tcx> {
46 type DepKind = rustc_middle::dep_graph::DepKind;
47 type DepContext = TyCtxt<'tcx>;
48
49 #[inline]
50 fn dep_context(&self) -> &Self::DepContext {
51 &self.tcx
52 }
53 }
54
55 impl QueryContext for QueryCtxt<'_> {
56 fn next_job_id(self) -> QueryJobId {
57 QueryJobId(
58 NonZeroU64::new(
59 self.queries.jobs.fetch_add(1, rustc_data_structures::sync::Ordering::Relaxed),
60 )
61 .unwrap(),
62 )
63 }
64
65 fn current_query_job(self) -> Option<QueryJobId> {
66 tls::with_related_context(*self, |icx| icx.query)
67 }
68
69 fn try_collect_active_jobs(self) -> Option<QueryMap<DepKind>> {
70 self.queries.try_collect_active_jobs(*self)
71 }
72
73 // Interactions with on_disk_cache
74 fn load_side_effects(self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects {
75 self.queries
76 .on_disk_cache
77 .as_ref()
78 .map(|c| c.load_side_effects(*self, prev_dep_node_index))
79 .unwrap_or_default()
80 }
81
82 fn store_side_effects(self, dep_node_index: DepNodeIndex, side_effects: QuerySideEffects) {
83 if let Some(c) = self.queries.on_disk_cache.as_ref() {
84 c.store_side_effects(dep_node_index, side_effects)
85 }
86 }
87
88 fn store_side_effects_for_anon_node(
89 self,
90 dep_node_index: DepNodeIndex,
91 side_effects: QuerySideEffects,
92 ) {
93 if let Some(c) = self.queries.on_disk_cache.as_ref() {
94 c.store_side_effects_for_anon_node(dep_node_index, side_effects)
95 }
96 }
97
98 /// Executes a job by changing the `ImplicitCtxt` to point to the
99 /// new query job while it executes. It returns the diagnostics
100 /// captured during execution and the actual result.
101 #[inline(always)]
102 fn start_query<R>(
103 self,
104 token: QueryJobId,
105 depth_limit: bool,
106 diagnostics: Option<&Lock<ThinVec<Diagnostic>>>,
107 compute: impl FnOnce() -> R,
108 ) -> R {
109 // The `TyCtxt` stored in TLS has the same global interner lifetime
110 // as `self`, so we use `with_related_context` to relate the 'tcx lifetimes
111 // when accessing the `ImplicitCtxt`.
112 tls::with_related_context(*self, move |current_icx| {
113 if depth_limit && !self.recursion_limit().value_within_limit(current_icx.query_depth) {
114 self.depth_limit_error(token);
115 }
116
117 // Update the `ImplicitCtxt` to point to our new query job.
118 let new_icx = ImplicitCtxt {
119 tcx: *self,
120 query: Some(token),
121 diagnostics,
122 query_depth: current_icx.query_depth + depth_limit as usize,
123 task_deps: current_icx.task_deps,
124 };
125
126 // Use the `ImplicitCtxt` while we execute the query.
127 tls::enter_context(&new_icx, compute)
128 })
129 }
130
131 fn depth_limit_error(self, job: QueryJobId) {
132 let mut span = None;
133 let mut layout_of_depth = None;
134 if let Some(map) = self.try_collect_active_jobs() {
135 if let Some((info, depth)) = job.try_find_layout_root(map) {
136 span = Some(info.job.span);
137 layout_of_depth = Some(LayoutOfDepth { desc: info.query.description, depth });
138 }
139 }
140
141 let suggested_limit = match self.recursion_limit() {
142 Limit(0) => Limit(2),
143 limit => limit * 2,
144 };
145
146 self.sess.emit_fatal(QueryOverflow {
147 span,
148 layout_of_depth,
149 suggested_limit,
150 crate_name: self.crate_name(LOCAL_CRATE),
151 });
152 }
153 }
154
155 impl<'tcx> QueryCtxt<'tcx> {
156 #[inline]
157 pub fn from_tcx(tcx: TyCtxt<'tcx>) -> Self {
158 let queries = tcx.queries.as_any();
159 let queries = unsafe {
160 let queries = std::mem::transmute::<&dyn Any, &dyn Any>(queries);
161 let queries = queries.downcast_ref().unwrap();
162 let queries = std::mem::transmute::<&Queries<'_>, &Queries<'_>>(queries);
163 queries
164 };
165 QueryCtxt { tcx, queries }
166 }
167
168 pub(crate) fn on_disk_cache(self) -> Option<&'tcx on_disk_cache::OnDiskCache<'tcx>> {
169 self.queries.on_disk_cache.as_ref()
170 }
171
172 pub(super) fn encode_query_results(
173 self,
174 encoder: &mut CacheEncoder<'_, 'tcx>,
175 query_result_index: &mut EncodedDepNodeIndex,
176 ) {
177 for query in &self.queries.query_structs {
178 if let Some(encode) = query.encode_query_results {
179 encode(self, encoder, query_result_index);
180 }
181 }
182 }
183
184 pub fn try_print_query_stack(
185 self,
186 query: Option<QueryJobId>,
187 handler: &Handler,
188 num_frames: Option<usize>,
189 ) -> usize {
190 rustc_query_system::query::print_query_stack(self, query, handler, num_frames)
191 }
192 }
193
194 #[derive(Clone, Copy)]
195 pub(crate) struct QueryStruct<'tcx> {
196 pub try_collect_active_jobs: fn(QueryCtxt<'tcx>, &mut QueryMap<DepKind>) -> Option<()>,
197 pub alloc_self_profile_query_strings: fn(TyCtxt<'tcx>, &mut QueryKeyStringCache),
198 pub encode_query_results:
199 Option<fn(QueryCtxt<'tcx>, &mut CacheEncoder<'_, 'tcx>, &mut EncodedDepNodeIndex)>,
200 }
201
202 macro_rules! handle_cycle_error {
203 ([]) => {{
204 rustc_query_system::HandleCycleError::Error
205 }};
206 ([(fatal_cycle) $($rest:tt)*]) => {{
207 rustc_query_system::HandleCycleError::Fatal
208 }};
209 ([(cycle_delay_bug) $($rest:tt)*]) => {{
210 rustc_query_system::HandleCycleError::DelayBug
211 }};
212 ([$other:tt $($modifiers:tt)*]) => {
213 handle_cycle_error!([$($modifiers)*])
214 };
215 }
216
217 macro_rules! is_anon {
218 ([]) => {{
219 false
220 }};
221 ([(anon) $($rest:tt)*]) => {{
222 true
223 }};
224 ([$other:tt $($modifiers:tt)*]) => {
225 is_anon!([$($modifiers)*])
226 };
227 }
228
229 macro_rules! is_eval_always {
230 ([]) => {{
231 false
232 }};
233 ([(eval_always) $($rest:tt)*]) => {{
234 true
235 }};
236 ([$other:tt $($modifiers:tt)*]) => {
237 is_eval_always!([$($modifiers)*])
238 };
239 }
240
241 macro_rules! depth_limit {
242 ([]) => {{
243 false
244 }};
245 ([(depth_limit) $($rest:tt)*]) => {{
246 true
247 }};
248 ([$other:tt $($modifiers:tt)*]) => {
249 depth_limit!([$($modifiers)*])
250 };
251 }
252
253 macro_rules! feedable {
254 ([]) => {{
255 false
256 }};
257 ([(feedable) $($rest:tt)*]) => {{
258 true
259 }};
260 ([$other:tt $($modifiers:tt)*]) => {
261 feedable!([$($modifiers)*])
262 };
263 }
264
265 macro_rules! hash_result {
266 ([]) => {{
267 Some(dep_graph::hash_result)
268 }};
269 ([(no_hash) $($rest:tt)*]) => {{
270 None
271 }};
272 ([$other:tt $($modifiers:tt)*]) => {
273 hash_result!([$($modifiers)*])
274 };
275 }
276
277 macro_rules! get_provider {
278 ([][$tcx:expr, $name:ident, $key:expr]) => {{
279 $tcx.queries.local_providers.$name
280 }};
281 ([(separate_provide_extern) $($rest:tt)*][$tcx:expr, $name:ident, $key:expr]) => {{
282 if $key.query_crate_is_local() {
283 $tcx.queries.local_providers.$name
284 } else {
285 $tcx.queries.extern_providers.$name
286 }
287 }};
288 ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
289 get_provider!([$($modifiers)*][$($args)*])
290 };
291 }
292
293 macro_rules! should_ever_cache_on_disk {
294 ([]$yes:tt $no:tt) => {{
295 $no
296 }};
297 ([(cache) $($rest:tt)*]$yes:tt $no:tt) => {{
298 $yes
299 }};
300 ([$other:tt $($modifiers:tt)*]$yes:tt $no:tt) => {
301 should_ever_cache_on_disk!([$($modifiers)*]$yes $no)
302 };
303 }
304
305 pub(crate) fn create_query_frame<
306 'tcx,
307 K: Copy + Key + for<'a> HashStable<StableHashingContext<'a>>,
308 >(
309 tcx: QueryCtxt<'tcx>,
310 do_describe: fn(TyCtxt<'tcx>, K) -> String,
311 key: K,
312 kind: DepKind,
313 name: &'static str,
314 ) -> QueryStackFrame<DepKind> {
315 // Avoid calling queries while formatting the description
316 let description = ty::print::with_no_queries!(
317 // Disable visible paths printing for performance reasons.
318 // Showing visible path instead of any path is not that important in production.
319 ty::print::with_no_visible_paths!(
320 // Force filename-line mode to avoid invoking `type_of` query.
321 ty::print::with_forced_impl_filename_line!(do_describe(tcx.tcx, key))
322 )
323 );
324 let description =
325 if tcx.sess.verbose() { format!("{description} [{name:?}]") } else { description };
326 let span = if kind == dep_graph::DepKind::def_span {
327 // The `def_span` query is used to calculate `default_span`,
328 // so exit to avoid infinite recursion.
329 None
330 } else {
331 Some(key.default_span(*tcx))
332 };
333 let def_id = key.key_as_def_id();
334 let def_kind = if kind == dep_graph::DepKind::opt_def_kind {
335 // Try to avoid infinite recursion.
336 None
337 } else {
338 def_id.and_then(|def_id| def_id.as_local()).and_then(|def_id| tcx.opt_def_kind(def_id))
339 };
340 let hash = || {
341 tcx.with_stable_hashing_context(|mut hcx| {
342 let mut hasher = StableHasher::new();
343 std::mem::discriminant(&kind).hash_stable(&mut hcx, &mut hasher);
344 key.hash_stable(&mut hcx, &mut hasher);
345 hasher.finish::<u64>()
346 })
347 };
348 let ty_adt_id = key.ty_adt_id();
349
350 QueryStackFrame::new(description, span, def_id, def_kind, kind, ty_adt_id, hash)
351 }
352
353 fn try_load_from_on_disk_cache<'tcx, Q>(tcx: TyCtxt<'tcx>, dep_node: DepNode)
354 where
355 Q: QueryConfig<QueryCtxt<'tcx>>,
356 Q::Key: DepNodeParams<TyCtxt<'tcx>>,
357 {
358 debug_assert!(tcx.dep_graph.is_green(&dep_node));
359
360 let key = Q::Key::recover(tcx, &dep_node).unwrap_or_else(|| {
361 panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash)
362 });
363 if Q::cache_on_disk(tcx, &key) {
364 let _ = Q::execute_query(tcx, key);
365 }
366 }
367
368 pub(crate) fn try_load_from_disk<'tcx, V>(
369 tcx: QueryCtxt<'tcx>,
370 id: SerializedDepNodeIndex,
371 ) -> Option<V>
372 where
373 V: for<'a> Decodable<CacheDecoder<'a, 'tcx>>,
374 {
375 tcx.on_disk_cache().as_ref()?.try_load_query_result(*tcx, id)
376 }
377
378 fn force_from_dep_node<'tcx, Q>(tcx: TyCtxt<'tcx>, dep_node: DepNode) -> bool
379 where
380 Q: QueryConfig<QueryCtxt<'tcx>>,
381 Q::Key: DepNodeParams<TyCtxt<'tcx>>,
382 Q::Value: Value<TyCtxt<'tcx>, DepKind>,
383 {
384 // We must avoid ever having to call `force_from_dep_node()` for a
385 // `DepNode::codegen_unit`:
386 // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we
387 // would always end up having to evaluate the first caller of the
388 // `codegen_unit` query that *is* reconstructible. This might very well be
389 // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just
390 // to re-trigger calling the `codegen_unit` query with the right key. At
391 // that point we would already have re-done all the work we are trying to
392 // avoid doing in the first place.
393 // The solution is simple: Just explicitly call the `codegen_unit` query for
394 // each CGU, right after partitioning. This way `try_mark_green` will always
395 // hit the cache instead of having to go through `force_from_dep_node`.
396 // This assertion makes sure, we actually keep applying the solution above.
397 debug_assert!(
398 dep_node.kind != DepKind::codegen_unit,
399 "calling force_from_dep_node() on DepKind::codegen_unit"
400 );
401
402 if let Some(key) = Q::Key::recover(tcx, &dep_node) {
403 #[cfg(debug_assertions)]
404 let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered();
405 let tcx = QueryCtxt::from_tcx(tcx);
406 force_query::<Q, _, DepKind>(tcx, key, dep_node);
407 true
408 } else {
409 false
410 }
411 }
412
413 pub(crate) fn query_callback<'tcx, Q>(is_anon: bool, is_eval_always: bool) -> DepKindStruct<'tcx>
414 where
415 Q: QueryConfig<QueryCtxt<'tcx>>,
416 Q::Key: DepNodeParams<TyCtxt<'tcx>>,
417 {
418 let fingerprint_style = Q::Key::fingerprint_style();
419
420 if is_anon || !fingerprint_style.reconstructible() {
421 return DepKindStruct {
422 is_anon,
423 is_eval_always,
424 fingerprint_style,
425 force_from_dep_node: None,
426 try_load_from_on_disk_cache: None,
427 };
428 }
429
430 DepKindStruct {
431 is_anon,
432 is_eval_always,
433 fingerprint_style,
434 force_from_dep_node: Some(force_from_dep_node::<Q>),
435 try_load_from_on_disk_cache: Some(try_load_from_on_disk_cache::<Q>),
436 }
437 }
438
439 macro_rules! expand_if_cached {
440 ([], $tokens:expr) => {{
441 None
442 }};
443 ([(cache) $($rest:tt)*], $tokens:expr) => {{
444 Some($tokens)
445 }};
446 ([$other:tt $($modifiers:tt)*], $tokens:expr) => {
447 expand_if_cached!([$($modifiers)*], $tokens)
448 };
449 }
450
451 // NOTE: `$V` isn't used here, but we still need to match on it so it can be passed to other macros
452 // invoked by `rustc_query_append`.
453 macro_rules! define_queries {
454 (
455 $($(#[$attr:meta])*
456 [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => {
457 define_queries_struct! {
458 input: ($(([$($modifiers)*] [$($attr)*] [$name]))*)
459 }
460
461 #[allow(nonstandard_style)]
462 mod queries {
463 use std::marker::PhantomData;
464
465 $(pub struct $name<'tcx> {
466 data: PhantomData<&'tcx ()>
467 })*
468 }
469
470 $(impl<'tcx> QueryConfig<QueryCtxt<'tcx>> for queries::$name<'tcx> {
471 type Key = query_keys::$name<'tcx>;
472 type Value = query_values::$name<'tcx>;
473 const NAME: &'static str = stringify!($name);
474
475 #[inline]
476 fn cache_on_disk(tcx: TyCtxt<'tcx>, key: &Self::Key) -> bool {
477 ::rustc_middle::query::cached::$name(tcx, key)
478 }
479
480 type Cache = query_storage::$name<'tcx>;
481
482 #[inline(always)]
483 fn query_state<'a>(tcx: QueryCtxt<'tcx>) -> &'a QueryState<Self::Key, crate::dep_graph::DepKind>
484 where QueryCtxt<'tcx>: 'a
485 {
486 &tcx.queries.$name
487 }
488
489 #[inline(always)]
490 fn query_cache<'a>(tcx: QueryCtxt<'tcx>) -> &'a Self::Cache
491 where 'tcx:'a
492 {
493 &tcx.query_system.caches.$name
494 }
495
496 fn execute_query(tcx: TyCtxt<'tcx>, key: Self::Key) -> Self::Value {
497 tcx.$name(key)
498 }
499
500 #[inline]
501 #[allow(unused_variables)]
502 fn compute(qcx: QueryCtxt<'tcx>, key: Self::Key) -> Self::Value {
503 query_provided_to_value::$name(
504 qcx.tcx,
505 get_provider!([$($modifiers)*][qcx, $name, key])(qcx.tcx, key)
506 )
507 }
508
509 #[inline]
510 fn try_load_from_disk(_qcx: QueryCtxt<'tcx>, _key: &Self::Key) -> rustc_query_system::query::TryLoadFromDisk<QueryCtxt<'tcx>, Self> {
511 should_ever_cache_on_disk!([$($modifiers)*] {
512 if Self::cache_on_disk(_qcx.tcx, _key) {
513 Some(|qcx: QueryCtxt<'tcx>, dep_node| {
514 let value = $crate::plumbing::try_load_from_disk::<query_provided::$name<'tcx>>(
515 qcx,
516 dep_node
517 );
518 value.map(|value| query_provided_to_value::$name(qcx.tcx, value))
519 })
520 } else {
521 None
522 }
523 } {
524 None
525 })
526 }
527
528 const ANON: bool = is_anon!([$($modifiers)*]);
529 const EVAL_ALWAYS: bool = is_eval_always!([$($modifiers)*]);
530 const DEPTH_LIMIT: bool = depth_limit!([$($modifiers)*]);
531 const FEEDABLE: bool = feedable!([$($modifiers)*]);
532
533 const DEP_KIND: rustc_middle::dep_graph::DepKind = dep_graph::DepKind::$name;
534 const HANDLE_CYCLE_ERROR: rustc_query_system::HandleCycleError = handle_cycle_error!([$($modifiers)*]);
535
536 const HASH_RESULT: rustc_query_system::query::HashResult<QueryCtxt<'tcx>, Self> = hash_result!([$($modifiers)*]);
537 })*
538
539 #[allow(nonstandard_style)]
540 mod query_callbacks {
541 use super::*;
542 use rustc_query_system::dep_graph::FingerprintStyle;
543
544 // We use this for most things when incr. comp. is turned off.
545 pub fn Null<'tcx>() -> DepKindStruct<'tcx> {
546 DepKindStruct {
547 is_anon: false,
548 is_eval_always: false,
549 fingerprint_style: FingerprintStyle::Unit,
550 force_from_dep_node: Some(|_, dep_node| bug!("force_from_dep_node: encountered {:?}", dep_node)),
551 try_load_from_on_disk_cache: None,
552 }
553 }
554
555 // We use this for the forever-red node.
556 pub fn Red<'tcx>() -> DepKindStruct<'tcx> {
557 DepKindStruct {
558 is_anon: false,
559 is_eval_always: false,
560 fingerprint_style: FingerprintStyle::Unit,
561 force_from_dep_node: Some(|_, dep_node| bug!("force_from_dep_node: encountered {:?}", dep_node)),
562 try_load_from_on_disk_cache: None,
563 }
564 }
565
566 pub fn TraitSelect<'tcx>() -> DepKindStruct<'tcx> {
567 DepKindStruct {
568 is_anon: true,
569 is_eval_always: false,
570 fingerprint_style: FingerprintStyle::Unit,
571 force_from_dep_node: None,
572 try_load_from_on_disk_cache: None,
573 }
574 }
575
576 pub fn CompileCodegenUnit<'tcx>() -> DepKindStruct<'tcx> {
577 DepKindStruct {
578 is_anon: false,
579 is_eval_always: false,
580 fingerprint_style: FingerprintStyle::Opaque,
581 force_from_dep_node: None,
582 try_load_from_on_disk_cache: None,
583 }
584 }
585
586 pub fn CompileMonoItem<'tcx>() -> DepKindStruct<'tcx> {
587 DepKindStruct {
588 is_anon: false,
589 is_eval_always: false,
590 fingerprint_style: FingerprintStyle::Opaque,
591 force_from_dep_node: None,
592 try_load_from_on_disk_cache: None,
593 }
594 }
595
596 $(pub(crate) fn $name<'tcx>()-> DepKindStruct<'tcx> {
597 $crate::plumbing::query_callback::<queries::$name<'tcx>>(
598 is_anon!([$($modifiers)*]),
599 is_eval_always!([$($modifiers)*]),
600 )
601 })*
602 }
603
604 mod query_structs {
605 use rustc_middle::ty::TyCtxt;
606 use $crate::plumbing::{QueryStruct, QueryCtxt};
607 use $crate::profiling_support::QueryKeyStringCache;
608 use rustc_query_system::query::QueryMap;
609 use rustc_middle::dep_graph::DepKind;
610
611 pub(super) const fn dummy_query_struct<'tcx>() -> QueryStruct<'tcx> {
612 fn noop_try_collect_active_jobs(_: QueryCtxt<'_>, _: &mut QueryMap<DepKind>) -> Option<()> {
613 None
614 }
615 fn noop_alloc_self_profile_query_strings(_: TyCtxt<'_>, _: &mut QueryKeyStringCache) {}
616
617 QueryStruct {
618 try_collect_active_jobs: noop_try_collect_active_jobs,
619 alloc_self_profile_query_strings: noop_alloc_self_profile_query_strings,
620 encode_query_results: None,
621 }
622 }
623
624 pub(super) use dummy_query_struct as Null;
625 pub(super) use dummy_query_struct as Red;
626 pub(super) use dummy_query_struct as TraitSelect;
627 pub(super) use dummy_query_struct as CompileCodegenUnit;
628 pub(super) use dummy_query_struct as CompileMonoItem;
629
630 $(
631 pub(super) const fn $name<'tcx>() -> QueryStruct<'tcx> { QueryStruct {
632 try_collect_active_jobs: |tcx, qmap| {
633 let make_query = |tcx, key| {
634 let kind = rustc_middle::dep_graph::DepKind::$name;
635 let name = stringify!($name);
636 $crate::plumbing::create_query_frame(tcx, rustc_middle::query::descs::$name, key, kind, name)
637 };
638 tcx.queries.$name.try_collect_active_jobs(
639 tcx,
640 make_query,
641 qmap,
642 )
643 },
644 alloc_self_profile_query_strings: |tcx, string_cache| {
645 $crate::profiling_support::alloc_self_profile_query_strings_for_query_cache(
646 tcx,
647 stringify!($name),
648 &tcx.query_system.caches.$name,
649 string_cache,
650 )
651 },
652 encode_query_results: expand_if_cached!([$($modifiers)*], |tcx, encoder, query_result_index|
653 $crate::on_disk_cache::encode_query_results::<_, super::queries::$name<'_>>(tcx, encoder, query_result_index)
654 ),
655 }})*
656 }
657
658 pub fn query_callbacks<'tcx>(arena: &'tcx Arena<'tcx>) -> &'tcx [DepKindStruct<'tcx>] {
659 arena.alloc_from_iter(make_dep_kind_array!(query_callbacks))
660 }
661 }
662 }
663
664 use crate::{ExternProviders, OnDiskCache, Providers};
665
666 impl<'tcx> Queries<'tcx> {
667 pub fn new(
668 local_providers: Providers,
669 extern_providers: ExternProviders,
670 on_disk_cache: Option<OnDiskCache<'tcx>>,
671 ) -> Self {
672 use crate::query_structs;
673 Queries {
674 local_providers: Box::new(local_providers),
675 extern_providers: Box::new(extern_providers),
676 query_structs: make_dep_kind_array!(query_structs).to_vec(),
677 on_disk_cache,
678 jobs: AtomicU64::new(1),
679 ..Queries::default()
680 }
681 }
682 }
683
684 macro_rules! define_queries_struct {
685 (
686 input: ($(([$($modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => {
687 #[derive(Default)]
688 pub struct Queries<'tcx> {
689 local_providers: Box<Providers>,
690 extern_providers: Box<ExternProviders>,
691 query_structs: Vec<$crate::plumbing::QueryStruct<'tcx>>,
692 pub on_disk_cache: Option<OnDiskCache<'tcx>>,
693 jobs: AtomicU64,
694
695 $(
696 $(#[$attr])*
697 $name: QueryState<
698 <queries::$name<'tcx> as QueryConfig<QueryCtxt<'tcx>>>::Key,
699 rustc_middle::dep_graph::DepKind,
700 >,
701 )*
702 }
703
704 impl<'tcx> Queries<'tcx> {
705 pub(crate) fn try_collect_active_jobs(
706 &'tcx self,
707 tcx: TyCtxt<'tcx>,
708 ) -> Option<QueryMap<rustc_middle::dep_graph::DepKind>> {
709 let tcx = QueryCtxt { tcx, queries: self };
710 let mut jobs = QueryMap::default();
711
712 for query in &self.query_structs {
713 (query.try_collect_active_jobs)(tcx, &mut jobs);
714 }
715
716 Some(jobs)
717 }
718 }
719
720 impl<'tcx> QueryEngine<'tcx> for Queries<'tcx> {
721 fn as_any(&'tcx self) -> &'tcx dyn std::any::Any {
722 let this = unsafe { std::mem::transmute::<&Queries<'_>, &Queries<'_>>(self) };
723 this as _
724 }
725
726 fn try_mark_green(&'tcx self, tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool {
727 let qcx = QueryCtxt { tcx, queries: self };
728 tcx.dep_graph.try_mark_green(qcx, dep_node).is_some()
729 }
730
731 $($(#[$attr])*
732 #[inline(always)]
733 #[tracing::instrument(level = "trace", skip(self, tcx), ret)]
734 fn $name(
735 &'tcx self,
736 tcx: TyCtxt<'tcx>,
737 span: Span,
738 key: <queries::$name<'tcx> as QueryConfig<QueryCtxt<'tcx>>>::Key,
739 mode: QueryMode,
740 ) -> Option<query_values::$name<'tcx>> {
741 let qcx = QueryCtxt { tcx, queries: self };
742 get_query::<queries::$name<'tcx>, _, rustc_middle::dep_graph::DepKind>(qcx, span, key, mode)
743 })*
744 }
745 };
746 }