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