1010
1111use rustc:: middle:: allocator:: AllocatorKind ;
1212use rustc_errors;
13- use syntax:: ast:: { Attribute , Crate , LitKind , StrStyle } ;
14- use syntax:: ast:: { Arg , FnHeader , Generics , Mac , Mutability , Ty , Unsafety } ;
15- use syntax:: ast:: { self , Expr , Ident , Item , ItemKind , TyKind , VisibilityKind } ;
16- use syntax:: attr;
17- use syntax:: codemap:: respan;
18- use syntax:: codemap:: { ExpnInfo , MacroAttribute } ;
19- use syntax:: ext:: base:: ExtCtxt ;
20- use syntax:: ext:: base:: Resolver ;
21- use syntax:: ext:: build:: AstBuilder ;
22- use syntax:: ext:: expand:: ExpansionConfig ;
23- use syntax:: ext:: hygiene:: { self , Mark , SyntaxContext } ;
24- use syntax:: fold:: { self , Folder } ;
25- use syntax:: parse:: ParseSess ;
26- use syntax:: ptr:: P ;
27- use syntax:: symbol:: Symbol ;
28- use syntax:: util:: small_vector:: SmallVector ;
29- use syntax_pos:: { Span , DUMMY_SP } ;
13+ use syntax:: {
14+ ast:: {
15+ self , Arg , Attribute , Crate , Expr , FnHeader , Generics , Ident , Item , ItemKind ,
16+ LitKind , Mac , Mod , Mutability , StrStyle , Ty , TyKind , Unsafety , VisibilityKind ,
17+ } ,
18+ attr,
19+ codemap:: {
20+ respan, ExpnInfo , MacroAttribute ,
21+ } ,
22+ ext:: {
23+ base:: { ExtCtxt , Resolver } ,
24+ build:: AstBuilder ,
25+ expand:: ExpansionConfig ,
26+ hygiene:: { self , Mark , SyntaxContext } ,
27+ } ,
28+ fold:: { self , Folder } ,
29+ parse:: ParseSess ,
30+ ptr:: P ,
31+ symbol:: Symbol ,
32+ util:: small_vector:: SmallVector ,
33+ } ;
34+ use syntax_pos:: Span ;
3035
3136use { AllocatorMethod , AllocatorTy , ALLOCATOR_METHODS } ;
3237
3338pub fn modify (
3439 sess : & ParseSess ,
3540 resolver : & mut Resolver ,
3641 krate : Crate ,
42+ crate_name : String ,
3743 handler : & rustc_errors:: Handler ,
3844) -> ast:: Crate {
3945 ExpandAllocatorDirectives {
4046 handler,
4147 sess,
4248 resolver,
4349 found : false ,
50+ crate_name : Some ( crate_name) ,
51+ in_submod : -1 , // -1 to account for the "root" module
4452 } . fold_crate ( krate)
4553}
4654
@@ -49,10 +57,17 @@ struct ExpandAllocatorDirectives<'a> {
4957 handler : & ' a rustc_errors:: Handler ,
5058 sess : & ' a ParseSess ,
5159 resolver : & ' a mut Resolver ,
60+ crate_name : Option < String > ,
61+
62+ // For now, we disallow `global_allocator` in submodules because hygiene is hard. Keep track of
63+ // whether we are in a submodule or not. If `in_submod > 0` we are in a submodule.
64+ in_submod : isize ,
5265}
5366
5467impl < ' a > Folder for ExpandAllocatorDirectives < ' a > {
5568 fn fold_item ( & mut self , item : P < Item > ) -> SmallVector < P < Item > > {
69+ debug ! ( "in submodule {}" , self . in_submod) ;
70+
5671 let name = if attr:: contains_name ( & item. attrs , "global_allocator" ) {
5772 "global_allocator"
5873 } else {
@@ -67,57 +82,93 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> {
6782 }
6883 }
6984
85+ if self . in_submod > 0 {
86+ self . handler
87+ . span_err ( item. span , "`global_allocator` cannot be used in submodules" ) ;
88+ return SmallVector :: one ( item) ;
89+ }
90+
7091 if self . found {
71- self . handler . span_err (
72- item. span ,
73- "cannot define more than one \
74- #[global_allocator]",
75- ) ;
92+ self . handler
93+ . span_err ( item. span , "cannot define more than one #[global_allocator]" ) ;
7694 return SmallVector :: one ( item) ;
7795 }
7896 self . found = true ;
7997
98+ // Create a fresh Mark for the new macro expansion we are about to do
8099 let mark = Mark :: fresh ( Mark :: root ( ) ) ;
81100 mark. set_expn_info ( ExpnInfo {
82- call_site : DUMMY_SP ,
101+ call_site : item . span , // use the call site of the static
83102 def_site : None ,
84103 format : MacroAttribute ( Symbol :: intern ( name) ) ,
85104 allow_internal_unstable : true ,
86105 allow_internal_unsafe : false ,
87106 edition : hygiene:: default_edition ( ) ,
88107 } ) ;
108+
109+ // Tie the span to the macro expansion info we just created
89110 let span = item. span . with_ctxt ( SyntaxContext :: empty ( ) . apply_mark ( mark) ) ;
90- let ecfg = ExpansionConfig :: default ( name. to_string ( ) ) ;
111+
112+ // Create an expansion config
113+ let ecfg = ExpansionConfig :: default ( self . crate_name . take ( ) . unwrap ( ) ) ;
114+
115+ // Generate a bunch of new items using the AllocFnFactory
91116 let mut f = AllocFnFactory {
92117 span,
93118 kind : AllocatorKind :: Global ,
94119 global : item. ident ,
95120 core : Ident :: from_str ( "core" ) ,
96121 cx : ExtCtxt :: new ( self . sess , ecfg, self . resolver ) ,
97122 } ;
123+
124+ // We will generate a new submodule. To `use` the static from that module, we need to get
125+ // the `super::...` path.
98126 let super_path = f. cx . path ( f. span , vec ! [ Ident :: from_str( "super" ) , f. global] ) ;
127+
128+ // Generate the items in the submodule
99129 let mut items = vec ! [
130+ // import `core` to use allocators
100131 f. cx. item_extern_crate( f. span, f. core) ,
132+ // `use` the `global_allocator` in `super`
101133 f. cx. item_use_simple(
102134 f. span,
103135 respan( f. span. shrink_to_lo( ) , VisibilityKind :: Inherited ) ,
104136 super_path,
105137 ) ,
106138 ] ;
107- for method in ALLOCATOR_METHODS {
108- items. push ( f. allocator_fn ( method) ) ;
109- }
139+
140+ // Add the allocator methods to the submodule
141+ items. extend (
142+ ALLOCATOR_METHODS
143+ . iter ( )
144+ . map ( |method| f. allocator_fn ( method) ) ,
145+ ) ;
146+
147+ // Generate the submodule itself
110148 let name = f. kind . fn_name ( "allocator_abi" ) ;
111149 let allocator_abi = Ident :: with_empty_ctxt ( Symbol :: gensym ( & name) ) ;
112150 let module = f. cx . item_mod ( span, span, allocator_abi, Vec :: new ( ) , items) ;
113151 let module = f. cx . monotonic_expander ( ) . fold_item ( module) . pop ( ) . unwrap ( ) ;
114152
115- let mut ret = SmallVector :: new ( ) ;
153+ // Return the item and new submodule
154+ let mut ret = SmallVector :: with_capacity ( 2 ) ;
116155 ret. push ( item) ;
117156 ret. push ( module) ;
157+
118158 return ret;
119159 }
120160
161+ // If we enter a submodule, take note.
162+ fn fold_mod ( & mut self , m : Mod ) -> Mod {
163+ debug ! ( "enter submodule" ) ;
164+ self . in_submod += 1 ;
165+ let ret = fold:: noop_fold_mod ( m, self ) ;
166+ self . in_submod -= 1 ;
167+ debug ! ( "exit submodule" ) ;
168+ ret
169+ }
170+
171+ // `fold_mac` is disabled by default. Enable it here.
121172 fn fold_mac ( & mut self , mac : Mac ) -> Mac {
122173 fold:: noop_fold_mac ( mac, self )
123174 }
0 commit comments