@@ -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 > {
@@ -133,7 +134,8 @@ impl<'a> Visitor for CollectCustomDerives<'a> {
133
134
}
134
135
135
136
// Once we've located the `#[proc_macro_derive]` attribute, verify
136
- // that it's of the form `#[proc_macro_derive(Foo)]`
137
+ // that it's of the form `#[proc_macro_derive(Foo)]` or
138
+ // `#[proc_macro_derive(Foo, attributes(A, ..))]`
137
139
let list = match attr. meta_item_list ( ) {
138
140
Some ( list) => list,
139
141
None => {
@@ -143,38 +145,69 @@ impl<'a> Visitor for CollectCustomDerives<'a> {
143
145
return
144
146
}
145
147
} ;
146
- if list. len ( ) != 1 {
148
+ if list. len ( ) != 1 && list . len ( ) != 2 {
147
149
self . handler . span_err ( attr. span ( ) ,
148
- "attribute must only have one argument " ) ;
150
+ "attribute must have either one or two arguments " ) ;
149
151
return
150
152
}
151
- let attr = & list[ 0 ] ;
152
- let trait_name = match attr. name ( ) {
153
+ let trait_attr = & list[ 0 ] ;
154
+ let attributes_attr = list. get ( 1 ) ;
155
+ let trait_name = match trait_attr. name ( ) {
153
156
Some ( name) => name,
154
157
_ => {
155
- self . handler . span_err ( attr . span ( ) , "not a meta item" ) ;
158
+ self . handler . span_err ( trait_attr . span ( ) , "not a meta item" ) ;
156
159
return
157
160
}
158
161
} ;
159
- if !attr . is_word ( ) {
160
- self . handler . span_err ( attr . span ( ) , "must only be one word" ) ;
162
+ if !trait_attr . is_word ( ) {
163
+ self . handler . span_err ( trait_attr . span ( ) , "must only be one word" ) ;
161
164
}
162
165
163
166
if deriving:: is_builtin_trait ( & trait_name) {
164
- self . handler . span_err ( attr . span ( ) ,
167
+ self . handler . span_err ( trait_attr . span ( ) ,
165
168
"cannot override a built-in #[derive] mode" ) ;
166
169
}
167
170
168
171
if self . derives . iter ( ) . any ( |d| d. trait_name == trait_name) {
169
- self . handler . span_err ( attr . span ( ) ,
172
+ self . handler . span_err ( trait_attr . span ( ) ,
170
173
"derive mode defined twice in this crate" ) ;
171
174
}
172
175
176
+ let proc_attrs: Vec < _ > = if let Some ( attr) = attributes_attr {
177
+ if !attr. check_name ( "attributes" ) {
178
+ self . handler . span_err ( attr. span ( ) , "second argument must be `attributes`" )
179
+ }
180
+ attr. meta_item_list ( ) . unwrap_or_else ( || {
181
+ self . handler . span_err ( attr. span ( ) ,
182
+ "attribute must be of form: \
183
+ `attributes(foo, bar)`") ;
184
+ & [ ]
185
+ } ) . into_iter ( ) . filter_map ( |attr| {
186
+ let name = match attr. name ( ) {
187
+ Some ( name) => name,
188
+ _ => {
189
+ self . handler . span_err ( attr. span ( ) , "not a meta item" ) ;
190
+ return None ;
191
+ } ,
192
+ } ;
193
+
194
+ if !attr. is_word ( ) {
195
+ self . handler . span_err ( attr. span ( ) , "must only be one word" ) ;
196
+ return None ;
197
+ }
198
+
199
+ Some ( name)
200
+ } ) . collect ( )
201
+ } else {
202
+ Vec :: new ( )
203
+ } ;
204
+
173
205
if self . in_root {
174
206
self . derives . push ( CustomDerive {
175
207
span : item. span ,
176
208
trait_name : trait_name,
177
209
function_name : item. ident ,
210
+ attrs : proc_attrs,
178
211
} ) ;
179
212
} else {
180
213
let msg = "functions tagged with `#[proc_macro_derive]` must \
@@ -208,8 +241,8 @@ impl<'a> Visitor for CollectCustomDerives<'a> {
208
241
//
209
242
// #[plugin_registrar]
210
243
// fn registrar(registrar: &mut Registry) {
211
- // registrar.register_custom_derive($name_trait1, ::$name1);
212
- // registrar.register_custom_derive($name_trait2, ::$name2);
244
+ // registrar.register_custom_derive($name_trait1, ::$name1, &[] );
245
+ // registrar.register_custom_derive($name_trait2, ::$name2, &["attribute_name"] );
213
246
// // ...
214
247
// }
215
248
// }
@@ -238,14 +271,18 @@ fn mk_registrar(cx: &mut ExtCtxt,
238
271
let stmts = custom_derives. iter ( ) . map ( |cd| {
239
272
let path = cx. path_global ( cd. span , vec ! [ cd. function_name] ) ;
240
273
let trait_name = cx. expr_str ( cd. span , cd. trait_name . clone ( ) ) ;
241
- ( path, trait_name)
242
- } ) . map ( |( path, trait_name) | {
274
+ let attrs = cx. expr_vec_slice (
275
+ span,
276
+ cd. attrs . iter ( ) . map ( |s| cx. expr_str ( cd. span , s. clone ( ) ) ) . collect :: < Vec < _ > > ( )
277
+ ) ;
278
+ ( path, trait_name, attrs)
279
+ } ) . map ( |( path, trait_name, attrs) | {
243
280
let registrar = cx. expr_ident ( span, registrar) ;
244
281
let ufcs_path = cx. path ( span, vec ! [ proc_macro, __internal, registry,
245
282
register_custom_derive] ) ;
246
283
cx. expr_call ( span,
247
284
cx. expr_path ( ufcs_path) ,
248
- vec ! [ registrar, trait_name, cx. expr_path( path) ] )
285
+ vec ! [ registrar, trait_name, cx. expr_path( path) , attrs ] )
249
286
} ) . map ( |expr| {
250
287
cx. stmt_expr ( expr)
251
288
} ) . collect :: < Vec < _ > > ( ) ;
0 commit comments