Skip to content

Commit a360f53

Browse files
committed
Auto merge of #153326 - Zalathar:query-modifiers, r=<try>
Make `rustc_with_all_queries!` pass query modifiers as named values
2 parents ec818fd + ba86d8a commit a360f53

File tree

7 files changed

+384
-490
lines changed

7 files changed

+384
-490
lines changed

compiler/rustc_macros/src/query.rs

Lines changed: 13 additions & 194 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
use proc_macro::TokenStream;
22
use proc_macro2::Span;
3-
use quote::{quote, quote_spanned};
3+
use quote::quote;
44
use syn::parse::{Parse, ParseStream, Result};
55
use syn::punctuated::Punctuated;
66
use syn::spanned::Spanned;
77
use syn::{
8-
AttrStyle, Attribute, Block, Error, Expr, Ident, Pat, ReturnType, Token, Type, braced,
9-
parenthesized, parse_macro_input, token,
8+
AttrStyle, Attribute, Error, Expr, Ident, Pat, ReturnType, Token, Type, braced, parenthesized,
9+
parse_macro_input, token,
1010
};
1111

12+
mod modifiers;
13+
1214
mod kw {
1315
syn::custom_keyword!(non_query);
1416
syn::custom_keyword!(query);
@@ -52,7 +54,7 @@ struct Query {
5254
key_ty: Type,
5355
return_ty: ReturnType,
5456

55-
modifiers: QueryModifiers,
57+
modifiers: modifiers::QueryModifiers,
5658
}
5759

5860
/// Declaration of a non-query dep kind.
@@ -102,7 +104,7 @@ impl Parse for QueryEntry {
102104
// Parse the query modifiers
103105
let braces_content;
104106
braced!(braces_content in input);
105-
let modifiers = parse_query_modifiers(&braces_content)?;
107+
let modifiers = modifiers::parse_query_modifiers(&braces_content)?;
106108

107109
// If there are no doc-comments, give at least some idea of what
108110
// it does by showing the query description.
@@ -127,151 +129,6 @@ impl<T: Parse> Parse for List<T> {
127129
}
128130
}
129131

130-
struct Desc {
131-
modifier: Ident,
132-
expr_list: Punctuated<Expr, Token![,]>,
133-
}
134-
135-
struct CacheOnDiskIf {
136-
modifier: Ident,
137-
block: Block,
138-
}
139-
140-
struct QueryModifiers {
141-
/// The description of the query.
142-
desc: Desc,
143-
144-
/// Use this type for the in-memory cache.
145-
arena_cache: Option<Ident>,
146-
147-
/// Cache the query to disk if the `Block` returns true.
148-
cache_on_disk_if: Option<CacheOnDiskIf>,
149-
150-
/// A cycle error for this query aborting the compilation with a fatal error.
151-
cycle_fatal: Option<Ident>,
152-
153-
/// A cycle error results in a delay_bug call
154-
cycle_delay_bug: Option<Ident>,
155-
156-
/// A cycle error results in a stashed cycle error that can be unstashed and canceled later
157-
cycle_stash: Option<Ident>,
158-
159-
/// Don't hash the result, instead just mark a query red if it runs
160-
no_hash: Option<Ident>,
161-
162-
/// Generate a dep node based on the dependencies of the query
163-
anon: Option<Ident>,
164-
165-
/// Always evaluate the query, ignoring its dependencies
166-
eval_always: Option<Ident>,
167-
168-
/// Whether the query has a call depth limit
169-
depth_limit: Option<Ident>,
170-
171-
/// Use a separate query provider for local and extern crates
172-
separate_provide_extern: Option<Ident>,
173-
174-
/// Generate a `feed` method to set the query's value from another query.
175-
feedable: Option<Ident>,
176-
177-
/// When this query is called via `tcx.ensure_ok()`, it returns
178-
/// `Result<(), ErrorGuaranteed>` instead of `()`. If the query needs to
179-
/// be executed, and that execution returns an error, the error result is
180-
/// returned to the caller.
181-
///
182-
/// If execution is skipped, a synthetic `Ok(())` is returned, on the
183-
/// assumption that a query with all-green inputs must have succeeded.
184-
///
185-
/// Can only be applied to queries with a return value of
186-
/// `Result<_, ErrorGuaranteed>`.
187-
return_result_from_ensure_ok: Option<Ident>,
188-
}
189-
190-
fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
191-
let mut arena_cache = None;
192-
let mut cache_on_disk_if = None;
193-
let mut desc = None;
194-
let mut cycle_fatal = None;
195-
let mut cycle_delay_bug = None;
196-
let mut cycle_stash = None;
197-
let mut no_hash = None;
198-
let mut anon = None;
199-
let mut eval_always = None;
200-
let mut depth_limit = None;
201-
let mut separate_provide_extern = None;
202-
let mut feedable = None;
203-
let mut return_result_from_ensure_ok = None;
204-
205-
while !input.is_empty() {
206-
let modifier: Ident = input.parse()?;
207-
208-
macro_rules! try_insert {
209-
($name:ident = $expr:expr) => {
210-
if $name.is_some() {
211-
return Err(Error::new(modifier.span(), "duplicate modifier"));
212-
}
213-
$name = Some($expr);
214-
};
215-
}
216-
217-
if modifier == "desc" {
218-
// Parse a description modifier like:
219-
// `desc { "foo {}", tcx.item_path(key) }`
220-
let attr_content;
221-
braced!(attr_content in input);
222-
let expr_list = attr_content.parse_terminated(Expr::parse, Token![,])?;
223-
try_insert!(desc = Desc { modifier, expr_list });
224-
} else if modifier == "cache_on_disk_if" {
225-
// Parse a cache-on-disk modifier like:
226-
// `cache_on_disk_if { tcx.is_typeck_child(key.to_def_id()) }`
227-
let block = input.parse()?;
228-
try_insert!(cache_on_disk_if = CacheOnDiskIf { modifier, block });
229-
} else if modifier == "arena_cache" {
230-
try_insert!(arena_cache = modifier);
231-
} else if modifier == "cycle_fatal" {
232-
try_insert!(cycle_fatal = modifier);
233-
} else if modifier == "cycle_delay_bug" {
234-
try_insert!(cycle_delay_bug = modifier);
235-
} else if modifier == "cycle_stash" {
236-
try_insert!(cycle_stash = modifier);
237-
} else if modifier == "no_hash" {
238-
try_insert!(no_hash = modifier);
239-
} else if modifier == "anon" {
240-
try_insert!(anon = modifier);
241-
} else if modifier == "eval_always" {
242-
try_insert!(eval_always = modifier);
243-
} else if modifier == "depth_limit" {
244-
try_insert!(depth_limit = modifier);
245-
} else if modifier == "separate_provide_extern" {
246-
try_insert!(separate_provide_extern = modifier);
247-
} else if modifier == "feedable" {
248-
try_insert!(feedable = modifier);
249-
} else if modifier == "return_result_from_ensure_ok" {
250-
try_insert!(return_result_from_ensure_ok = modifier);
251-
} else {
252-
return Err(Error::new(modifier.span(), "unknown query modifier"));
253-
}
254-
}
255-
let Some(desc) = desc else {
256-
return Err(input.error("no description provided"));
257-
};
258-
Ok(QueryModifiers {
259-
arena_cache,
260-
cache_on_disk_if,
261-
desc,
262-
cycle_fatal,
263-
cycle_delay_bug,
264-
cycle_stash,
265-
no_hash,
266-
anon,
267-
eval_always,
268-
depth_limit,
269-
separate_provide_extern,
270-
feedable,
271-
return_result_from_ensure_ok,
272-
})
273-
}
274-
275132
fn doc_comment_from_desc(list: &Punctuated<Expr, token::Comma>) -> Result<Attribute> {
276133
use ::syn::*;
277134
let mut iter = list.iter();
@@ -318,7 +175,7 @@ fn make_helpers_for_query(query: &Query, streams: &mut HelperTokenStreams) {
318175
erased_name.set_span(Span::call_site());
319176

320177
// Generate a function to check whether we should cache the query to disk, for some key.
321-
if let Some(CacheOnDiskIf { block, .. }) = modifiers.cache_on_disk_if.as_ref() {
178+
if let Some(modifiers::CacheOnDiskIf { block, .. }) = modifiers.cache_on_disk_if.as_ref() {
322179
// `disallowed_pass_by_ref` is needed because some keys are `rustc_pass_by_value`.
323180
streams.cache_on_disk_if_fns_stream.extend(quote! {
324181
#[cfg_attr(not(bootstrap), allow(unused_variables, rustc::disallowed_pass_by_ref))]
@@ -329,7 +186,7 @@ fn make_helpers_for_query(query: &Query, streams: &mut HelperTokenStreams) {
329186
});
330187
}
331188

332-
let Desc { expr_list, .. } = &modifiers.desc;
189+
let modifiers::Desc { expr_list, .. } = &modifiers.desc;
333190

334191
let desc = quote! {
335192
#[allow(unused_variables)]
@@ -356,7 +213,7 @@ fn add_to_analyzer_stream(query: &Query, analyzer_stream: &mut proc_macro2::Toke
356213
crate::query::modifiers::#name;
357214
});
358215

359-
if let Some(CacheOnDiskIf { modifier, .. }) = &modifiers.cache_on_disk_if {
216+
if let Some(modifiers::CacheOnDiskIf { modifier, .. }) = &modifiers.cache_on_disk_if {
360217
modifiers_stream.extend(quote! {
361218
crate::query::modifiers::#modifier;
362219
});
@@ -458,51 +315,13 @@ pub(super) fn rustc_queries(input: TokenStream) -> TokenStream {
458315
ReturnType::Type(..) => quote! { #return_ty },
459316
};
460317

461-
let mut modifiers_out = vec![];
462-
463-
macro_rules! passthrough {
464-
( $( $modifier:ident ),+ $(,)? ) => {
465-
$( if let Some($modifier) = &modifiers.$modifier {
466-
modifiers_out.push(quote! { (#$modifier) });
467-
}; )+
468-
}
469-
}
470-
471-
passthrough!(
472-
arena_cache,
473-
cycle_fatal,
474-
cycle_delay_bug,
475-
cycle_stash,
476-
no_hash,
477-
anon,
478-
eval_always,
479-
feedable,
480-
depth_limit,
481-
separate_provide_extern,
482-
return_result_from_ensure_ok,
483-
);
484-
485-
// If there was a `cache_on_disk_if` modifier in the real input, pass
486-
// on a synthetic `(cache_on_disk)` modifier that can be inspected by
487-
// macro-rules macros.
488-
if modifiers.cache_on_disk_if.is_some() {
489-
modifiers_out.push(quote! { (cache_on_disk) });
490-
}
491-
492-
// This uses the span of the query definition for the commas,
493-
// which can be important if we later encounter any ambiguity
494-
// errors with any of the numerous macro_rules! macros that
495-
// we use. Using the call-site span would result in a span pointing
496-
// at the entire `rustc_queries!` invocation, which wouldn't
497-
// be very useful.
498-
let span = name.span();
499-
let modifiers_stream = quote_spanned! { span => #(#modifiers_out),* };
318+
let modifiers_stream = modifiers::make_modifiers_stream(&query, modifiers);
500319

501320
// Add the query to the group
502321
query_stream.extend(quote! {
503322
#(#doc_comments)*
504-
[#modifiers_stream]
505-
fn #name(#key_ty) #return_ty,
323+
fn #name(#key_ty) #return_ty
324+
{ #modifiers_stream }
506325
});
507326

508327
if let Some(feedable) = &modifiers.feedable {

0 commit comments

Comments
 (0)