1111use rustc:: middle:: allocator:: AllocatorKind ;
1212use rustc_errors;
1313use rustc_target:: spec:: abi:: Abi ;
14- use syntax:: ast:: { Attribute , Crate , LitKind , StrStyle } ;
15- use syntax:: ast:: { Arg , Constness , Generics , Mac , Mutability , Ty , Unsafety } ;
16- use syntax:: ast:: { self , Expr , Ident , Item , ItemKind , TyKind , VisibilityKind } ;
17- use syntax:: attr;
18- use syntax:: codemap:: { dummy_spanned, respan} ;
19- use syntax:: codemap:: { ExpnInfo , MacroAttribute , NameAndSpan } ;
20- use syntax:: ext:: base:: ExtCtxt ;
21- use syntax:: ext:: base:: Resolver ;
22- use syntax:: ext:: build:: AstBuilder ;
23- use syntax:: ext:: expand:: ExpansionConfig ;
24- use syntax:: ext:: hygiene:: { self , Mark , SyntaxContext } ;
25- use syntax:: fold:: { self , Folder } ;
26- use syntax:: parse:: ParseSess ;
27- use syntax:: ptr:: P ;
28- use syntax:: symbol:: Symbol ;
29- use syntax:: util:: small_vector:: SmallVector ;
30- use syntax_pos:: { Span , DUMMY_SP } ;
14+ use syntax:: {
15+ ast:: {
16+ self , Arg , Attribute , Constness , Crate , Expr , Generics , Ident , Item , ItemKind ,
17+ LitKind , Mac , Mod , Mutability , StrStyle , Ty , TyKind , Unsafety , VisibilityKind ,
18+ } ,
19+ attr,
20+ codemap:: {
21+ dummy_spanned, respan, ExpnInfo , MacroAttribute , NameAndSpan ,
22+ } ,
23+ ext:: {
24+ base:: { ExtCtxt , Resolver } ,
25+ build:: AstBuilder ,
26+ expand:: ExpansionConfig ,
27+ hygiene:: { self , Mark , SyntaxContext } ,
28+ } ,
29+ fold:: { self , Folder } ,
30+ parse:: ParseSess ,
31+ ptr:: P ,
32+ symbol:: Symbol ,
33+ util:: small_vector:: SmallVector ,
34+ } ;
35+ use syntax_pos:: Span ;
3136
3237use { AllocatorMethod , AllocatorTy , ALLOCATOR_METHODS } ;
3338
3439pub fn modify (
3540 sess : & ParseSess ,
3641 resolver : & mut Resolver ,
3742 krate : Crate ,
43+ crate_name : String ,
3844 handler : & rustc_errors:: Handler ,
3945) -> ast:: Crate {
4046 ExpandAllocatorDirectives {
4147 handler,
4248 sess,
4349 resolver,
4450 found : false ,
51+ crate_name : Some ( crate_name) ,
52+ in_submod : -1 , // -1 to account for the "root" module
4553 } . fold_crate ( krate)
4654}
4755
@@ -50,10 +58,17 @@ struct ExpandAllocatorDirectives<'a> {
5058 handler : & ' a rustc_errors:: Handler ,
5159 sess : & ' a ParseSess ,
5260 resolver : & ' a mut Resolver ,
61+ crate_name : Option < String > ,
62+
63+ // For now, we disallow `global_allocator` in submodules because hygiene is hard. Keep track of
64+ // whether we are in a submodule or not. If `in_submod > 0` we are in a submodule.
65+ in_submod : isize ,
5366}
5467
5568impl < ' a > Folder for ExpandAllocatorDirectives < ' a > {
5669 fn fold_item ( & mut self , item : P < Item > ) -> SmallVector < P < Item > > {
70+ debug ! ( "in submodule {}" , self . in_submod) ;
71+
5772 let name = if attr:: contains_name ( & item. attrs , "global_allocator" ) {
5873 "global_allocator"
5974 } else {
@@ -68,19 +83,23 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> {
6883 }
6984 }
7085
86+ if self . in_submod > 0 {
87+ self . handler
88+ . span_err ( item. span , "`global_allocator` cannot be used in submodules" ) ;
89+ return SmallVector :: one ( item) ;
90+ }
91+
7192 if self . found {
72- self . handler . span_err (
73- item. span ,
74- "cannot define more than one \
75- #[global_allocator]",
76- ) ;
93+ self . handler
94+ . span_err ( item. span , "cannot define more than one #[global_allocator]" ) ;
7795 return SmallVector :: one ( item) ;
7896 }
7997 self . found = true ;
8098
99+ // Create a fresh Mark for the new macro expansion we are about to do
81100 let mark = Mark :: fresh ( Mark :: root ( ) ) ;
82101 mark. set_expn_info ( ExpnInfo {
83- call_site : DUMMY_SP ,
102+ call_site : item . span , // use the call site of the static
84103 callee : NameAndSpan {
85104 format : MacroAttribute ( Symbol :: intern ( name) ) ,
86105 span : None ,
@@ -89,38 +108,70 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> {
89108 edition : hygiene:: default_edition ( ) ,
90109 } ,
91110 } ) ;
111+
112+ // Tie the span to the macro expansion info we just created
92113 let span = item. span . with_ctxt ( SyntaxContext :: empty ( ) . apply_mark ( mark) ) ;
93- let ecfg = ExpansionConfig :: default ( name. to_string ( ) ) ;
114+
115+ // Create an expansion config
116+ let ecfg = ExpansionConfig :: default ( self . crate_name . take ( ) . unwrap ( ) ) ;
117+
118+ // Generate a bunch of new items using the AllocFnFactory
94119 let mut f = AllocFnFactory {
95120 span,
96121 kind : AllocatorKind :: Global ,
97122 global : item. ident ,
98123 core : Ident :: from_str ( "core" ) ,
99124 cx : ExtCtxt :: new ( self . sess , ecfg, self . resolver ) ,
100125 } ;
126+
127+ // We will generate a new submodule. To `use` the static from that module, we need to get
128+ // the `super::...` path.
101129 let super_path = f. cx . path ( f. span , vec ! [ Ident :: from_str( "super" ) , f. global] ) ;
130+
131+ // Generate the items in the submodule
102132 let mut items = vec ! [
133+ // import `core` to use allocators
103134 f. cx. item_extern_crate( f. span, f. core) ,
135+ // `use` the `global_allocator` in `super`
104136 f. cx. item_use_simple(
105137 f. span,
106138 respan( f. span. shrink_to_lo( ) , VisibilityKind :: Inherited ) ,
107139 super_path,
108140 ) ,
109141 ] ;
110- for method in ALLOCATOR_METHODS {
111- items. push ( f. allocator_fn ( method) ) ;
112- }
142+
143+ // Add the allocator methods to the submodule
144+ items. extend (
145+ ALLOCATOR_METHODS
146+ . iter ( )
147+ . map ( |method| f. allocator_fn ( method) ) ,
148+ ) ;
149+
150+ // Generate the submodule itself
113151 let name = f. kind . fn_name ( "allocator_abi" ) ;
114152 let allocator_abi = Ident :: with_empty_ctxt ( Symbol :: gensym ( & name) ) ;
115153 let module = f. cx . item_mod ( span, span, allocator_abi, Vec :: new ( ) , items) ;
116154 let module = f. cx . monotonic_expander ( ) . fold_item ( module) . pop ( ) . unwrap ( ) ;
117155
118- let mut ret = SmallVector :: new ( ) ;
156+ // Return the item and new submodule
157+ let mut ret = SmallVector :: with_capacity ( 2 ) ;
119158 ret. push ( item) ;
120159 ret. push ( module) ;
160+
121161 return ret;
122162 }
123163
164+ // If we enter a submodule, take note.
165+ fn fold_mod ( & mut self , m : Mod ) -> Mod {
166+ debug ! ( "enter submodule" ) ;
167+ self . in_submod += 1 ;
168+ let ret = fold:: noop_fold_mod ( m, self ) ;
169+ self . in_submod -= 1 ;
170+ debug ! ( "exit submodule" ) ;
171+ ret
172+ }
173+
174+ // `fold_mac` is disabled by default. Enable it here.
124175 fn fold_mac ( & mut self , mac : Mac ) -> Mac {
125176 fold:: noop_fold_mac ( mac, self )
126177 }
0 commit comments