1macro_rules!maybe_into_query_key {
2 (DefId) => { impl $crate::query::IntoQueryKey<DefId> };
3 (LocalDefId) => { impl $crate::query::IntoQueryKey<LocalDefId> };
4 ($K:ty) => { $K };
5}
67macro_rules!define_query_api {
8 (
9// You might expect the key to be `$K:ty`, but it needs to be `$($K:tt)*` so that
10 // `maybe_into_query_key!` can match on specific type names.
11queries {
12 $(
13 $(#[$attr:meta])*
14fn $name:ident($($K:tt)*) -> $V:ty
15 {
16// Search for (QMODLIST) to find all occurrences of this query modifier list.
17arena_cache: $arena_cache:literal,
18 cache_on_disk: $cache_on_disk:literal,
19 depth_limit: $depth_limit:literal,
20 desc: $desc:expr,
21 eval_always: $eval_always:literal,
22 feedable: $feedable:literal,
23 handle_cycle_error: $handle_cycle_error:literal,
24 no_force: $no_force:literal,
25 no_hash: $no_hash:literal,
26 returns_error_guaranteed: $returns_error_guaranteed:literal,
27 separate_provide_extern: $separate_provide_extern:literal,
28 }
29 )*
30 }
31// Non-queries are unused here.
32non_queries { $($_:tt)* }
33 ) => {
34 $(
35pub mod $name {
36use super::*;
37use $crate::query::erase::{self, Erased};
3839pub type Key<'tcx> = $($K)*;
40pub type Value<'tcx> = $V;
4142/// Key type used by provider functions in `local_providers`.
43 /// This query has the `separate_provide_extern` modifier.
44#[cfg($separate_provide_extern)]
45pub type LocalKey<'tcx> =
46 <Key<'tcx> as $crate::query::QueryKey>::LocalQueryKey;
47/// Key type used by provider functions in `local_providers`.
48#[cfg(not($separate_provide_extern))]
49pub type LocalKey<'tcx> = Key<'tcx>;
5051/// Type returned from query providers and loaded from disk-cache.
52#[cfg($arena_cache)]
53pub type ProvidedValue<'tcx> =
54 <Value<'tcx> as $crate::query::arena_cached::ArenaCached<'tcx>>::Provided;
55/// Type returned from query providers and loaded from disk-cache.
56#[cfg(not($arena_cache))]
57pub type ProvidedValue<'tcx> = Value<'tcx>;
5859pub type Cache<'tcx> =
60 <Key<'tcx> as $crate::query::QueryKey>::Cache<Erased<Value<'tcx>>>;
6162/// This helper function takes a value returned by the query provider
63 /// (or loaded from disk, or supplied by query feeding), allocates
64 /// it in an arena if requested by the `arena_cache` modifier, and
65 /// then returns an erased copy of it.
66#[inline(always)]
67pub fn provided_to_erased<'tcx>(
68 tcx: TyCtxt<'tcx>,
69 provided_value: ProvidedValue<'tcx>,
70 ) -> Erased<Value<'tcx>> {
71// For queries with the `arena_cache` modifier, store the
72 // provided value in an arena and get a reference to it.
73#[cfg($arena_cache)]
74let value: Value<'tcx> = {
75use $crate::query::arena_cached::ArenaCached;
76 <Value<'tcx> as ArenaCached>::alloc_in_arena(
77 tcx,
78&tcx.query_system.arenas.$name,
79 provided_value,
80 )
81 };
8283// Otherwise, the provided value is the value (and `tcx` is unused).
84#[cfg(not($arena_cache))]
85let value: Value<'tcx> = {
86let _ = tcx;
87 provided_value
88 };
8990 erase::erase_val(value)
91 }
9293// Ensure that keys grow no larger than 88 bytes by accident.
94 // Increase this limit if necessary, but do try to keep the size low if possible
95#[cfg(target_pointer_width = "64")]
96const _: () = {
97if size_of::<Key<'static>>() > 88 {
98panic!("{}", concat!(
99"the query `",
100stringify!($name),
101"` has a key type `",
102stringify!($($K)*),
103"` that is too large"
104));
105 }
106 };
107108// Ensure that values grow no larger than 64 bytes by accident.
109 // Increase this limit if necessary, but do try to keep the size low if possible
110#[cfg(target_pointer_width = "64")]
111 #[cfg(not(feature = "rustc_randomized_layouts"))]
112const _: () = {
113if size_of::<Value<'static>>() > 64 {
114panic!("{}", concat!(
115"the query `",
116stringify!($name),
117"` has a value type `",
118stringify!($V),
119"` that is too large"
120));
121 }
122 };
123 }
124 )*
125126/// Identifies a query by kind and key. This is in contrast to `QueryJobId` which is just a
127 /// number.
128#[allow(non_camel_case_types)]
129 #[derive(Clone, Copy, Debug)]
130pub enum TaggedQueryKey<'tcx> {
131 $(
132$name($name::Key<'tcx>),
133 )*
134 }
135136impl<'tcx> TaggedQueryKey<'tcx> {
137/// Returns the name of the query this key is tagged with.
138 ///
139 /// This is useful for error/debug output, but don't use it to check for
140 /// specific query names. Instead, match on the `TaggedQueryKey` variant.
141pub fn query_name(&self) -> &'static str {
142match self {
143 $(
144 TaggedQueryKey::$name(_) => stringify!($name),
145 )*
146 }
147 }
148149/// Formats a human-readable description of this query and its key, as
150 /// specified by the `desc` query modifier.
151 ///
152 /// Used when reporting query cycle errors and similar problems.
153pub fn description(&self, tcx: TyCtxt<'tcx>) -> String {
154let (name, description) = ty::print::with_no_queries!(match self {
155 $(
156 TaggedQueryKey::$name(key) => (stringify!($name), ($desc)(tcx, *key)),
157 )*
158 });
159if tcx.sess.verbose_internals() {
160format!("{description} [{name:?}]")
161 } else {
162 description
163 }
164 }
165166/// Calls `self.description` or returns a fallback if there was a fatal error
167pub fn catch_description(&self, tcx: TyCtxt<'tcx>) -> String {
168 catch_fatal_errors(|| self.description(tcx)).unwrap_or_else(|_| format!("<error describing {}>", self.query_name()))
169 }
170171/// Returns the default span for this query if `span` is a dummy span.
172pub fn default_span(&self, tcx: TyCtxt<'tcx>, span: Span) -> Span {
173if !span.is_dummy() {
174return span
175 }
176if let TaggedQueryKey::def_span(..) = self {
177// The `def_span` query is used to calculate `default_span`,
178 // so exit to avoid infinite recursion.
179return DUMMY_SP
180 }
181match self {
182 $(
183 TaggedQueryKey::$name(key) =>
184$crate::query::QueryKey::default_span(key, tcx),
185 )*
186 }
187 }
188189/// Calls `self.default_span` or returns `DUMMY_SP` if there was a fatal error
190pub fn catch_default_span(&self, tcx: TyCtxt<'tcx>, span: Span) -> Span {
191 catch_fatal_errors(|| self.default_span(tcx, span)).unwrap_or(DUMMY_SP)
192 }
193 }
194195/// Holds a `QueryVTable` for each query.
196pub struct QueryVTables<'tcx> {
197 $(
198pub $name: $crate::query::QueryVTable<'tcx, $name::Cache<'tcx>>,
199 )*
200 }
201202/// Holds per-query arenas for queries with the `arena_cache` modifier.
203#[derive(Default)]
204pub struct QueryArenas<'tcx> {
205 $(
206// Use the `ArenaCached` helper trait to determine the arena's value type.
207#[cfg($arena_cache)]
208pub $name: TypedArena<
209 <$V as $crate::query::arena_cached::ArenaCached<'tcx>>::Allocated,
210 >,
211 )*
212 }
213214pub struct Providers {
215 $(
216/// This is the provider for the query. Use `Find references` on this to
217 /// navigate between the provider assignment and the query definition.
218pub $name: for<'tcx> fn(
219 TyCtxt<'tcx>,
220$name::LocalKey<'tcx>,
221 ) -> $name::ProvidedValue<'tcx>,
222 )*
223 }
224225pub struct ExternProviders {
226 $(
227#[cfg($separate_provide_extern)]
228pub $name: for<'tcx> fn(
229 TyCtxt<'tcx>,
230$name::Key<'tcx>,
231 ) -> $name::ProvidedValue<'tcx>,
232 )*
233 }
234235impl Default for Providers {
236fn default() -> Self {
237 Providers {
238 $(
239$name: |_, key| {
240$crate::query::query_api::default_query(stringify!($name), &key)
241 },
242 )*
243 }
244 }
245 }
246247impl Default for ExternProviders {
248fn default() -> Self {
249 ExternProviders {
250 $(
251#[cfg($separate_provide_extern)]
252$name: |_, key| $crate::query::query_api::default_extern_query(
253stringify!($name),
254&key,
255 ),
256 )*
257 }
258 }
259 }
260261impl Copy for Providers {}
262impl Clone for Providers {
263fn clone(&self) -> Self { *self }
264 }
265266impl Copy for ExternProviders {}
267impl Clone for ExternProviders {
268fn clone(&self) -> Self { *self }
269 }
270271impl<'tcx> TyCtxt<'tcx> {
272 $(
273 $(#[$attr])*
274#[inline(always)]
275 #[must_use]
276pub fn $name(self, key: maybe_into_query_key!($($K)*)) -> $V {
277self.at(DUMMY_SP).$name(key)
278 }
279 )*
280 }
281282impl<'tcx> $crate::query::TyCtxtAt<'tcx> {
283 $(
284 $(#[$attr])*
285#[inline(always)]
286pub fn $name(self, key: maybe_into_query_key!($($K)*)) -> $V {
287$crate::query::erase::restore_val::<$V>($crate::query::calls::query_get_at(
288self.tcx,
289self.span,
290&self.tcx.query_system.query_vtables.$name,
291$crate::query::IntoQueryKey::into_query_key(key),
292 ))
293 }
294 )*
295 }
296297impl<'tcx> $crate::query::TyCtxtEnsureOk<'tcx> {
298 $(
299 $(#[$attr])*
300#[inline(always)]
301pub fn $name(self, key: maybe_into_query_key!($($K)*)) {
302$crate::query::calls::query_ensure_ok(
303self.tcx,
304&self.tcx.query_system.query_vtables.$name,
305$crate::query::IntoQueryKey::into_query_key(key),
306 )
307 }
308 )*
309 }
310311// Only defined when the `returns_error_guaranteed` modifier is present.
312impl<'tcx> $crate::query::TyCtxtEnsureResult<'tcx> {
313 $(
314#[cfg($returns_error_guaranteed)]
315$(#[$attr])*
316#[inline(always)]
317pub fn $name(
318self,
319 key: maybe_into_query_key!($($K)*),
320 ) -> Result<(), rustc_errors::ErrorGuaranteed> {
321$crate::query::calls::query_ensure_result(
322self.tcx,
323&self.tcx.query_system.query_vtables.$name,
324$crate::query::IntoQueryKey::into_query_key(key),
325 )
326 }
327 )*
328 }
329330impl<'tcx> $crate::query::TyCtxtEnsureDone<'tcx> {
331 $(
332 $(#[$attr])*
333#[inline(always)]
334pub fn $name(self, key: maybe_into_query_key!($($K)*)) {
335// This has the same implementation as `tcx.$query(..)` as it isn't currently
336 // beneficial to have an optimized variant due to how promotion works.
337let _ = self.tcx.$name(key);
338 }
339 )*
340 }
341342 $(
343// Only defined when the `feedable` modifier is present.
344#[cfg($feedable)]
345impl<'tcx, K: $crate::query::IntoQueryKey<$name::Key<'tcx>> + Copy>
346 TyCtxtFeed<'tcx, K>
347 {
348 $(#[$attr])*
349#[inline(always)]
350pub fn $name(self, value: $name::ProvidedValue<'tcx>) {
351$crate::query::calls::query_feed(
352self.tcx,
353&self.tcx.query_system.query_vtables.$name,
354self.key().into_query_key(),
355$name::provided_to_erased(self.tcx, value),
356 );
357 }
358 }
359 )*
360 };
361}
362363// Re-export `macro_rules!` macros as normal items, so that they can be imported normally.
364pub(crate) use define_query_api;
365pub(crate) use maybe_into_query_key;
366367#[cold]
368pub(crate) fn default_query(name: &str, key: &dyn std::fmt::Debug) -> ! {
369crate::util::bug::bug_fmt(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))bug!(
370"`tcx.{name}({key:?})` is not supported for this key;\n\
371 hint: Queries can be either made to the local crate, or the external crate. \
372 This error means you tried to use it for one that's not supported.\n\
373 If that's not the case, {name} was likely never assigned to a provider function.\n",
374 )375}
376377#[cold]
378pub(crate) fn default_extern_query(name: &str, key: &dyn std::fmt::Debug) -> ! {
379crate::util::bug::bug_fmt(format_args!("`tcx.{0}({1:?})` unsupported by its crate; perhaps the `{0}` query was never assigned a provider function",
name, key))bug!(
380"`tcx.{name}({key:?})` unsupported by its crate; \
381 perhaps the `{name}` query was never assigned a provider function",
382 )383}