]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_query_system/src/query/plumbing.rs
Rollup merge of #92586 - esp-rs:bugfix/allocation-alignment-espidf, r=yaahc
[rust.git] / compiler / rustc_query_system / src / query / 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::dep_graph::{DepContext, DepNode, DepNodeIndex, DepNodeParams};
6 use crate::query::caches::QueryCache;
7 use crate::query::config::{QueryDescription, QueryVtable};
8 use crate::query::job::{
9     report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryShardJobId,
10 };
11 use crate::query::{QueryContext, QueryMap, QuerySideEffects, QueryStackFrame};
12 use rustc_data_structures::fingerprint::Fingerprint;
13 use rustc_data_structures::fx::{FxHashMap, FxHasher};
14 #[cfg(parallel_compiler)]
15 use rustc_data_structures::profiling::TimingGuard;
16 use rustc_data_structures::sharded::{get_shard_index_by_hash, Sharded};
17 use rustc_data_structures::sync::{Lock, LockGuard};
18 use rustc_data_structures::thin_vec::ThinVec;
19 use rustc_errors::{DiagnosticBuilder, FatalError};
20 use rustc_session::Session;
21 use rustc_span::{Span, DUMMY_SP};
22 use std::cell::Cell;
23 use std::collections::hash_map::Entry;
24 use std::fmt::Debug;
25 use std::hash::{Hash, Hasher};
26 use std::mem;
27 use std::num::NonZeroU32;
28 use std::ptr;
29
30 pub struct QueryCacheStore<C: QueryCache> {
31     cache: C,
32     shards: Sharded<C::Sharded>,
33 }
34
35 impl<C: QueryCache + Default> Default for QueryCacheStore<C> {
36     fn default() -> Self {
37         Self { cache: C::default(), shards: Default::default() }
38     }
39 }
40
41 /// Values used when checking a query cache which can be reused on a cache-miss to execute the query.
42 pub struct QueryLookup {
43     pub(super) key_hash: u64,
44     shard: usize,
45 }
46
47 // We compute the key's hash once and then use it for both the
48 // shard lookup and the hashmap lookup. This relies on the fact
49 // that both of them use `FxHasher`.
50 fn hash_for_shard<K: Hash>(key: &K) -> u64 {
51     let mut hasher = FxHasher::default();
52     key.hash(&mut hasher);
53     hasher.finish()
54 }
55
56 impl<C: QueryCache> QueryCacheStore<C> {
57     pub(super) fn get_lookup<'tcx>(
58         &'tcx self,
59         key: &C::Key,
60     ) -> (QueryLookup, LockGuard<'tcx, C::Sharded>) {
61         let key_hash = hash_for_shard(key);
62         let shard = get_shard_index_by_hash(key_hash);
63         let lock = self.shards.get_shard_by_index(shard).lock();
64         (QueryLookup { key_hash, shard }, lock)
65     }
66
67     pub fn iter_results(&self, f: &mut dyn FnMut(&C::Key, &C::Value, DepNodeIndex)) {
68         self.cache.iter(&self.shards, f)
69     }
70 }
71
72 struct QueryStateShard<D, K> {
73     active: FxHashMap<K, QueryResult<D>>,
74
75     /// Used to generate unique ids for active jobs.
76     jobs: u32,
77 }
78
79 impl<D, K> Default for QueryStateShard<D, K> {
80     fn default() -> QueryStateShard<D, K> {
81         QueryStateShard { active: Default::default(), jobs: 0 }
82     }
83 }
84
85 pub struct QueryState<D, K> {
86     shards: Sharded<QueryStateShard<D, K>>,
87 }
88
89 /// Indicates the state of a query for a given key in a query map.
90 enum QueryResult<D> {
91     /// An already executing query. The query job can be used to await for its completion.
92     Started(QueryJob<D>),
93
94     /// The query panicked. Queries trying to wait on this will raise a fatal error which will
95     /// silently panic.
96     Poisoned,
97 }
98
99 impl<D, K> QueryState<D, K>
100 where
101     D: Copy + Clone + Eq + Hash,
102     K: Eq + Hash + Clone + Debug,
103 {
104     pub fn all_inactive(&self) -> bool {
105         let shards = self.shards.lock_shards();
106         shards.iter().all(|shard| shard.active.is_empty())
107     }
108
109     pub fn try_collect_active_jobs<CTX: Copy>(
110         &self,
111         tcx: CTX,
112         kind: D,
113         make_query: fn(CTX, K) -> QueryStackFrame,
114         jobs: &mut QueryMap<D>,
115     ) -> Option<()> {
116         // We use try_lock_shards here since we are called from the
117         // deadlock handler, and this shouldn't be locked.
118         let shards = self.shards.try_lock_shards()?;
119         for (shard_id, shard) in shards.iter().enumerate() {
120             for (k, v) in shard.active.iter() {
121                 if let QueryResult::Started(ref job) = *v {
122                     let id = QueryJobId::new(job.id, shard_id, kind);
123                     let query = make_query(tcx, k.clone());
124                     jobs.insert(id, QueryJobInfo { query, job: job.clone() });
125                 }
126             }
127         }
128
129         Some(())
130     }
131 }
132
133 impl<D, K> Default for QueryState<D, K> {
134     fn default() -> QueryState<D, K> {
135         QueryState { shards: Default::default() }
136     }
137 }
138
139 /// A type representing the responsibility to execute the job in the `job` field.
140 /// This will poison the relevant query if dropped.
141 struct JobOwner<'tcx, D, K>
142 where
143     D: Copy + Clone + Eq + Hash,
144     K: Eq + Hash + Clone,
145 {
146     state: &'tcx QueryState<D, K>,
147     key: K,
148     id: QueryJobId<D>,
149 }
150
151 #[cold]
152 #[inline(never)]
153 fn mk_cycle<CTX, V, R>(
154     tcx: CTX,
155     error: CycleError,
156     handle_cycle_error: fn(CTX, DiagnosticBuilder<'_>) -> V,
157     cache: &dyn crate::query::QueryStorage<Value = V, Stored = R>,
158 ) -> R
159 where
160     CTX: QueryContext,
161     V: std::fmt::Debug,
162     R: Clone,
163 {
164     let error = report_cycle(tcx.dep_context().sess(), error);
165     let value = handle_cycle_error(tcx, error);
166     cache.store_nocache(value)
167 }
168
169 impl<'tcx, D, K> JobOwner<'tcx, D, K>
170 where
171     D: Copy + Clone + Eq + Hash,
172     K: Eq + Hash + Clone,
173 {
174     /// Either gets a `JobOwner` corresponding the query, allowing us to
175     /// start executing the query, or returns with the result of the query.
176     /// This function assumes that `try_get_cached` is already called and returned `lookup`.
177     /// If the query is executing elsewhere, this will wait for it and return the result.
178     /// If the query panicked, this will silently panic.
179     ///
180     /// This function is inlined because that results in a noticeable speed-up
181     /// for some compile-time benchmarks.
182     #[inline(always)]
183     fn try_start<'b, CTX>(
184         tcx: &'b CTX,
185         state: &'b QueryState<CTX::DepKind, K>,
186         span: Span,
187         key: K,
188         lookup: QueryLookup,
189         dep_kind: CTX::DepKind,
190     ) -> TryGetJob<'b, CTX::DepKind, K>
191     where
192         CTX: QueryContext,
193     {
194         let shard = lookup.shard;
195         let mut state_lock = state.shards.get_shard_by_index(shard).lock();
196         let lock = &mut *state_lock;
197
198         match lock.active.entry(key) {
199             Entry::Vacant(entry) => {
200                 // Generate an id unique within this shard.
201                 let id = lock.jobs.checked_add(1).unwrap();
202                 lock.jobs = id;
203                 let id = QueryShardJobId(NonZeroU32::new(id).unwrap());
204
205                 let job = tcx.current_query_job();
206                 let job = QueryJob::new(id, span, job);
207
208                 let key = entry.key().clone();
209                 entry.insert(QueryResult::Started(job));
210
211                 let global_id = QueryJobId::new(id, shard, dep_kind);
212                 let owner = JobOwner { state, id: global_id, key };
213                 return TryGetJob::NotYetStarted(owner);
214             }
215             Entry::Occupied(mut entry) => {
216                 match entry.get_mut() {
217                     #[cfg(not(parallel_compiler))]
218                     QueryResult::Started(job) => {
219                         let id = QueryJobId::new(job.id, shard, dep_kind);
220
221                         drop(state_lock);
222
223                         // If we are single-threaded we know that we have cycle error,
224                         // so we just return the error.
225                         return TryGetJob::Cycle(id.find_cycle_in_stack(
226                             tcx.try_collect_active_jobs().unwrap(),
227                             &tcx.current_query_job(),
228                             span,
229                         ));
230                     }
231                     #[cfg(parallel_compiler)]
232                     QueryResult::Started(job) => {
233                         // For parallel queries, we'll block and wait until the query running
234                         // in another thread has completed. Record how long we wait in the
235                         // self-profiler.
236                         let query_blocked_prof_timer = tcx.dep_context().profiler().query_blocked();
237
238                         // Get the latch out
239                         let latch = job.latch();
240
241                         drop(state_lock);
242
243                         // With parallel queries we might just have to wait on some other
244                         // thread.
245                         let result = latch.wait_on(tcx.current_query_job(), span);
246
247                         match result {
248                             Ok(()) => TryGetJob::JobCompleted(query_blocked_prof_timer),
249                             Err(cycle) => TryGetJob::Cycle(cycle),
250                         }
251                     }
252                     QueryResult::Poisoned => FatalError.raise(),
253                 }
254             }
255         }
256     }
257
258     /// Completes the query by updating the query cache with the `result`,
259     /// signals the waiter and forgets the JobOwner, so it won't poison the query
260     fn complete<C>(
261         self,
262         cache: &QueryCacheStore<C>,
263         result: C::Value,
264         dep_node_index: DepNodeIndex,
265     ) -> C::Stored
266     where
267         C: QueryCache<Key = K>,
268     {
269         // We can move out of `self` here because we `mem::forget` it below
270         let key = unsafe { ptr::read(&self.key) };
271         let state = self.state;
272
273         // Forget ourself so our destructor won't poison the query
274         mem::forget(self);
275
276         let (job, result) = {
277             let key_hash = hash_for_shard(&key);
278             let shard = get_shard_index_by_hash(key_hash);
279             let job = {
280                 let mut lock = state.shards.get_shard_by_index(shard).lock();
281                 match lock.active.remove(&key).unwrap() {
282                     QueryResult::Started(job) => job,
283                     QueryResult::Poisoned => panic!(),
284                 }
285             };
286             let result = {
287                 let mut lock = cache.shards.get_shard_by_index(shard).lock();
288                 cache.cache.complete(&mut lock, key, result, dep_node_index)
289             };
290             (job, result)
291         };
292
293         job.signal_complete();
294         result
295     }
296 }
297
298 impl<'tcx, D, K> Drop for JobOwner<'tcx, D, K>
299 where
300     D: Copy + Clone + Eq + Hash,
301     K: Eq + Hash + Clone,
302 {
303     #[inline(never)]
304     #[cold]
305     fn drop(&mut self) {
306         // Poison the query so jobs waiting on it panic.
307         let state = self.state;
308         let shard = state.shards.get_shard_by_value(&self.key);
309         let job = {
310             let mut shard = shard.lock();
311             let job = match shard.active.remove(&self.key).unwrap() {
312                 QueryResult::Started(job) => job,
313                 QueryResult::Poisoned => panic!(),
314             };
315             shard.active.insert(self.key.clone(), QueryResult::Poisoned);
316             job
317         };
318         // Also signal the completion of the job, so waiters
319         // will continue execution.
320         job.signal_complete();
321     }
322 }
323
324 #[derive(Clone)]
325 pub(crate) struct CycleError {
326     /// The query and related span that uses the cycle.
327     pub usage: Option<(Span, QueryStackFrame)>,
328     pub cycle: Vec<QueryInfo>,
329 }
330
331 /// The result of `try_start`.
332 enum TryGetJob<'tcx, D, K>
333 where
334     D: Copy + Clone + Eq + Hash,
335     K: Eq + Hash + Clone,
336 {
337     /// The query is not yet started. Contains a guard to the cache eventually used to start it.
338     NotYetStarted(JobOwner<'tcx, D, K>),
339
340     /// The query was already completed.
341     /// Returns the result of the query and its dep-node index
342     /// if it succeeded or a cycle error if it failed.
343     #[cfg(parallel_compiler)]
344     JobCompleted(TimingGuard<'tcx>),
345
346     /// Trying to execute the query resulted in a cycle.
347     Cycle(CycleError),
348 }
349
350 /// Checks if the query is already computed and in the cache.
351 /// It returns the shard index and a lock guard to the shard,
352 /// which will be used if the query is not in the cache and we need
353 /// to compute it.
354 #[inline]
355 pub fn try_get_cached<'a, CTX, C, R, OnHit>(
356     tcx: CTX,
357     cache: &'a QueryCacheStore<C>,
358     key: &C::Key,
359     // `on_hit` can be called while holding a lock to the query cache
360     on_hit: OnHit,
361 ) -> Result<R, QueryLookup>
362 where
363     C: QueryCache,
364     CTX: DepContext,
365     OnHit: FnOnce(&C::Stored) -> R,
366 {
367     cache.cache.lookup(cache, &key, |value, index| {
368         if unlikely!(tcx.profiler().enabled()) {
369             tcx.profiler().query_cache_hit(index.into());
370         }
371         tcx.dep_graph().read_index(index);
372         on_hit(value)
373     })
374 }
375
376 fn try_execute_query<CTX, C>(
377     tcx: CTX,
378     state: &QueryState<CTX::DepKind, C::Key>,
379     cache: &QueryCacheStore<C>,
380     span: Span,
381     key: C::Key,
382     lookup: QueryLookup,
383     dep_node: Option<DepNode<CTX::DepKind>>,
384     query: &QueryVtable<CTX, C::Key, C::Value>,
385 ) -> (C::Stored, Option<DepNodeIndex>)
386 where
387     C: QueryCache,
388     C::Key: Clone + DepNodeParams<CTX::DepContext>,
389     CTX: QueryContext,
390 {
391     match JobOwner::<'_, CTX::DepKind, C::Key>::try_start(
392         &tcx,
393         state,
394         span,
395         key.clone(),
396         lookup,
397         query.dep_kind,
398     ) {
399         TryGetJob::NotYetStarted(job) => {
400             let (result, dep_node_index) = execute_job(tcx, key, dep_node, query, job.id);
401             let result = job.complete(cache, result, dep_node_index);
402             (result, Some(dep_node_index))
403         }
404         TryGetJob::Cycle(error) => {
405             let result = mk_cycle(tcx, error, query.handle_cycle_error, &cache.cache);
406             (result, None)
407         }
408         #[cfg(parallel_compiler)]
409         TryGetJob::JobCompleted(query_blocked_prof_timer) => {
410             let (v, index) = cache
411                 .cache
412                 .lookup(cache, &key, |value, index| (value.clone(), index))
413                 .unwrap_or_else(|_| panic!("value must be in cache after waiting"));
414
415             if unlikely!(tcx.dep_context().profiler().enabled()) {
416                 tcx.dep_context().profiler().query_cache_hit(index.into());
417             }
418             query_blocked_prof_timer.finish_with_query_invocation_id(index.into());
419
420             (v, Some(index))
421         }
422     }
423 }
424
425 fn execute_job<CTX, K, V>(
426     tcx: CTX,
427     key: K,
428     mut dep_node_opt: Option<DepNode<CTX::DepKind>>,
429     query: &QueryVtable<CTX, K, V>,
430     job_id: QueryJobId<CTX::DepKind>,
431 ) -> (V, DepNodeIndex)
432 where
433     K: Clone + DepNodeParams<CTX::DepContext>,
434     V: Debug,
435     CTX: QueryContext,
436 {
437     let dep_graph = tcx.dep_context().dep_graph();
438
439     // Fast path for when incr. comp. is off.
440     if !dep_graph.is_fully_enabled() {
441         let prof_timer = tcx.dep_context().profiler().query_provider();
442         let result = tcx.start_query(job_id, None, || query.compute(*tcx.dep_context(), key));
443         let dep_node_index = dep_graph.next_virtual_depnode_index();
444         prof_timer.finish_with_query_invocation_id(dep_node_index.into());
445         return (result, dep_node_index);
446     }
447
448     if !query.anon && !query.eval_always {
449         // `to_dep_node` is expensive for some `DepKind`s.
450         let dep_node =
451             dep_node_opt.get_or_insert_with(|| query.to_dep_node(*tcx.dep_context(), &key));
452
453         // The diagnostics for this query will be promoted to the current session during
454         // `try_mark_green()`, so we can ignore them here.
455         if let Some(ret) = tcx.start_query(job_id, None, || {
456             try_load_from_disk_and_cache_in_memory(tcx, &key, &dep_node, query)
457         }) {
458             return ret;
459         }
460     }
461
462     let prof_timer = tcx.dep_context().profiler().query_provider();
463     let diagnostics = Lock::new(ThinVec::new());
464
465     let (result, dep_node_index) = tcx.start_query(job_id, Some(&diagnostics), || {
466         if query.anon {
467             return dep_graph.with_anon_task(*tcx.dep_context(), query.dep_kind, || {
468                 query.compute(*tcx.dep_context(), key)
469             });
470         }
471
472         // `to_dep_node` is expensive for some `DepKind`s.
473         let dep_node = dep_node_opt.unwrap_or_else(|| query.to_dep_node(*tcx.dep_context(), &key));
474
475         dep_graph.with_task(dep_node, *tcx.dep_context(), key, query.compute, query.hash_result)
476     });
477
478     prof_timer.finish_with_query_invocation_id(dep_node_index.into());
479
480     let diagnostics = diagnostics.into_inner();
481     let side_effects = QuerySideEffects { diagnostics };
482
483     if unlikely!(!side_effects.is_empty()) {
484         if query.anon {
485             tcx.store_side_effects_for_anon_node(dep_node_index, side_effects);
486         } else {
487             tcx.store_side_effects(dep_node_index, side_effects);
488         }
489     }
490
491     (result, dep_node_index)
492 }
493
494 fn try_load_from_disk_and_cache_in_memory<CTX, K, V>(
495     tcx: CTX,
496     key: &K,
497     dep_node: &DepNode<CTX::DepKind>,
498     query: &QueryVtable<CTX, K, V>,
499 ) -> Option<(V, DepNodeIndex)>
500 where
501     K: Clone,
502     CTX: QueryContext,
503     V: Debug,
504 {
505     // Note this function can be called concurrently from the same query
506     // We must ensure that this is handled correctly.
507
508     let dep_graph = tcx.dep_context().dep_graph();
509     let (prev_dep_node_index, dep_node_index) = dep_graph.try_mark_green(tcx, &dep_node)?;
510
511     debug_assert!(dep_graph.is_green(dep_node));
512
513     // First we try to load the result from the on-disk cache.
514     // Some things are never cached on disk.
515     if query.cache_on_disk {
516         let prof_timer = tcx.dep_context().profiler().incr_cache_loading();
517
518         // The call to `with_query_deserialization` enforces that no new `DepNodes`
519         // are created during deserialization. See the docs of that method for more
520         // details.
521         let result = dep_graph
522             .with_query_deserialization(|| query.try_load_from_disk(tcx, prev_dep_node_index));
523
524         prof_timer.finish_with_query_invocation_id(dep_node_index.into());
525
526         if let Some(result) = result {
527             if unlikely!(tcx.dep_context().sess().opts.debugging_opts.query_dep_graph) {
528                 dep_graph.mark_debug_loaded_from_disk(*dep_node)
529             }
530
531             let prev_fingerprint = tcx
532                 .dep_context()
533                 .dep_graph()
534                 .prev_fingerprint_of(dep_node)
535                 .unwrap_or(Fingerprint::ZERO);
536             // If `-Zincremental-verify-ich` is specified, re-hash results from
537             // the cache and make sure that they have the expected fingerprint.
538             //
539             // If not, we still seek to verify a subset of fingerprints loaded
540             // from disk. Re-hashing results is fairly expensive, so we can't
541             // currently afford to verify every hash. This subset should still
542             // give us some coverage of potential bugs though.
543             let try_verify = prev_fingerprint.as_value().1 % 32 == 0;
544             if unlikely!(
545                 try_verify || tcx.dep_context().sess().opts.debugging_opts.incremental_verify_ich
546             ) {
547                 incremental_verify_ich(*tcx.dep_context(), &result, dep_node, query);
548             }
549
550             return Some((result, dep_node_index));
551         }
552
553         // We always expect to find a cached result for things that
554         // can be forced from `DepNode`.
555         debug_assert!(
556             !tcx.dep_context().fingerprint_style(dep_node.kind).reconstructible(),
557             "missing on-disk cache entry for {:?}",
558             dep_node
559         );
560     }
561
562     // We could not load a result from the on-disk cache, so
563     // recompute.
564     let prof_timer = tcx.dep_context().profiler().query_provider();
565
566     // The dep-graph for this computation is already in-place.
567     let result = dep_graph.with_ignore(|| query.compute(*tcx.dep_context(), key.clone()));
568
569     prof_timer.finish_with_query_invocation_id(dep_node_index.into());
570
571     // Verify that re-running the query produced a result with the expected hash
572     // This catches bugs in query implementations, turning them into ICEs.
573     // For example, a query might sort its result by `DefId` - since `DefId`s are
574     // not stable across compilation sessions, the result could get up getting sorted
575     // in a different order when the query is re-run, even though all of the inputs
576     // (e.g. `DefPathHash` values) were green.
577     //
578     // See issue #82920 for an example of a miscompilation that would get turned into
579     // an ICE by this check
580     incremental_verify_ich(*tcx.dep_context(), &result, dep_node, query);
581
582     Some((result, dep_node_index))
583 }
584
585 fn incremental_verify_ich<CTX, K, V: Debug>(
586     tcx: CTX::DepContext,
587     result: &V,
588     dep_node: &DepNode<CTX::DepKind>,
589     query: &QueryVtable<CTX, K, V>,
590 ) where
591     CTX: QueryContext,
592 {
593     assert!(
594         tcx.dep_graph().is_green(dep_node),
595         "fingerprint for green query instance not loaded from cache: {:?}",
596         dep_node,
597     );
598
599     debug!("BEGIN verify_ich({:?})", dep_node);
600     let new_hash = query.hash_result.map_or(Fingerprint::ZERO, |f| {
601         let mut hcx = tcx.create_stable_hashing_context();
602         f(&mut hcx, result)
603     });
604     let old_hash = tcx.dep_graph().prev_fingerprint_of(dep_node);
605     debug!("END verify_ich({:?})", dep_node);
606
607     if Some(new_hash) != old_hash {
608         incremental_verify_ich_cold(tcx.sess(), DebugArg::from(&dep_node), DebugArg::from(&result));
609     }
610 }
611
612 // This DebugArg business is largely a mirror of std::fmt::ArgumentV1, which is
613 // currently not exposed publicly.
614 //
615 // The PR which added this attempted to use `&dyn Debug` instead, but that
616 // showed statistically significant worse compiler performance. It's not
617 // actually clear what the cause there was -- the code should be cold. If this
618 // can be replaced with `&dyn Debug` with on perf impact, then it probably
619 // should be.
620 extern "C" {
621     type Opaque;
622 }
623
624 struct DebugArg<'a> {
625     value: &'a Opaque,
626     fmt: fn(&Opaque, &mut std::fmt::Formatter<'_>) -> std::fmt::Result,
627 }
628
629 impl<'a, T> From<&'a T> for DebugArg<'a>
630 where
631     T: std::fmt::Debug,
632 {
633     fn from(value: &'a T) -> DebugArg<'a> {
634         DebugArg {
635             value: unsafe { std::mem::transmute(value) },
636             fmt: unsafe {
637                 std::mem::transmute(<T as std::fmt::Debug>::fmt as fn(_, _) -> std::fmt::Result)
638             },
639         }
640     }
641 }
642
643 impl std::fmt::Debug for DebugArg<'_> {
644     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
645         (self.fmt)(self.value, f)
646     }
647 }
648
649 // Note that this is marked #[cold] and intentionally takes the equivalent of
650 // `dyn Debug` for its arguments, as we want to avoid generating a bunch of
651 // different implementations for LLVM to chew on (and filling up the final
652 // binary, too).
653 #[cold]
654 fn incremental_verify_ich_cold(sess: &Session, dep_node: DebugArg<'_>, result: DebugArg<'_>) {
655     let run_cmd = if let Some(crate_name) = &sess.opts.crate_name {
656         format!("`cargo clean -p {}` or `cargo clean`", crate_name)
657     } else {
658         "`cargo clean`".to_string()
659     };
660
661     // When we emit an error message and panic, we try to debug-print the `DepNode`
662     // and query result. Unfortunately, this can cause us to run additional queries,
663     // which may result in another fingerprint mismatch while we're in the middle
664     // of processing this one. To avoid a double-panic (which kills the process
665     // before we can print out the query static), we print out a terse
666     // but 'safe' message if we detect a re-entrant call to this method.
667     thread_local! {
668         static INSIDE_VERIFY_PANIC: Cell<bool> = const { Cell::new(false) };
669     };
670
671     let old_in_panic = INSIDE_VERIFY_PANIC.with(|in_panic| in_panic.replace(true));
672
673     if old_in_panic {
674         sess.struct_err(
675             "internal compiler error: re-entrant incremental verify failure, suppressing message",
676         )
677         .emit();
678     } else {
679         sess.struct_err(&format!("internal compiler error: encountered incremental compilation error with {:?}", dep_node))
680                 .help(&format!("This is a known issue with the compiler. Run {} to allow your project to compile", run_cmd))
681                 .note(&"Please follow the instructions below to create a bug report with the provided information")
682                 .note(&"See <https://github.com/rust-lang/rust/issues/84970> for more information")
683                 .emit();
684         panic!("Found unstable fingerprints for {:?}: {:?}", dep_node, result);
685     }
686
687     INSIDE_VERIFY_PANIC.with(|in_panic| in_panic.set(old_in_panic));
688 }
689
690 /// Ensure that either this query has all green inputs or been executed.
691 /// Executing `query::ensure(D)` is considered a read of the dep-node `D`.
692 /// Returns true if the query should still run.
693 ///
694 /// This function is particularly useful when executing passes for their
695 /// side-effects -- e.g., in order to report errors for erroneous programs.
696 ///
697 /// Note: The optimization is only available during incr. comp.
698 #[inline(never)]
699 fn ensure_must_run<CTX, K, V>(
700     tcx: CTX,
701     key: &K,
702     query: &QueryVtable<CTX, K, V>,
703 ) -> (bool, Option<DepNode<CTX::DepKind>>)
704 where
705     K: crate::dep_graph::DepNodeParams<CTX::DepContext>,
706     CTX: QueryContext,
707 {
708     if query.eval_always {
709         return (true, None);
710     }
711
712     // Ensuring an anonymous query makes no sense
713     assert!(!query.anon);
714
715     let dep_node = query.to_dep_node(*tcx.dep_context(), key);
716
717     let dep_graph = tcx.dep_context().dep_graph();
718     match dep_graph.try_mark_green(tcx, &dep_node) {
719         None => {
720             // A None return from `try_mark_green` means that this is either
721             // a new dep node or that the dep node has already been marked red.
722             // Either way, we can't call `dep_graph.read()` as we don't have the
723             // DepNodeIndex. We must invoke the query itself. The performance cost
724             // this introduces should be negligible as we'll immediately hit the
725             // in-memory cache, or another query down the line will.
726             (true, Some(dep_node))
727         }
728         Some((_, dep_node_index)) => {
729             dep_graph.read_index(dep_node_index);
730             tcx.dep_context().profiler().query_cache_hit(dep_node_index.into());
731             (false, None)
732         }
733     }
734 }
735
736 pub enum QueryMode {
737     Get,
738     Ensure,
739 }
740
741 pub fn get_query<Q, CTX>(
742     tcx: CTX,
743     span: Span,
744     key: Q::Key,
745     lookup: QueryLookup,
746     mode: QueryMode,
747 ) -> Option<Q::Stored>
748 where
749     Q: QueryDescription<CTX>,
750     Q::Key: DepNodeParams<CTX::DepContext>,
751     CTX: QueryContext,
752 {
753     let query = Q::make_vtable(tcx, &key);
754     let dep_node = if let QueryMode::Ensure = mode {
755         let (must_run, dep_node) = ensure_must_run(tcx, &key, &query);
756         if !must_run {
757             return None;
758         }
759         dep_node
760     } else {
761         None
762     };
763
764     debug!("ty::query::get_query<{}>(key={:?}, span={:?})", Q::NAME, key, span);
765     let (result, dep_node_index) = try_execute_query(
766         tcx,
767         Q::query_state(tcx),
768         Q::query_cache(tcx),
769         span,
770         key,
771         lookup,
772         dep_node,
773         &query,
774     );
775     if let Some(dep_node_index) = dep_node_index {
776         tcx.dep_context().dep_graph().read_index(dep_node_index)
777     }
778     Some(result)
779 }
780
781 pub fn force_query<Q, CTX>(tcx: CTX, key: Q::Key, dep_node: DepNode<CTX::DepKind>)
782 where
783     Q: QueryDescription<CTX>,
784     Q::Key: DepNodeParams<CTX::DepContext>,
785     CTX: QueryContext,
786 {
787     // We may be concurrently trying both execute and force a query.
788     // Ensure that only one of them runs the query.
789     let cache = Q::query_cache(tcx);
790     let cached = cache.cache.lookup(cache, &key, |_, index| {
791         if unlikely!(tcx.dep_context().profiler().enabled()) {
792             tcx.dep_context().profiler().query_cache_hit(index.into());
793         }
794     });
795
796     let lookup = match cached {
797         Ok(()) => return,
798         Err(lookup) => lookup,
799     };
800
801     let query = Q::make_vtable(tcx, &key);
802     let state = Q::query_state(tcx);
803     debug_assert!(!query.anon);
804
805     try_execute_query(tcx, state, cache, DUMMY_SP, key, lookup, Some(dep_node), &query);
806 }