@@ -30,6 +30,7 @@ struct CustomDerive {
3030 trait_name : InternedString ,
3131 function_name : Ident ,
3232 span : Span ,
33+ attrs : Vec < InternedString > ,
3334}
3435
3536struct CollectCustomDerives < ' a > {
@@ -144,7 +145,8 @@ impl<'a> Visitor for CollectCustomDerives<'a> {
144145 }
145146
146147 // 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, ..))]`
148150 let list = match attr. meta_item_list ( ) {
149151 Some ( list) => list,
150152 None => {
@@ -154,38 +156,69 @@ impl<'a> Visitor for CollectCustomDerives<'a> {
154156 return
155157 }
156158 } ;
157- if list. len ( ) != 1 {
159+ if list. len ( ) != 1 && list . len ( ) != 2 {
158160 self . handler . span_err ( attr. span ( ) ,
159- "attribute must only have one argument " ) ;
161+ "attribute must have either one or two arguments " ) ;
160162 return
161163 }
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 ( ) {
164167 Some ( name) => name,
165168 _ => {
166- self . handler . span_err ( attr . span ( ) , "not a meta item" ) ;
169+ self . handler . span_err ( trait_attr . span ( ) , "not a meta item" ) ;
167170 return
168171 }
169172 } ;
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" ) ;
172175 }
173176
174177 if deriving:: is_builtin_trait ( & trait_name) {
175- self . handler . span_err ( attr . span ( ) ,
178+ self . handler . span_err ( trait_attr . span ( ) ,
176179 "cannot override a built-in #[derive] mode" ) ;
177180 }
178181
179182 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 ( ) ,
181184 "derive mode defined twice in this crate" ) ;
182185 }
183186
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+
184216 if self . in_root {
185217 self . derives . push ( CustomDerive {
186218 span : item. span ,
187219 trait_name : trait_name,
188220 function_name : item. ident ,
221+ attrs : proc_attrs,
189222 } ) ;
190223 } else {
191224 let msg = "functions tagged with `#[proc_macro_derive]` must \
@@ -219,8 +252,8 @@ impl<'a> Visitor for CollectCustomDerives<'a> {
219252//
220253// #[plugin_registrar]
221254// 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"] );
224257// // ...
225258// }
226259// }
@@ -249,14 +282,18 @@ fn mk_registrar(cx: &mut ExtCtxt,
249282 let stmts = custom_derives. iter ( ) . map ( |cd| {
250283 let path = cx. path_global ( cd. span , vec ! [ cd. function_name] ) ;
251284 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) | {
254291 let registrar = cx. expr_ident ( span, registrar) ;
255292 let ufcs_path = cx. path ( span, vec ! [ proc_macro, __internal, registry,
256293 register_custom_derive] ) ;
257294 cx. expr_call ( span,
258295 cx. expr_path ( ufcs_path) ,
259- vec ! [ registrar, trait_name, cx. expr_path( path) ] )
296+ vec ! [ registrar, trait_name, cx. expr_path( path) , attrs ] )
260297 } ) . map ( |expr| {
261298 cx. stmt_expr ( expr)
262299 } ) . collect :: < Vec < _ > > ( ) ;
0 commit comments