1
1
use proc_macro:: TokenStream ;
2
- use proc_macro2:: Span ;
3
2
use syn:: {
4
3
Token , Ident , Type , Attribute , ReturnType , Expr , Block , Error ,
5
4
braced, parenthesized, parse_macro_input,
@@ -21,8 +20,8 @@ struct IdentOrWild(Ident);
21
20
impl Parse for IdentOrWild {
22
21
fn parse ( input : ParseStream < ' _ > ) -> Result < Self > {
23
22
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 ( ) ) )
26
25
} else {
27
26
IdentOrWild ( input. parse ( ) ?)
28
27
} )
@@ -31,7 +30,7 @@ impl Parse for IdentOrWild {
31
30
32
31
/// A modifier for a query
33
32
enum QueryModifier {
34
- /// The description of the query
33
+ /// The description of the query.
35
34
Desc ( Option < Ident > , Punctuated < Expr , Token ! [ , ] > ) ,
36
35
37
36
/// Cache the query to disk if the `Expr` returns true.
@@ -107,7 +106,7 @@ fn check_attributes(attrs: Vec<Attribute>) -> Result<()> {
107
106
108
107
/// A compiler query. `query ... { ... }`
109
108
struct Query {
110
- attrs : List < QueryModifier > ,
109
+ modifiers : List < QueryModifier > ,
111
110
name : Ident ,
112
111
key : IdentOrWild ,
113
112
arg : Type ,
@@ -131,10 +130,10 @@ impl Parse for Query {
131
130
// Parse the query modifiers
132
131
let content;
133
132
braced ! ( content in input) ;
134
- let attrs = content. parse ( ) ?;
133
+ let modifiers = content. parse ( ) ?;
135
134
136
135
Ok ( Query {
137
- attrs ,
136
+ modifiers ,
138
137
name,
139
138
key,
140
139
arg,
@@ -174,24 +173,76 @@ impl Parse for Group {
174
173
}
175
174
}
176
175
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
+
177
232
/// 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
+ ) {
179
238
let name = & query. name ;
180
239
let arg = & query. arg ;
181
240
let key = & query. key . 0 ;
182
241
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
-
189
242
// 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
195
246
quote ! {
196
247
#[ inline]
197
248
fn try_load_from_disk(
@@ -202,6 +253,7 @@ fn add_query_description_impl(query: &Query, impls: &mut proc_macro2::TokenStrea
202
253
}
203
254
}
204
255
} else {
256
+ // Use the default code to load the query from disk
205
257
quote ! {
206
258
#[ inline]
207
259
fn try_load_from_disk(
@@ -224,14 +276,11 @@ fn add_query_description_impl(query: &Query, impls: &mut proc_macro2::TokenStrea
224
276
}
225
277
} ) ;
226
278
227
- if cache. is_none ( ) && load_cached. is_some ( ) {
279
+ if cache. is_none ( ) && modifiers . load_cached . is_some ( ) {
228
280
panic ! ( "load_cached modifier on query `{}` without a cache modifier" , name) ;
229
281
}
230
282
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) | {
235
284
let tcx = tcx. as_ref ( ) . map ( |t| quote ! { #t } ) . unwrap_or ( quote ! { _ } ) ;
236
285
quote ! {
237
286
fn describe(
@@ -266,7 +315,8 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
266
315
267
316
for group in groups. 0 {
268
317
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) ;
270
320
let name = & query. name ;
271
321
let arg = & query. arg ;
272
322
let result_full = & query. result ;
@@ -275,18 +325,19 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
275
325
_ => quote ! { #result_full } ,
276
326
} ;
277
327
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
+ } ;
283
334
284
335
// Add the query to the group
285
336
group_stream. extend ( quote ! {
286
337
[ #fatal_cycle] fn #name: #name( #arg) #result,
287
338
} ) ;
288
339
289
- add_query_description_impl ( query, & mut query_description_stream) ;
340
+ add_query_description_impl ( & query, modifiers , & mut query_description_stream) ;
290
341
291
342
// Create a dep node for the query
292
343
dep_node_def_stream. extend ( quote ! {
0 commit comments