1use rustc_span::bug;
23macro_rules!maybe_into_query_key {
4 (DefId) => { impl $crate::query::IntoQueryKey<DefId> };
5 (LocalDefId) => { impl $crate::query::IntoQueryKey<LocalDefId> };
6 ($K:ty) => { $K };
7}
89macro_rules!define_query_api {
10 (
11// You might expect the key to be `$K:ty`, but it needs to be `$($K:tt)*` so that
12 // `maybe_into_query_key!` can match on specific type names.
13queries {
14 $(
15 $(#[$attr:meta])*
16fn $name:ident($($K:tt)*) -> $V:ty
17 {
18// Search for (QMODLIST) to find all occurrences of this query modifier list.
19arena_cache: $arena_cache:literal,
20 cache_on_disk: $cache_on_disk:literal,
21 depth_limit: $depth_limit:literal,
22 desc: $desc:expr,
23 eval_always: $eval_always:literal,
24 feedable: $feedable:literal,
25 handle_cycle_error: $handle_cycle_error:literal,
26 no_force: $no_force:literal,
27 no_hash: $no_hash:literal,
28 returns_error_guaranteed: $returns_error_guaranteed:literal,
29 separate_provide_extern: $separate_provide_extern:literal,
30 }
31 )*
32 }
33// Non-queries are unused here.
34non_queries { $($_:tt)* }
35 ) => {
36 $(
37pub mod $name {
38use super::*;
39use $crate::query::erase::{self, Erased};
4041pub type Key<'tcx> = $($K)*;
42pub type Value<'tcx> = $V;
4344/// Key type used by provider functions in `local_providers`.
45 /// This query has the `separate_provide_extern` modifier.
46#[cfg($separate_provide_extern)]
47pub type LocalKey<'tcx> =
48 <Key<'tcx> as $crate::query::QueryKey>::LocalQueryKey;
49/// Key type used by provider functions in `local_providers`.
50#[cfg(not($separate_provide_extern))]
51pub type LocalKey<'tcx> = Key<'tcx>;
5253/// Type returned from query providers and loaded from disk-cache.
54#[cfg($arena_cache)]
55pub type ProvidedValue<'tcx> =
56 <Value<'tcx> as $crate::query::arena_cached::ArenaCached<'tcx>>::Provided;
57/// Type returned from query providers and loaded from disk-cache.
58#[cfg(not($arena_cache))]
59pub type ProvidedValue<'tcx> = Value<'tcx>;
6061pub type Cache<'tcx> =
62 <Key<'tcx> as $crate::query::QueryKey>::Cache<Erased<Value<'tcx>>>;
6364/// This helper function takes a value returned by the query provider
65 /// (or loaded from disk, or supplied by query feeding), allocates
66 /// it in an arena if requested by the `arena_cache` modifier, and
67 /// then returns an erased copy of it.
68#[inline(always)]
69pub fn provided_to_erased<'tcx>(
70 tcx: TyCtxt<'tcx>,
71 provided_value: ProvidedValue<'tcx>,
72 ) -> Erased<Value<'tcx>> {
73// For queries with the `arena_cache` modifier, store the
74 // provided value in an arena and get a reference to it.
75#[cfg($arena_cache)]
76let value: Value<'tcx> = {
77use $crate::query::arena_cached::ArenaCached;
78 <Value<'tcx> as ArenaCached>::alloc_in_arena(
79 tcx,
80&tcx.query_system.arenas.$name,
81 provided_value,
82 )
83 };
8485// Otherwise, the provided value is the value (and `tcx` is unused).
86#[cfg(not($arena_cache))]
87let value: Value<'tcx> = {
88let _ = tcx;
89 provided_value
90 };
9192 erase::erase_val(value)
93 }
9495// Ensure that keys grow no larger than 88 bytes by accident.
96 // Increase this limit if necessary, but do try to keep the size low if possible
97#[cfg(target_pointer_width = "64")]
98const _: () = {
99if size_of::<Key<'static>>() > 88 {
100panic!("{}", concat!(
101"the query `",
102stringify!($name),
103"` has a key type `",
104stringify!($($K)*),
105"` that is too large"
106));
107 }
108 };
109110// Ensure that values grow no larger than 64 bytes by accident.
111 // Increase this limit if necessary, but do try to keep the size low if possible
112#[cfg(target_pointer_width = "64")]
113 #[cfg(not(feature = "rustc_randomized_layouts"))]
114const _: () = {
115if size_of::<Value<'static>>() > 64 {
116panic!("{}", concat!(
117"the query `",
118stringify!($name),
119"` has a value type `",
120stringify!($V),
121"` that is too large"
122));
123 }
124 };
125 }
126 )*
127128/// Identifies a query by kind and key. This is in contrast to `QueryJobId` which is just a
129 /// number.
130#[allow(non_camel_case_types)]
131 #[derive(Clone, Copy, Debug)]
132pub enum TaggedQueryKey<'tcx> {
133 $(
134$name($name::Key<'tcx>),
135 )*
136 }
137138impl<'tcx> TaggedQueryKey<'tcx> {
139/// Returns the name of the query this key is tagged with.
140 ///
141 /// This is useful for error/debug output, but don't use it to check for
142 /// specific query names. Instead, match on the `TaggedQueryKey` variant.
143pub fn query_name(&self) -> &'static str {
144match self {
145 $(
146 TaggedQueryKey::$name(_) => stringify!($name),
147 )*
148 }
149 }
150151/// Formats a human-readable description of this query and its key, as
152 /// specified by the `desc` query modifier.
153 ///
154 /// Used when reporting query cycle errors and similar problems.
155pub fn description(&self, tcx: TyCtxt<'tcx>) -> String {
156let (name, description) = ty::print::with_no_queries!(match self {
157 $(
158 TaggedQueryKey::$name(key) => (stringify!($name), ($desc)(tcx, *key)),
159 )*
160 });
161if tcx.sess.verbose_internals() {
162format!("{description} [{name:?}]")
163 } else {
164 description
165 }
166 }
167168/// Calls `self.description` or returns a fallback if there was a fatal error
169pub fn catch_description(&self, tcx: TyCtxt<'tcx>) -> String {
170 catch_fatal_errors(|| self.description(tcx)).unwrap_or_else(|_| format!("<error describing {}>", self.query_name()))
171 }
172173/// Returns the default span for this query if `span` is a dummy span.
174pub fn default_span(&self, tcx: TyCtxt<'tcx>, span: Span) -> Span {
175if !span.is_dummy() {
176return span
177 }
178if let TaggedQueryKey::def_span(..) = self {
179// The `def_span` query is used to calculate `default_span`,
180 // so exit to avoid infinite recursion.
181return DUMMY_SP
182 }
183match self {
184 $(
185 TaggedQueryKey::$name(key) =>
186$crate::query::QueryKey::default_span(key, tcx),
187 )*
188 }
189 }
190191/// Calls `self.default_span` or returns `DUMMY_SP` if there was a fatal error
192pub fn catch_default_span(&self, tcx: TyCtxt<'tcx>, span: Span) -> Span {
193 catch_fatal_errors(|| self.default_span(tcx, span)).unwrap_or(DUMMY_SP)
194 }
195 }
196197/// Holds a `QueryVTable` for each query.
198pub struct QueryVTables<'tcx> {
199 $(
200pub $name: $crate::query::QueryVTable<'tcx, $name::Cache<'tcx>>,
201 )*
202 }
203204/// Holds per-query arenas for queries with the `arena_cache` modifier.
205#[derive(Default)]
206pub struct QueryArenas<'tcx> {
207 $(
208// Use the `ArenaCached` helper trait to determine the arena's value type.
209#[cfg($arena_cache)]
210pub $name: TypedArena<
211 <$V as $crate::query::arena_cached::ArenaCached<'tcx>>::Allocated,
212 >,
213 )*
214 }
215216pub struct Providers {
217 $(
218/// This is the provider for the query. Use `Find references` on this to
219 /// navigate between the provider assignment and the query definition.
220pub $name: for<'tcx> fn(
221 TyCtxt<'tcx>,
222$name::LocalKey<'tcx>,
223 ) -> $name::ProvidedValue<'tcx>,
224 )*
225 }
226227pub struct ExternProviders {
228 $(
229#[cfg($separate_provide_extern)]
230pub $name: for<'tcx> fn(
231 TyCtxt<'tcx>,
232$name::Key<'tcx>,
233 ) -> $name::ProvidedValue<'tcx>,
234 )*
235 }
236237impl Default for Providers {
238fn default() -> Self {
239 Providers {
240 $(
241$name: |_, key| {
242$crate::query::query_api::default_query(stringify!($name), &key)
243 },
244 )*
245 }
246 }
247 }
248249impl Default for ExternProviders {
250fn default() -> Self {
251 ExternProviders {
252 $(
253#[cfg($separate_provide_extern)]
254$name: |_, key| $crate::query::query_api::default_extern_query(
255stringify!($name),
256&key,
257 ),
258 )*
259 }
260 }
261 }
262263impl Copy for Providers {}
264impl Clone for Providers {
265fn clone(&self) -> Self { *self }
266 }
267268impl Copy for ExternProviders {}
269impl Clone for ExternProviders {
270fn clone(&self) -> Self { *self }
271 }
272273impl<'tcx> TyCtxt<'tcx> {
274 $(
275 $(#[$attr])*
276#[inline(always)]
277 #[must_use]
278pub fn $name(self, key: maybe_into_query_key!($($K)*)) -> $V {
279self.at(DUMMY_SP).$name(key)
280 }
281 )*
282 }
283284impl<'tcx> $crate::query::TyCtxtAt<'tcx> {
285 $(
286 $(#[$attr])*
287#[inline(always)]
288pub fn $name(self, key: maybe_into_query_key!($($K)*)) -> $V {
289$crate::query::erase::restore_val::<$V>($crate::query::calls::query_get_at(
290self.tcx,
291self.span,
292&self.tcx.query_system.query_vtables.$name,
293$crate::query::IntoQueryKey::into_query_key(key),
294 ))
295 }
296 )*
297 }
298299impl<'tcx> $crate::query::TyCtxtEnsureOk<'tcx> {
300 $(
301 $(#[$attr])*
302#[inline(always)]
303pub fn $name(self, key: maybe_into_query_key!($($K)*)) {
304$crate::query::calls::query_ensure_ok(
305self.tcx,
306&self.tcx.query_system.query_vtables.$name,
307$crate::query::IntoQueryKey::into_query_key(key),
308 )
309 }
310 )*
311 }
312313// Only defined when the `returns_error_guaranteed` modifier is present.
314impl<'tcx> $crate::query::TyCtxtEnsureResult<'tcx> {
315 $(
316#[cfg($returns_error_guaranteed)]
317$(#[$attr])*
318#[inline(always)]
319pub fn $name(
320self,
321 key: maybe_into_query_key!($($K)*),
322 ) -> Result<(), rustc_errors::ErrorGuaranteed> {
323$crate::query::calls::query_ensure_result(
324self.tcx,
325&self.tcx.query_system.query_vtables.$name,
326$crate::query::IntoQueryKey::into_query_key(key),
327 )
328 }
329 )*
330 }
331332impl<'tcx> $crate::query::TyCtxtEnsureDone<'tcx> {
333 $(
334 $(#[$attr])*
335#[inline(always)]
336pub fn $name(self, key: maybe_into_query_key!($($K)*)) {
337// This has the same implementation as `tcx.$query(..)` as it isn't currently
338 // beneficial to have an optimized variant due to how promotion works.
339let _ = self.tcx.$name(key);
340 }
341 )*
342 }
343344 $(
345// Only defined when the `feedable` modifier is present.
346#[cfg($feedable)]
347impl<'tcx, K: $crate::query::IntoQueryKey<$name::Key<'tcx>> + Copy>
348 TyCtxtFeed<'tcx, K>
349 {
350 $(#[$attr])*
351#[inline(always)]
352pub fn $name(self, value: $name::ProvidedValue<'tcx>) {
353$crate::query::calls::query_feed(
354self.tcx,
355&self.tcx.query_system.query_vtables.$name,
356self.key().into_query_key(),
357$name::provided_to_erased(self.tcx, value),
358 );
359 }
360 }
361 )*
362 };
363}
364365// Re-export `macro_rules!` macros as normal items, so that they can be imported normally.
366pub(crate) use define_query_api;
367pub(crate) use maybe_into_query_key;
368369#[cold]
370pub(crate) fn default_query(name: &str, key: &dyn std::fmt::Debug) -> ! {
371::rustc_span::macros::bug_impl(None,
format_args!("`tcx.{0}({1:?})` is not supported for this key;\nhint: Queries can be either made to the local crate, or the external crate. This error means you tried to use it for one that\'s not supported.\nIf that\'s not the case, {0} was likely never assigned to a provider function.\n",
name, key), Location::caller())bug!(
372"`tcx.{name}({key:?})` is not supported for this key;\n\
373 hint: Queries can be either made to the local crate, or the external crate. \
374 This error means you tried to use it for one that's not supported.\n\
375 If that's not the case, {name} was likely never assigned to a provider function.\n",
376 )377}
378379#[cold]
380pub(crate) fn default_extern_query(name: &str, key: &dyn std::fmt::Debug) -> ! {
381::rustc_span::macros::bug_impl(None,
format_args!("`tcx.{0}({1:?})` unsupported by its crate; perhaps the `{0}` query was never assigned a provider function",
name, key), Location::caller())bug!(
382"`tcx.{name}({key:?})` unsupported by its crate; \
383 perhaps the `{name}` query was never assigned a provider function",
384 )385}