@@ -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 > {
@@ -133,7 +134,8 @@ impl<'a> Visitor for CollectCustomDerives<'a> {
133134 }
134135
135136 // 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, ..))]`
137139 let list = match attr. meta_item_list ( ) {
138140 Some ( list) => list,
139141 None => {
@@ -143,38 +145,69 @@ impl<'a> Visitor for CollectCustomDerives<'a> {
143145 return
144146 }
145147 } ;
146- if list. len ( ) != 1 {
148+ if list. len ( ) != 1 && list . len ( ) != 2 {
147149 self . handler . span_err ( attr. span ( ) ,
148- "attribute must only have one argument " ) ;
150+ "attribute must have either one or two arguments " ) ;
149151 return
150152 }
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 ( ) {
153156 Some ( name) => name,
154157 _ => {
155- self . handler . span_err ( attr . span ( ) , "not a meta item" ) ;
158+ self . handler . span_err ( trait_attr . span ( ) , "not a meta item" ) ;
156159 return
157160 }
158161 } ;
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" ) ;
161164 }
162165
163166 if deriving:: is_builtin_trait ( & trait_name) {
164- self . handler . span_err ( attr . span ( ) ,
167+ self . handler . span_err ( trait_attr . span ( ) ,
165168 "cannot override a built-in #[derive] mode" ) ;
166169 }
167170
168171 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 ( ) ,
170173 "derive mode defined twice in this crate" ) ;
171174 }
172175
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+
173205 if self . in_root {
174206 self . derives . push ( CustomDerive {
175207 span : item. span ,
176208 trait_name : trait_name,
177209 function_name : item. ident ,
210+ attrs : proc_attrs,
178211 } ) ;
179212 } else {
180213 let msg = "functions tagged with `#[proc_macro_derive]` must \
@@ -208,8 +241,8 @@ impl<'a> Visitor for CollectCustomDerives<'a> {
208241//
209242// #[plugin_registrar]
210243// 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"] );
213246// // ...
214247// }
215248// }
@@ -238,14 +271,18 @@ fn mk_registrar(cx: &mut ExtCtxt,
238271 let stmts = custom_derives. iter ( ) . map ( |cd| {
239272 let path = cx. path_global ( cd. span , vec ! [ cd. function_name] ) ;
240273 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) | {
243280 let registrar = cx. expr_ident ( span, registrar) ;
244281 let ufcs_path = cx. path ( span, vec ! [ proc_macro, __internal, registry,
245282 register_custom_derive] ) ;
246283 cx. expr_call ( span,
247284 cx. expr_path ( ufcs_path) ,
248- vec ! [ registrar, trait_name, cx. expr_path( path) ] )
285+ vec ! [ registrar, trait_name, cx. expr_path( path) , attrs ] )
249286 } ) . map ( |expr| {
250287 cx. stmt_expr ( expr)
251288 } ) . collect :: < Vec < _ > > ( ) ;
0 commit comments