]>
Commit | Line | Data |
---|---|---|
532ac7d7 | 1 | use proc_macro::TokenStream; |
dfeec247 | 2 | use proc_macro2::{Delimiter, TokenTree}; |
94222f64 | 3 | use quote::{quote, quote_spanned}; |
dfeec247 XL |
4 | use syn::parse::{Parse, ParseStream, Result}; |
5 | use syn::punctuated::Punctuated; | |
6 | use syn::spanned::Spanned; | |
532ac7d7 | 7 | use syn::{ |
5869c6ff XL |
8 | braced, parenthesized, parse_macro_input, parse_quote, AttrStyle, Attribute, Block, Error, |
9 | Expr, Ident, ReturnType, Token, Type, | |
532ac7d7 | 10 | }; |
532ac7d7 | 11 | |
532ac7d7 XL |
12 | mod kw { |
13 | syn::custom_keyword!(query); | |
14 | } | |
15 | ||
16 | /// Ident or a wildcard `_`. | |
17 | struct IdentOrWild(Ident); | |
18 | ||
19 | impl Parse for IdentOrWild { | |
20 | fn parse(input: ParseStream<'_>) -> Result<Self> { | |
21 | Ok(if input.peek(Token![_]) { | |
22 | let underscore = input.parse::<Token![_]>()?; | |
23 | IdentOrWild(Ident::new("_", underscore.span())) | |
24 | } else { | |
25 | IdentOrWild(input.parse()?) | |
26 | }) | |
27 | } | |
28 | } | |
29 | ||
30 | /// A modifier for a query | |
31 | enum QueryModifier { | |
32 | /// The description of the query. | |
33 | Desc(Option<Ident>, Punctuated<Expr, Token![,]>), | |
34 | ||
74b04a01 XL |
35 | /// Use this type for the in-memory cache. |
36 | Storage(Type), | |
37 | ||
532ac7d7 | 38 | /// Cache the query to disk if the `Expr` returns true. |
3c0e092e | 39 | Cache(Option<IdentOrWild>, Block), |
532ac7d7 XL |
40 | |
41 | /// Custom code to load the query from disk. | |
42 | LoadCached(Ident, Ident, Block), | |
43 | ||
44 | /// A cycle error for this query aborting the compilation with a fatal error. | |
94222f64 | 45 | FatalCycle(Ident), |
532ac7d7 XL |
46 | |
47 | /// A cycle error results in a delay_bug call | |
94222f64 | 48 | CycleDelayBug(Ident), |
532ac7d7 XL |
49 | |
50 | /// Don't hash the result, instead just mark a query red if it runs | |
94222f64 | 51 | NoHash(Ident), |
532ac7d7 | 52 | |
532ac7d7 | 53 | /// Generate a dep node based on the dependencies of the query |
94222f64 | 54 | Anon(Ident), |
532ac7d7 | 55 | |
74b04a01 | 56 | /// Always evaluate the query, ignoring its dependencies |
94222f64 | 57 | EvalAlways(Ident), |
3c0e092e XL |
58 | |
59 | /// Use a separate query provider for local and extern crates | |
60 | SeparateProvideExtern(Ident), | |
a2a8927a XL |
61 | |
62 | /// Always remap the ParamEnv's constness before hashing and passing to the query provider | |
63 | RemapEnvConstness(Ident), | |
532ac7d7 XL |
64 | } |
65 | ||
66 | impl Parse for QueryModifier { | |
67 | fn parse(input: ParseStream<'_>) -> Result<Self> { | |
68 | let modifier: Ident = input.parse()?; | |
69 | if modifier == "desc" { | |
70 | // Parse a description modifier like: | |
71 | // `desc { |tcx| "foo {}", tcx.item_path(key) }` | |
72 | let attr_content; | |
73 | braced!(attr_content in input); | |
74 | let tcx = if attr_content.peek(Token![|]) { | |
75 | attr_content.parse::<Token![|]>()?; | |
76 | let tcx = attr_content.parse()?; | |
77 | attr_content.parse::<Token![|]>()?; | |
78 | Some(tcx) | |
79 | } else { | |
80 | None | |
81 | }; | |
82 | let desc = attr_content.parse_terminated(Expr::parse)?; | |
83 | Ok(QueryModifier::Desc(tcx, desc)) | |
dc9dc135 | 84 | } else if modifier == "cache_on_disk_if" { |
532ac7d7 | 85 | // Parse a cache modifier like: |
dc9dc135 XL |
86 | // `cache(tcx, value) { |tcx| key.is_local() }` |
87 | let has_args = if let TokenTree::Group(group) = input.fork().parse()? { | |
88 | group.delimiter() == Delimiter::Parenthesis | |
89 | } else { | |
90 | false | |
91 | }; | |
92 | let args = if has_args { | |
93 | let args; | |
94 | parenthesized!(args in input); | |
95 | let tcx = args.parse()?; | |
3c0e092e | 96 | Some(tcx) |
532ac7d7 XL |
97 | } else { |
98 | None | |
99 | }; | |
dc9dc135 XL |
100 | let block = input.parse()?; |
101 | Ok(QueryModifier::Cache(args, block)) | |
532ac7d7 XL |
102 | } else if modifier == "load_cached" { |
103 | // Parse a load_cached modifier like: | |
6a06907d | 104 | // `load_cached(tcx, id) { tcx.on_disk_cache.try_load_query_result(tcx, id) }` |
532ac7d7 XL |
105 | let args; |
106 | parenthesized!(args in input); | |
107 | let tcx = args.parse()?; | |
108 | args.parse::<Token![,]>()?; | |
109 | let id = args.parse()?; | |
110 | let block = input.parse()?; | |
111 | Ok(QueryModifier::LoadCached(tcx, id, block)) | |
74b04a01 | 112 | } else if modifier == "storage" { |
f9f354fc XL |
113 | let args; |
114 | parenthesized!(args in input); | |
115 | let ty = args.parse()?; | |
74b04a01 | 116 | Ok(QueryModifier::Storage(ty)) |
532ac7d7 | 117 | } else if modifier == "fatal_cycle" { |
94222f64 | 118 | Ok(QueryModifier::FatalCycle(modifier)) |
532ac7d7 | 119 | } else if modifier == "cycle_delay_bug" { |
94222f64 | 120 | Ok(QueryModifier::CycleDelayBug(modifier)) |
532ac7d7 | 121 | } else if modifier == "no_hash" { |
94222f64 | 122 | Ok(QueryModifier::NoHash(modifier)) |
532ac7d7 | 123 | } else if modifier == "anon" { |
94222f64 | 124 | Ok(QueryModifier::Anon(modifier)) |
532ac7d7 | 125 | } else if modifier == "eval_always" { |
94222f64 | 126 | Ok(QueryModifier::EvalAlways(modifier)) |
3c0e092e XL |
127 | } else if modifier == "separate_provide_extern" { |
128 | Ok(QueryModifier::SeparateProvideExtern(modifier)) | |
a2a8927a XL |
129 | } else if modifier == "remap_env_constness" { |
130 | Ok(QueryModifier::RemapEnvConstness(modifier)) | |
532ac7d7 XL |
131 | } else { |
132 | Err(Error::new(modifier.span(), "unknown query modifier")) | |
133 | } | |
134 | } | |
135 | } | |
136 | ||
137 | /// Ensures only doc comment attributes are used | |
1b1a35ee XL |
138 | fn check_attributes(attrs: Vec<Attribute>) -> Result<Vec<Attribute>> { |
139 | let inner = |attr: Attribute| { | |
532ac7d7 | 140 | if !attr.path.is_ident("doc") { |
1b1a35ee XL |
141 | Err(Error::new(attr.span(), "attributes not supported on queries")) |
142 | } else if attr.style != AttrStyle::Outer { | |
143 | Err(Error::new( | |
144 | attr.span(), | |
145 | "attributes must be outer attributes (`///`), not inner attributes", | |
146 | )) | |
147 | } else { | |
148 | Ok(attr) | |
532ac7d7 | 149 | } |
1b1a35ee XL |
150 | }; |
151 | attrs.into_iter().map(inner).collect() | |
532ac7d7 XL |
152 | } |
153 | ||
154 | /// A compiler query. `query ... { ... }` | |
155 | struct Query { | |
1b1a35ee | 156 | doc_comments: Vec<Attribute>, |
532ac7d7 XL |
157 | modifiers: List<QueryModifier>, |
158 | name: Ident, | |
159 | key: IdentOrWild, | |
160 | arg: Type, | |
161 | result: ReturnType, | |
162 | } | |
163 | ||
164 | impl Parse for Query { | |
165 | fn parse(input: ParseStream<'_>) -> Result<Self> { | |
1b1a35ee | 166 | let doc_comments = check_attributes(input.call(Attribute::parse_outer)?)?; |
532ac7d7 XL |
167 | |
168 | // Parse the query declaration. Like `query type_of(key: DefId) -> Ty<'tcx>` | |
169 | input.parse::<kw::query>()?; | |
170 | let name: Ident = input.parse()?; | |
171 | let arg_content; | |
172 | parenthesized!(arg_content in input); | |
173 | let key = arg_content.parse()?; | |
174 | arg_content.parse::<Token![:]>()?; | |
175 | let arg = arg_content.parse()?; | |
176 | let result = input.parse()?; | |
177 | ||
178 | // Parse the query modifiers | |
179 | let content; | |
180 | braced!(content in input); | |
181 | let modifiers = content.parse()?; | |
182 | ||
1b1a35ee | 183 | Ok(Query { doc_comments, modifiers, name, key, arg, result }) |
532ac7d7 XL |
184 | } |
185 | } | |
186 | ||
187 | /// A type used to greedily parse another type until the input is empty. | |
188 | struct List<T>(Vec<T>); | |
189 | ||
190 | impl<T: Parse> Parse for List<T> { | |
191 | fn parse(input: ParseStream<'_>) -> Result<Self> { | |
192 | let mut list = Vec::new(); | |
193 | while !input.is_empty() { | |
194 | list.push(input.parse()?); | |
195 | } | |
196 | Ok(List(list)) | |
197 | } | |
198 | } | |
199 | ||
532ac7d7 XL |
200 | struct QueryModifiers { |
201 | /// The description of the query. | |
f9f354fc | 202 | desc: (Option<Ident>, Punctuated<Expr, Token![,]>), |
532ac7d7 | 203 | |
74b04a01 XL |
204 | /// Use this type for the in-memory cache. |
205 | storage: Option<Type>, | |
206 | ||
dc9dc135 | 207 | /// Cache the query to disk if the `Block` returns true. |
3c0e092e | 208 | cache: Option<(Option<IdentOrWild>, Block)>, |
532ac7d7 XL |
209 | |
210 | /// Custom code to load the query from disk. | |
211 | load_cached: Option<(Ident, Ident, Block)>, | |
212 | ||
213 | /// A cycle error for this query aborting the compilation with a fatal error. | |
94222f64 | 214 | fatal_cycle: Option<Ident>, |
532ac7d7 XL |
215 | |
216 | /// A cycle error results in a delay_bug call | |
94222f64 | 217 | cycle_delay_bug: Option<Ident>, |
532ac7d7 XL |
218 | |
219 | /// Don't hash the result, instead just mark a query red if it runs | |
94222f64 | 220 | no_hash: Option<Ident>, |
532ac7d7 | 221 | |
532ac7d7 | 222 | /// Generate a dep node based on the dependencies of the query |
94222f64 | 223 | anon: Option<Ident>, |
532ac7d7 | 224 | |
74b04a01 | 225 | // Always evaluate the query, ignoring its dependencies |
94222f64 | 226 | eval_always: Option<Ident>, |
3c0e092e XL |
227 | |
228 | /// Use a separate query provider for local and extern crates | |
229 | separate_provide_extern: Option<Ident>, | |
a2a8927a XL |
230 | |
231 | /// Always remap the ParamEnv's constness before hashing. | |
232 | remap_env_constness: Option<Ident>, | |
532ac7d7 XL |
233 | } |
234 | ||
235 | /// Process query modifiers into a struct, erroring on duplicates | |
236 | fn process_modifiers(query: &mut Query) -> QueryModifiers { | |
237 | let mut load_cached = None; | |
74b04a01 | 238 | let mut storage = None; |
532ac7d7 XL |
239 | let mut cache = None; |
240 | let mut desc = None; | |
94222f64 XL |
241 | let mut fatal_cycle = None; |
242 | let mut cycle_delay_bug = None; | |
243 | let mut no_hash = None; | |
244 | let mut anon = None; | |
245 | let mut eval_always = None; | |
3c0e092e | 246 | let mut separate_provide_extern = None; |
a2a8927a | 247 | let mut remap_env_constness = None; |
532ac7d7 XL |
248 | for modifier in query.modifiers.0.drain(..) { |
249 | match modifier { | |
250 | QueryModifier::LoadCached(tcx, id, block) => { | |
251 | if load_cached.is_some() { | |
252 | panic!("duplicate modifier `load_cached` for query `{}`", query.name); | |
253 | } | |
254 | load_cached = Some((tcx, id, block)); | |
255 | } | |
74b04a01 XL |
256 | QueryModifier::Storage(ty) => { |
257 | if storage.is_some() { | |
258 | panic!("duplicate modifier `storage` for query `{}`", query.name); | |
259 | } | |
260 | storage = Some(ty); | |
261 | } | |
dc9dc135 | 262 | QueryModifier::Cache(args, expr) => { |
532ac7d7 XL |
263 | if cache.is_some() { |
264 | panic!("duplicate modifier `cache` for query `{}`", query.name); | |
265 | } | |
dc9dc135 | 266 | cache = Some((args, expr)); |
532ac7d7 XL |
267 | } |
268 | QueryModifier::Desc(tcx, list) => { | |
269 | if desc.is_some() { | |
270 | panic!("duplicate modifier `desc` for query `{}`", query.name); | |
271 | } | |
5869c6ff XL |
272 | // If there are no doc-comments, give at least some idea of what |
273 | // it does by showing the query description. | |
274 | if query.doc_comments.is_empty() { | |
275 | use ::syn::*; | |
276 | let mut list = list.iter(); | |
277 | let format_str: String = match list.next() { | |
278 | Some(&Expr::Lit(ExprLit { lit: Lit::Str(ref lit_str), .. })) => { | |
279 | lit_str.value().replace("`{}`", "{}") // We add them later anyways for consistency | |
280 | } | |
281 | _ => panic!("Expected a string literal"), | |
282 | }; | |
283 | let mut fmt_fragments = format_str.split("{}"); | |
284 | let mut doc_string = fmt_fragments.next().unwrap().to_string(); | |
285 | list.map(::quote::ToTokens::to_token_stream).zip(fmt_fragments).for_each( | |
286 | |(tts, next_fmt_fragment)| { | |
287 | use ::core::fmt::Write; | |
288 | write!( | |
289 | &mut doc_string, | |
290 | " `{}` {}", | |
291 | tts.to_string().replace(" . ", "."), | |
292 | next_fmt_fragment, | |
293 | ) | |
294 | .unwrap(); | |
295 | }, | |
296 | ); | |
297 | let doc_string = format!( | |
298 | "[query description - consider adding a doc-comment!] {}", | |
299 | doc_string | |
300 | ); | |
301 | let comment = parse_quote! { | |
302 | #[doc = #doc_string] | |
303 | }; | |
304 | query.doc_comments.push(comment); | |
305 | } | |
532ac7d7 XL |
306 | desc = Some((tcx, list)); |
307 | } | |
94222f64 XL |
308 | QueryModifier::FatalCycle(ident) => { |
309 | if fatal_cycle.is_some() { | |
532ac7d7 XL |
310 | panic!("duplicate modifier `fatal_cycle` for query `{}`", query.name); |
311 | } | |
94222f64 | 312 | fatal_cycle = Some(ident); |
532ac7d7 | 313 | } |
94222f64 XL |
314 | QueryModifier::CycleDelayBug(ident) => { |
315 | if cycle_delay_bug.is_some() { | |
532ac7d7 XL |
316 | panic!("duplicate modifier `cycle_delay_bug` for query `{}`", query.name); |
317 | } | |
94222f64 | 318 | cycle_delay_bug = Some(ident); |
532ac7d7 | 319 | } |
94222f64 XL |
320 | QueryModifier::NoHash(ident) => { |
321 | if no_hash.is_some() { | |
532ac7d7 XL |
322 | panic!("duplicate modifier `no_hash` for query `{}`", query.name); |
323 | } | |
94222f64 | 324 | no_hash = Some(ident); |
532ac7d7 | 325 | } |
94222f64 XL |
326 | QueryModifier::Anon(ident) => { |
327 | if anon.is_some() { | |
532ac7d7 XL |
328 | panic!("duplicate modifier `anon` for query `{}`", query.name); |
329 | } | |
94222f64 | 330 | anon = Some(ident); |
532ac7d7 | 331 | } |
94222f64 XL |
332 | QueryModifier::EvalAlways(ident) => { |
333 | if eval_always.is_some() { | |
532ac7d7 XL |
334 | panic!("duplicate modifier `eval_always` for query `{}`", query.name); |
335 | } | |
94222f64 | 336 | eval_always = Some(ident); |
532ac7d7 | 337 | } |
3c0e092e XL |
338 | QueryModifier::SeparateProvideExtern(ident) => { |
339 | if separate_provide_extern.is_some() { | |
340 | panic!( | |
341 | "duplicate modifier `separate_provide_extern` for query `{}`", | |
342 | query.name | |
343 | ); | |
344 | } | |
345 | separate_provide_extern = Some(ident); | |
346 | } | |
a2a8927a XL |
347 | QueryModifier::RemapEnvConstness(ident) => { |
348 | if remap_env_constness.is_some() { | |
349 | panic!("duplicate modifier `remap_env_constness` for query `{}`", query.name); | |
350 | } | |
351 | remap_env_constness = Some(ident) | |
352 | } | |
532ac7d7 XL |
353 | } |
354 | } | |
f9f354fc XL |
355 | let desc = desc.unwrap_or_else(|| { |
356 | panic!("no description provided for query `{}`", query.name); | |
357 | }); | |
532ac7d7 XL |
358 | QueryModifiers { |
359 | load_cached, | |
74b04a01 | 360 | storage, |
532ac7d7 XL |
361 | cache, |
362 | desc, | |
363 | fatal_cycle, | |
364 | cycle_delay_bug, | |
365 | no_hash, | |
532ac7d7 XL |
366 | anon, |
367 | eval_always, | |
3c0e092e | 368 | separate_provide_extern, |
a2a8927a | 369 | remap_env_constness, |
532ac7d7 XL |
370 | } |
371 | } | |
372 | ||
373 | /// Add the impl of QueryDescription for the query to `impls` if one is requested | |
374 | fn add_query_description_impl( | |
375 | query: &Query, | |
376 | modifiers: QueryModifiers, | |
dc9dc135 | 377 | impls: &mut proc_macro2::TokenStream, |
532ac7d7 XL |
378 | ) { |
379 | let name = &query.name; | |
532ac7d7 XL |
380 | let key = &query.key.0; |
381 | ||
382 | // Find out if we should cache the query on disk | |
f9f354fc | 383 | let cache = if let Some((args, expr)) = modifiers.cache.as_ref() { |
532ac7d7 XL |
384 | let try_load_from_disk = if let Some((tcx, id, block)) = modifiers.load_cached.as_ref() { |
385 | // Use custom code to load the query from disk | |
386 | quote! { | |
3c0e092e XL |
387 | const TRY_LOAD_FROM_DISK: Option<fn(QueryCtxt<$tcx>, SerializedDepNodeIndex) -> Option<Self::Value>> |
388 | = Some(|#tcx, #id| { #block }); | |
532ac7d7 XL |
389 | } |
390 | } else { | |
391 | // Use the default code to load the query from disk | |
392 | quote! { | |
3c0e092e XL |
393 | const TRY_LOAD_FROM_DISK: Option<fn(QueryCtxt<$tcx>, SerializedDepNodeIndex) -> Option<Self::Value>> |
394 | = Some(|tcx, id| tcx.on_disk_cache().as_ref()?.try_load_query_result(*tcx, id)); | |
532ac7d7 XL |
395 | } |
396 | }; | |
397 | ||
dfeec247 XL |
398 | let tcx = args |
399 | .as_ref() | |
400 | .map(|t| { | |
3c0e092e | 401 | let t = &t.0; |
dfeec247 XL |
402 | quote! { #t } |
403 | }) | |
6a06907d | 404 | .unwrap_or_else(|| quote! { _ }); |
ba9703b0 XL |
405 | // expr is a `Block`, meaning that `{ #expr }` gets expanded |
406 | // to `{ { stmts... } }`, which triggers the `unused_braces` lint. | |
532ac7d7 | 407 | quote! { |
ba9703b0 | 408 | #[allow(unused_variables, unused_braces)] |
3c0e092e XL |
409 | #[inline] |
410 | fn cache_on_disk(#tcx: TyCtxt<'tcx>, #key: &Self::Key) -> bool { | |
532ac7d7 XL |
411 | #expr |
412 | } | |
413 | ||
414 | #try_load_from_disk | |
415 | } | |
f9f354fc XL |
416 | } else { |
417 | if modifiers.load_cached.is_some() { | |
418 | panic!("load_cached modifier on query `{}` without a cache modifier", name); | |
419 | } | |
3c0e092e XL |
420 | quote! { |
421 | #[inline] | |
422 | fn cache_on_disk(_: TyCtxt<'tcx>, _: &Self::Key) -> bool { | |
423 | false | |
424 | } | |
425 | ||
426 | const TRY_LOAD_FROM_DISK: Option<fn(QueryCtxt<$tcx>, SerializedDepNodeIndex) -> Option<Self::Value>> = None; | |
427 | } | |
f9f354fc XL |
428 | }; |
429 | ||
430 | let (tcx, desc) = modifiers.desc; | |
6a06907d | 431 | let tcx = tcx.as_ref().map_or_else(|| quote! { _ }, |t| quote! { #t }); |
f9f354fc XL |
432 | |
433 | let desc = quote! { | |
434 | #[allow(unused_variables)] | |
3c0e092e | 435 | fn describe(tcx: QueryCtxt<$tcx>, key: Self::Key) -> String { |
6a06907d | 436 | let (#tcx, #key) = (*tcx, key); |
1b1a35ee | 437 | ::rustc_middle::ty::print::with_no_trimmed_paths(|| format!(#desc).into()) |
f9f354fc XL |
438 | } |
439 | }; | |
532ac7d7 | 440 | |
f9f354fc | 441 | impls.extend(quote! { |
3c0e092e | 442 | (#name<$tcx:tt>) => { |
f9f354fc XL |
443 | #desc |
444 | #cache | |
3c0e092e | 445 | }; |
532ac7d7 | 446 | }); |
532ac7d7 XL |
447 | } |
448 | ||
449 | pub fn rustc_queries(input: TokenStream) -> TokenStream { | |
5869c6ff | 450 | let queries = parse_macro_input!(input as List<Query>); |
532ac7d7 XL |
451 | |
452 | let mut query_stream = quote! {}; | |
453 | let mut query_description_stream = quote! {}; | |
454 | let mut dep_node_def_stream = quote! {}; | |
416331ca | 455 | let mut cached_queries = quote! {}; |
532ac7d7 | 456 | |
5869c6ff XL |
457 | for mut query in queries.0 { |
458 | let modifiers = process_modifiers(&mut query); | |
459 | let name = &query.name; | |
460 | let arg = &query.arg; | |
461 | let result_full = &query.result; | |
462 | let result = match query.result { | |
463 | ReturnType::Default => quote! { -> () }, | |
464 | _ => quote! { #result_full }, | |
465 | }; | |
532ac7d7 | 466 | |
5869c6ff XL |
467 | if modifiers.cache.is_some() { |
468 | cached_queries.extend(quote! { | |
469 | #name, | |
470 | }); | |
471 | } | |
dc9dc135 | 472 | |
5869c6ff | 473 | let mut attributes = Vec::new(); |
532ac7d7 | 474 | |
5869c6ff | 475 | // Pass on the fatal_cycle modifier |
94222f64 | 476 | if let Some(fatal_cycle) = &modifiers.fatal_cycle { |
c295e0f8 | 477 | attributes.push(quote! { (#fatal_cycle) }); |
5869c6ff XL |
478 | }; |
479 | // Pass on the storage modifier | |
480 | if let Some(ref ty) = modifiers.storage { | |
94222f64 | 481 | let span = ty.span(); |
c295e0f8 | 482 | attributes.push(quote_spanned! {span=> (storage #ty) }); |
5869c6ff XL |
483 | }; |
484 | // Pass on the cycle_delay_bug modifier | |
94222f64 | 485 | if let Some(cycle_delay_bug) = &modifiers.cycle_delay_bug { |
c295e0f8 | 486 | attributes.push(quote! { (#cycle_delay_bug) }); |
5869c6ff XL |
487 | }; |
488 | // Pass on the no_hash modifier | |
94222f64 | 489 | if let Some(no_hash) = &modifiers.no_hash { |
c295e0f8 | 490 | attributes.push(quote! { (#no_hash) }); |
5869c6ff XL |
491 | }; |
492 | // Pass on the anon modifier | |
94222f64 | 493 | if let Some(anon) = &modifiers.anon { |
c295e0f8 | 494 | attributes.push(quote! { (#anon) }); |
5869c6ff XL |
495 | }; |
496 | // Pass on the eval_always modifier | |
94222f64 | 497 | if let Some(eval_always) = &modifiers.eval_always { |
c295e0f8 | 498 | attributes.push(quote! { (#eval_always) }); |
5869c6ff | 499 | }; |
3c0e092e XL |
500 | // Pass on the separate_provide_extern modifier |
501 | if let Some(separate_provide_extern) = &modifiers.separate_provide_extern { | |
502 | attributes.push(quote! { (#separate_provide_extern) }); | |
503 | } | |
a2a8927a XL |
504 | // Pass on the remap_env_constness modifier |
505 | if let Some(remap_env_constness) = &modifiers.remap_env_constness { | |
506 | attributes.push(quote! { (#remap_env_constness) }); | |
507 | } | |
532ac7d7 | 508 | |
94222f64 XL |
509 | // This uses the span of the query definition for the commas, |
510 | // which can be important if we later encounter any ambiguity | |
511 | // errors with any of the numerous macro_rules! macros that | |
512 | // we use. Using the call-site span would result in a span pointing | |
513 | // at the entire `rustc_queries!` invocation, which wouldn't | |
514 | // be very useful. | |
515 | let span = name.span(); | |
516 | let attribute_stream = quote_spanned! {span=> #(#attributes),*}; | |
5869c6ff XL |
517 | let doc_comments = query.doc_comments.iter(); |
518 | // Add the query to the group | |
519 | query_stream.extend(quote! { | |
520 | #(#doc_comments)* | |
521 | [#attribute_stream] fn #name(#arg) #result, | |
522 | }); | |
dc9dc135 | 523 | |
5869c6ff XL |
524 | // Create a dep node for the query |
525 | dep_node_def_stream.extend(quote! { | |
526 | [#attribute_stream] #name(#arg), | |
527 | }); | |
532ac7d7 | 528 | |
5869c6ff | 529 | add_query_description_impl(&query, modifiers, &mut query_description_stream); |
532ac7d7 XL |
530 | } |
531 | ||
532ac7d7 | 532 | TokenStream::from(quote! { |
6a06907d | 533 | #[macro_export] |
532ac7d7 XL |
534 | macro_rules! rustc_query_append { |
535 | ([$($macro:tt)*][$($other:tt)*]) => { | |
536 | $($macro)* { | |
537 | $($other)* | |
538 | ||
539 | #query_stream | |
540 | ||
541 | } | |
542 | } | |
543 | } | |
544 | macro_rules! rustc_dep_node_append { | |
545 | ([$($macro:tt)*][$($other:tt)*]) => { | |
546 | $($macro)*( | |
547 | $($other)* | |
548 | ||
549 | #dep_node_def_stream | |
550 | ); | |
551 | } | |
552 | } | |
6a06907d | 553 | #[macro_export] |
416331ca XL |
554 | macro_rules! rustc_cached_queries { |
555 | ($($macro:tt)*) => { | |
556 | $($macro)*(#cached_queries); | |
557 | } | |
558 | } | |
6a06907d XL |
559 | #[macro_export] |
560 | macro_rules! rustc_query_description { | |
3c0e092e | 561 | #query_description_stream |
6a06907d | 562 | } |
532ac7d7 XL |
563 | }) |
564 | } |