11use proc_macro:: TokenStream ;
2- use proc_macro2:: Span ;
32use syn:: {
43 Token , Ident , Type , Attribute , ReturnType , Expr , Block , Error ,
54 braced, parenthesized, parse_macro_input,
@@ -21,8 +20,8 @@ struct IdentOrWild(Ident);
2120impl 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
3332enum 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 ... { ... }`
109108struct 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