@@ -27,21 +27,25 @@ use syntax_pos::{Span, DUMMY_SP};
2727
2828use deriving;
2929
30+ const PROC_MACRO_KINDS : [ & ' static str ; 3 ] =
31+ [ "proc_macro_derive" , "proc_macro_attribute" , "proc_macro" ] ;
32+
3033struct ProcMacroDerive {
3134 trait_name : ast:: Name ,
3235 function_name : Ident ,
3336 span : Span ,
3437 attrs : Vec < ast:: Name > ,
3538}
3639
37- struct AttrProcMacro {
40+ struct ProcMacroDef {
3841 function_name : Ident ,
3942 span : Span ,
4043}
4144
4245struct CollectProcMacros < ' a > {
4346 derives : Vec < ProcMacroDerive > ,
44- attr_macros : Vec < AttrProcMacro > ,
47+ attr_macros : Vec < ProcMacroDef > ,
48+ bang_macros : Vec < ProcMacroDef > ,
4549 in_root : bool ,
4650 handler : & ' a errors:: Handler ,
4751 is_proc_macro_crate : bool ,
@@ -58,17 +62,18 @@ pub fn modify(sess: &ParseSess,
5862 let ecfg = ExpansionConfig :: default ( "proc_macro" . to_string ( ) ) ;
5963 let mut cx = ExtCtxt :: new ( sess, ecfg, resolver) ;
6064
61- let ( derives, attr_macros) = {
65+ let ( derives, attr_macros, bang_macros ) = {
6266 let mut collect = CollectProcMacros {
6367 derives : Vec :: new ( ) ,
6468 attr_macros : Vec :: new ( ) ,
69+ bang_macros : Vec :: new ( ) ,
6570 in_root : true ,
6671 handler : handler,
6772 is_proc_macro_crate : is_proc_macro_crate,
6873 is_test_crate : is_test_crate,
6974 } ;
7075 visit:: walk_crate ( & mut collect, & krate) ;
71- ( collect. derives , collect. attr_macros )
76+ ( collect. derives , collect. attr_macros , collect . bang_macros )
7277 } ;
7378
7479 if !is_proc_macro_crate {
@@ -83,7 +88,7 @@ pub fn modify(sess: &ParseSess,
8388 return krate;
8489 }
8590
86- krate. module . items . push ( mk_registrar ( & mut cx, & derives, & attr_macros) ) ;
91+ krate. module . items . push ( mk_registrar ( & mut cx, & derives, & attr_macros, & bang_macros ) ) ;
8792
8893 if krate. exported_macros . len ( ) > 0 {
8994 handler. err ( "cannot export macro_rules! macros from a `proc-macro` \
@@ -93,6 +98,10 @@ pub fn modify(sess: &ParseSess,
9398 return krate
9499}
95100
101+ fn is_proc_macro_attr ( attr : & ast:: Attribute ) -> bool {
102+ PROC_MACRO_KINDS . iter ( ) . any ( |kind| attr. check_name ( kind) )
103+ }
104+
96105impl < ' a > CollectProcMacros < ' a > {
97106 fn check_not_pub_in_root ( & self , vis : & ast:: Visibility , sp : Span ) {
98107 if self . is_proc_macro_crate &&
@@ -196,12 +205,12 @@ impl<'a> CollectProcMacros<'a> {
196205 fn collect_attr_proc_macro ( & mut self , item : & ' a ast:: Item , attr : & ' a ast:: Attribute ) {
197206 if let Some ( _) = attr. meta_item_list ( ) {
198207 self . handler . span_err ( attr. span , "`#[proc_macro_attribute]` attribute
199- cannot contain any meta items " ) ;
208+ does not take any arguments " ) ;
200209 return ;
201210 }
202211
203212 if self . in_root && item. vis == ast:: Visibility :: Public {
204- self . attr_macros . push ( AttrProcMacro {
213+ self . attr_macros . push ( ProcMacroDef {
205214 span : item. span ,
206215 function_name : item. ident ,
207216 } ) ;
@@ -215,6 +224,29 @@ impl<'a> CollectProcMacros<'a> {
215224 self . handler . span_err ( item. span , msg) ;
216225 }
217226 }
227+
228+ fn collect_bang_proc_macro ( & mut self , item : & ' a ast:: Item , attr : & ' a ast:: Attribute ) {
229+ if let Some ( _) = attr. meta_item_list ( ) {
230+ self . handler . span_err ( attr. span , "`#[proc_macro]` attribute
231+ does not take any arguments" ) ;
232+ return ;
233+ }
234+
235+ if self . in_root && item. vis == ast:: Visibility :: Public {
236+ self . bang_macros . push ( ProcMacroDef {
237+ span : item. span ,
238+ function_name : item. ident ,
239+ } ) ;
240+ } else {
241+ let msg = if !self . in_root {
242+ "functions tagged with `#[proc_macro]` must \
243+ currently reside in the root of the crate"
244+ } else {
245+ "functions tagged with `#[proc_macro]` must be `pub`"
246+ } ;
247+ self . handler . span_err ( item. span , msg) ;
248+ }
249+ }
218250}
219251
220252impl < ' a > Visitor < ' a > for CollectProcMacros < ' a > {
@@ -232,7 +264,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
232264 let mut found_attr: Option < & ' a ast:: Attribute > = None ;
233265
234266 for attr in & item. attrs {
235- if attr . check_name ( "proc_macro_derive" ) || attr. check_name ( "proc_macro_attribute" ) {
267+ if is_proc_macro_attr ( & attr) {
236268 if let Some ( prev_attr) = found_attr {
237269 let msg = if attr. name ( ) == prev_attr. name ( ) {
238270 format ! ( "Only one `#[{}]` attribute is allowed on any given function" ,
@@ -285,6 +317,8 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
285317 self . collect_custom_derive ( item, attr) ;
286318 } else if attr. check_name ( "proc_macro_attribute" ) {
287319 self . collect_attr_proc_macro ( item, attr) ;
320+ } else if attr. check_name ( "proc_macro" ) {
321+ self . collect_bang_proc_macro ( item, attr) ;
288322 } ;
289323
290324 visit:: walk_item ( self , item) ;
@@ -320,7 +354,8 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
320354// }
321355fn mk_registrar ( cx : & mut ExtCtxt ,
322356 custom_derives : & [ ProcMacroDerive ] ,
323- custom_attrs : & [ AttrProcMacro ] ) -> P < ast:: Item > {
357+ custom_attrs : & [ ProcMacroDef ] ,
358+ custom_macros : & [ ProcMacroDef ] ) -> P < ast:: Item > {
324359 let eid = cx. codemap ( ) . record_expansion ( ExpnInfo {
325360 call_site : DUMMY_SP ,
326361 callee : NameAndSpan {
@@ -342,6 +377,7 @@ fn mk_registrar(cx: &mut ExtCtxt,
342377 let registrar = Ident :: from_str ( "registrar" ) ;
343378 let register_custom_derive = Ident :: from_str ( "register_custom_derive" ) ;
344379 let register_attr_proc_macro = Ident :: from_str ( "register_attr_proc_macro" ) ;
380+ let register_bang_proc_macro = Ident :: from_str ( "register_bang_proc_macro" ) ;
345381
346382 let mut stmts = custom_derives. iter ( ) . map ( |cd| {
347383 let path = cx. path_global ( cd. span , vec ! [ cd. function_name] ) ;
@@ -371,6 +407,18 @@ fn mk_registrar(cx: &mut ExtCtxt,
371407 vec ! [ registrar, name, cx. expr_path( path) ] ) )
372408 } ) ) ;
373409
410+ stmts. extend ( custom_macros. iter ( ) . map ( |cm| {
411+ let name = cx. expr_str ( cm. span , cm. function_name . name ) ;
412+ let path = cx. path_global ( cm. span , vec ! [ cm. function_name] ) ;
413+ let registrar = cx. expr_ident ( cm. span , registrar) ;
414+
415+ let ufcs_path = cx. path ( span,
416+ vec ! [ proc_macro, __internal, registry, register_bang_proc_macro] ) ;
417+
418+ cx. stmt_expr ( cx. expr_call ( span, cx. expr_path ( ufcs_path) ,
419+ vec ! [ registrar, name, cx. expr_path( path) ] ) )
420+ } ) ) ;
421+
374422 let path = cx. path ( span, vec ! [ proc_macro, __internal, registry] ) ;
375423 let registrar_path = cx. ty_path ( path) ;
376424 let arg_ty = cx. ty_rptr ( span, registrar_path, None , ast:: Mutability :: Mutable ) ;
0 commit comments