Skip to content

Commit 198dfce

Browse files
committed
Preprocess query modifiers
1 parent 4f49fff commit 198dfce

File tree

1 file changed

+82
-31
lines changed

1 file changed

+82
-31
lines changed

src/librustc_macros/src/query.rs

+82-31
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use proc_macro::TokenStream;
2-
use proc_macro2::Span;
32
use syn::{
43
Token, Ident, Type, Attribute, ReturnType, Expr, Block, Error,
54
braced, parenthesized, parse_macro_input,
@@ -21,8 +20,8 @@ struct IdentOrWild(Ident);
2120
impl Parse for IdentOrWild {
2221
fn parse(input: ParseStream<'_>) -> Result<Self> {
2322
Ok(if input.peek(Token![_]) {
24-
input.parse::<Token![_]>()?;
25-
IdentOrWild(Ident::new("_", Span::call_site()))
23+
let underscore = input.parse::<Token![_]>()?;
24+
IdentOrWild(Ident::new("_", underscore.span()))
2625
} else {
2726
IdentOrWild(input.parse()?)
2827
})
@@ -31,7 +30,7 @@ impl Parse for IdentOrWild {
3130

3231
/// A modifier for a query
3332
enum QueryModifier {
34-
/// The description of the query
33+
/// The description of the query.
3534
Desc(Option<Ident>, Punctuated<Expr, Token![,]>),
3635

3736
/// Cache the query to disk if the `Expr` returns true.
@@ -107,7 +106,7 @@ fn check_attributes(attrs: Vec<Attribute>) -> Result<()> {
107106

108107
/// A compiler query. `query ... { ... }`
109108
struct Query {
110-
attrs: List<QueryModifier>,
109+
modifiers: List<QueryModifier>,
111110
name: Ident,
112111
key: IdentOrWild,
113112
arg: Type,
@@ -131,10 +130,10 @@ impl Parse for Query {
131130
// Parse the query modifiers
132131
let content;
133132
braced!(content in input);
134-
let attrs = content.parse()?;
133+
let modifiers = content.parse()?;
135134

136135
Ok(Query {
137-
attrs,
136+
modifiers,
138137
name,
139138
key,
140139
arg,
@@ -174,24 +173,76 @@ impl Parse for Group {
174173
}
175174
}
176175

176+
struct QueryModifiers {
177+
/// The description of the query.
178+
desc: Option<(Option<Ident>, Punctuated<Expr, Token![,]>)>,
179+
180+
/// Cache the query to disk if the `Expr` returns true.
181+
cache: Option<(Option<Ident>, Expr)>,
182+
183+
/// Custom code to load the query from disk.
184+
load_cached: Option<(Ident, Ident, Block)>,
185+
186+
/// A cycle error for this query aborting the compilation with a fatal error.
187+
fatal_cycle: bool,
188+
}
189+
190+
/// Process query modifiers into a struct, erroring on duplicates
191+
fn process_modifiers(query: &mut Query) -> QueryModifiers {
192+
let mut load_cached = None;
193+
let mut cache = None;
194+
let mut desc = None;
195+
let mut fatal_cycle = false;
196+
for modifier in query.modifiers.0.drain(..) {
197+
match modifier {
198+
QueryModifier::LoadCached(tcx, id, block) => {
199+
if load_cached.is_some() {
200+
panic!("duplicate modifier `load_cached` for query `{}`", query.name);
201+
}
202+
load_cached = Some((tcx, id, block));
203+
}
204+
QueryModifier::Cache(tcx, expr) => {
205+
if cache.is_some() {
206+
panic!("duplicate modifier `cache` for query `{}`", query.name);
207+
}
208+
cache = Some((tcx, expr));
209+
}
210+
QueryModifier::Desc(tcx, list) => {
211+
if desc.is_some() {
212+
panic!("duplicate modifier `desc` for query `{}`", query.name);
213+
}
214+
desc = Some((tcx, list));
215+
}
216+
QueryModifier::FatalCycle => {
217+
if fatal_cycle {
218+
panic!("duplicate modifier `fatal_cycle` for query `{}`", query.name);
219+
}
220+
fatal_cycle = true;
221+
}
222+
}
223+
}
224+
QueryModifiers {
225+
load_cached,
226+
cache,
227+
desc,
228+
fatal_cycle,
229+
}
230+
}
231+
177232
/// Add the impl of QueryDescription for the query to `impls` if one is requested
178-
fn add_query_description_impl(query: &Query, impls: &mut proc_macro2::TokenStream) {
233+
fn add_query_description_impl(
234+
query: &Query,
235+
modifiers: QueryModifiers,
236+
impls: &mut proc_macro2::TokenStream
237+
) {
179238
let name = &query.name;
180239
let arg = &query.arg;
181240
let key = &query.key.0;
182241

183-
// Find custom code to load the query from disk
184-
let load_cached = query.attrs.0.iter().find_map(|attr| match attr {
185-
QueryModifier::LoadCached(tcx, id, block) => Some((tcx, id, block)),
186-
_ => None,
187-
});
188-
189242
// Find out if we should cache the query on disk
190-
let cache = query.attrs.0.iter().find_map(|attr| match attr {
191-
QueryModifier::Cache(tcx, expr) => Some((tcx, expr)),
192-
_ => None,
193-
}).map(|(tcx, expr)| {
194-
let try_load_from_disk = if let Some((tcx, id, block)) = load_cached {
243+
let cache = modifiers.cache.as_ref().map(|(tcx, expr)| {
244+
let try_load_from_disk = if let Some((tcx, id, block)) = modifiers.load_cached.as_ref() {
245+
// Use custom code to load the query from disk
195246
quote! {
196247
#[inline]
197248
fn try_load_from_disk(
@@ -202,6 +253,7 @@ fn add_query_description_impl(query: &Query, impls: &mut proc_macro2::TokenStrea
202253
}
203254
}
204255
} else {
256+
// Use the default code to load the query from disk
205257
quote! {
206258
#[inline]
207259
fn try_load_from_disk(
@@ -224,14 +276,11 @@ fn add_query_description_impl(query: &Query, impls: &mut proc_macro2::TokenStrea
224276
}
225277
});
226278

227-
if cache.is_none() && load_cached.is_some() {
279+
if cache.is_none() && modifiers.load_cached.is_some() {
228280
panic!("load_cached modifier on query `{}` without a cache modifier", name);
229281
}
230282

231-
let desc = query.attrs.0.iter().find_map(|attr| match attr {
232-
QueryModifier::Desc(tcx, desc) => Some((tcx, desc)),
233-
_ => None,
234-
}).map(|(tcx, desc)| {
283+
let desc = modifiers.desc.as_ref().map(|(tcx, desc)| {
235284
let tcx = tcx.as_ref().map(|t| quote! { #t }).unwrap_or(quote! { _ });
236285
quote! {
237286
fn describe(
@@ -266,7 +315,8 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
266315

267316
for group in groups.0 {
268317
let mut group_stream = quote! {};
269-
for query in &group.queries.0 {
318+
for mut query in group.queries.0 {
319+
let modifiers = process_modifiers(&mut query);
270320
let name = &query.name;
271321
let arg = &query.arg;
272322
let result_full = &query.result;
@@ -275,18 +325,19 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
275325
_ => quote! { #result_full },
276326
};
277327

278-
// Look for a fatal_cycle modifier to pass on
279-
let fatal_cycle = query.attrs.0.iter().find_map(|attr| match attr {
280-
QueryModifier::FatalCycle => Some(()),
281-
_ => None,
282-
}).map(|_| quote! { fatal_cycle }).unwrap_or(quote! {});
328+
// Pass on the fatal_cycle modifier
329+
let fatal_cycle = if modifiers.fatal_cycle {
330+
quote! { fatal_cycle }
331+
} else {
332+
quote! {}
333+
};
283334

284335
// Add the query to the group
285336
group_stream.extend(quote! {
286337
[#fatal_cycle] fn #name: #name(#arg) #result,
287338
});
288339

289-
add_query_description_impl(query, &mut query_description_stream);
340+
add_query_description_impl(&query, modifiers, &mut query_description_stream);
290341

291342
// Create a dep node for the query
292343
dep_node_def_stream.extend(quote! {

0 commit comments

Comments
 (0)