11
11
use rustc:: middle:: allocator:: AllocatorKind ;
12
12
use rustc_errors;
13
13
use 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 ;
31
36
32
37
use { AllocatorMethod , AllocatorTy , ALLOCATOR_METHODS } ;
33
38
34
39
pub fn modify (
35
40
sess : & ParseSess ,
36
41
resolver : & mut Resolver ,
37
42
krate : Crate ,
43
+ crate_name : String ,
38
44
handler : & rustc_errors:: Handler ,
39
45
) -> ast:: Crate {
40
46
ExpandAllocatorDirectives {
41
47
handler,
42
48
sess,
43
49
resolver,
44
50
found : false ,
51
+ crate_name : Some ( crate_name) ,
52
+ in_submod : -1 , // -1 to account for the "root" module
45
53
} . fold_crate ( krate)
46
54
}
47
55
@@ -50,10 +58,17 @@ struct ExpandAllocatorDirectives<'a> {
50
58
handler : & ' a rustc_errors:: Handler ,
51
59
sess : & ' a ParseSess ,
52
60
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 ,
53
66
}
54
67
55
68
impl < ' a > Folder for ExpandAllocatorDirectives < ' a > {
56
69
fn fold_item ( & mut self , item : P < Item > ) -> SmallVector < P < Item > > {
70
+ debug ! ( "in submodule {}" , self . in_submod) ;
71
+
57
72
let name = if attr:: contains_name ( & item. attrs , "global_allocator" ) {
58
73
"global_allocator"
59
74
} else {
@@ -68,19 +83,23 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> {
68
83
}
69
84
}
70
85
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
+
71
92
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]" ) ;
77
95
return SmallVector :: one ( item) ;
78
96
}
79
97
self . found = true ;
80
98
99
+ // Create a fresh Mark for the new macro expansion we are about to do
81
100
let mark = Mark :: fresh ( Mark :: root ( ) ) ;
82
101
mark. set_expn_info ( ExpnInfo {
83
- call_site : DUMMY_SP ,
102
+ call_site : item . span , // use the call site of the static
84
103
callee : NameAndSpan {
85
104
format : MacroAttribute ( Symbol :: intern ( name) ) ,
86
105
span : None ,
@@ -89,38 +108,70 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> {
89
108
edition : hygiene:: default_edition ( ) ,
90
109
} ,
91
110
} ) ;
111
+
112
+ // Tie the span to the macro expansion info we just created
92
113
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
94
119
let mut f = AllocFnFactory {
95
120
span,
96
121
kind : AllocatorKind :: Global ,
97
122
global : item. ident ,
98
123
core : Ident :: from_str ( "core" ) ,
99
124
cx : ExtCtxt :: new ( self . sess , ecfg, self . resolver ) ,
100
125
} ;
126
+
127
+ // We will generate a new submodule. To `use` the static from that module, we need to get
128
+ // the `super::...` path.
101
129
let super_path = f. cx . path ( f. span , vec ! [ Ident :: from_str( "super" ) , f. global] ) ;
130
+
131
+ // Generate the items in the submodule
102
132
let mut items = vec ! [
133
+ // import `core` to use allocators
103
134
f. cx. item_extern_crate( f. span, f. core) ,
135
+ // `use` the `global_allocator` in `super`
104
136
f. cx. item_use_simple(
105
137
f. span,
106
138
respan( f. span. shrink_to_lo( ) , VisibilityKind :: Inherited ) ,
107
139
super_path,
108
140
) ,
109
141
] ;
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
113
151
let name = f. kind . fn_name ( "allocator_abi" ) ;
114
152
let allocator_abi = Ident :: with_empty_ctxt ( Symbol :: gensym ( & name) ) ;
115
153
let module = f. cx . item_mod ( span, span, allocator_abi, Vec :: new ( ) , items) ;
116
154
let module = f. cx . monotonic_expander ( ) . fold_item ( module) . pop ( ) . unwrap ( ) ;
117
155
118
- let mut ret = SmallVector :: new ( ) ;
156
+ // Return the item and new submodule
157
+ let mut ret = SmallVector :: with_capacity ( 2 ) ;
119
158
ret. push ( item) ;
120
159
ret. push ( module) ;
160
+
121
161
return ret;
122
162
}
123
163
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.
124
175
fn fold_mac ( & mut self , mac : Mac ) -> Mac {
125
176
fold:: noop_fold_mac ( mac, self )
126
177
}
0 commit comments