@@ -30,6 +30,7 @@ struct CustomDerive {
30
30
trait_name : InternedString ,
31
31
function_name : Ident ,
32
32
span : Span ,
33
+ attrs : Vec < InternedString > ,
33
34
}
34
35
35
36
struct CollectCustomDerives < ' a > {
@@ -144,7 +145,8 @@ impl<'a> Visitor for CollectCustomDerives<'a> {
144
145
}
145
146
146
147
// Once we've located the `#[proc_macro_derive]` attribute, verify
147
- // that it's of the form `#[proc_macro_derive(Foo)]`
148
+ // that it's of the form `#[proc_macro_derive(Foo)]` or
149
+ // `#[proc_macro_derive(Foo, attributes(A, ..))]`
148
150
let list = match attr. meta_item_list ( ) {
149
151
Some ( list) => list,
150
152
None => {
@@ -154,38 +156,69 @@ impl<'a> Visitor for CollectCustomDerives<'a> {
154
156
return
155
157
}
156
158
} ;
157
- if list. len ( ) != 1 {
159
+ if list. len ( ) != 1 && list . len ( ) != 2 {
158
160
self . handler . span_err ( attr. span ( ) ,
159
- "attribute must only have one argument " ) ;
161
+ "attribute must have either one or two arguments " ) ;
160
162
return
161
163
}
162
- let attr = & list[ 0 ] ;
163
- let trait_name = match attr. name ( ) {
164
+ let trait_attr = & list[ 0 ] ;
165
+ let attributes_attr = list. get ( 1 ) ;
166
+ let trait_name = match trait_attr. name ( ) {
164
167
Some ( name) => name,
165
168
_ => {
166
- self . handler . span_err ( attr . span ( ) , "not a meta item" ) ;
169
+ self . handler . span_err ( trait_attr . span ( ) , "not a meta item" ) ;
167
170
return
168
171
}
169
172
} ;
170
- if !attr . is_word ( ) {
171
- self . handler . span_err ( attr . span ( ) , "must only be one word" ) ;
173
+ if !trait_attr . is_word ( ) {
174
+ self . handler . span_err ( trait_attr . span ( ) , "must only be one word" ) ;
172
175
}
173
176
174
177
if deriving:: is_builtin_trait ( & trait_name) {
175
- self . handler . span_err ( attr . span ( ) ,
178
+ self . handler . span_err ( trait_attr . span ( ) ,
176
179
"cannot override a built-in #[derive] mode" ) ;
177
180
}
178
181
179
182
if self . derives . iter ( ) . any ( |d| d. trait_name == trait_name) {
180
- self . handler . span_err ( attr . span ( ) ,
183
+ self . handler . span_err ( trait_attr . span ( ) ,
181
184
"derive mode defined twice in this crate" ) ;
182
185
}
183
186
187
+ let proc_attrs: Vec < _ > = if let Some ( attr) = attributes_attr {
188
+ if !attr. check_name ( "attributes" ) {
189
+ self . handler . span_err ( attr. span ( ) , "second argument must be `attributes`" )
190
+ }
191
+ attr. meta_item_list ( ) . unwrap_or_else ( || {
192
+ self . handler . span_err ( attr. span ( ) ,
193
+ "attribute must be of form: \
194
+ `attributes(foo, bar)`") ;
195
+ & [ ]
196
+ } ) . into_iter ( ) . filter_map ( |attr| {
197
+ let name = match attr. name ( ) {
198
+ Some ( name) => name,
199
+ _ => {
200
+ self . handler . span_err ( attr. span ( ) , "not a meta item" ) ;
201
+ return None ;
202
+ } ,
203
+ } ;
204
+
205
+ if !attr. is_word ( ) {
206
+ self . handler . span_err ( attr. span ( ) , "must only be one word" ) ;
207
+ return None ;
208
+ }
209
+
210
+ Some ( name)
211
+ } ) . collect ( )
212
+ } else {
213
+ Vec :: new ( )
214
+ } ;
215
+
184
216
if self . in_root {
185
217
self . derives . push ( CustomDerive {
186
218
span : item. span ,
187
219
trait_name : trait_name,
188
220
function_name : item. ident ,
221
+ attrs : proc_attrs,
189
222
} ) ;
190
223
} else {
191
224
let msg = "functions tagged with `#[proc_macro_derive]` must \
@@ -219,8 +252,8 @@ impl<'a> Visitor for CollectCustomDerives<'a> {
219
252
//
220
253
// #[plugin_registrar]
221
254
// fn registrar(registrar: &mut Registry) {
222
- // registrar.register_custom_derive($name_trait1, ::$name1);
223
- // registrar.register_custom_derive($name_trait2, ::$name2);
255
+ // registrar.register_custom_derive($name_trait1, ::$name1, &[] );
256
+ // registrar.register_custom_derive($name_trait2, ::$name2, &["attribute_name"] );
224
257
// // ...
225
258
// }
226
259
// }
@@ -249,14 +282,18 @@ fn mk_registrar(cx: &mut ExtCtxt,
249
282
let stmts = custom_derives. iter ( ) . map ( |cd| {
250
283
let path = cx. path_global ( cd. span , vec ! [ cd. function_name] ) ;
251
284
let trait_name = cx. expr_str ( cd. span , cd. trait_name . clone ( ) ) ;
252
- ( path, trait_name)
253
- } ) . map ( |( path, trait_name) | {
285
+ let attrs = cx. expr_vec_slice (
286
+ span,
287
+ cd. attrs . iter ( ) . map ( |s| cx. expr_str ( cd. span , s. clone ( ) ) ) . collect :: < Vec < _ > > ( )
288
+ ) ;
289
+ ( path, trait_name, attrs)
290
+ } ) . map ( |( path, trait_name, attrs) | {
254
291
let registrar = cx. expr_ident ( span, registrar) ;
255
292
let ufcs_path = cx. path ( span, vec ! [ proc_macro, __internal, registry,
256
293
register_custom_derive] ) ;
257
294
cx. expr_call ( span,
258
295
cx. expr_path ( ufcs_path) ,
259
- vec ! [ registrar, trait_name, cx. expr_path( path) ] )
296
+ vec ! [ registrar, trait_name, cx. expr_path( path) , attrs ] )
260
297
} ) . map ( |expr| {
261
298
cx. stmt_expr ( expr)
262
299
} ) . collect :: < Vec < _ > > ( ) ;
0 commit comments