@@ -17,7 +17,7 @@ use plugin::registry::Registry;
17
17
use std:: mem;
18
18
use std:: env;
19
19
use std:: dynamic_lib:: DynamicLibrary ;
20
- use std:: collections:: HashSet ;
20
+ use std:: collections:: { HashSet , HashMap } ;
21
21
use std:: borrow:: ToOwned ;
22
22
use syntax:: ast;
23
23
use syntax:: attr;
@@ -116,6 +116,8 @@ pub fn load_plugins(sess: &Session, krate: &ast::Crate,
116
116
return loader. plugins ;
117
117
}
118
118
119
+ pub type MacroSelection = HashMap < token:: InternedString , Span > ;
120
+
119
121
// note that macros aren't expanded yet, and therefore macros can't add plugins.
120
122
impl < ' a , ' v > Visitor < ' v > for PluginLoader < ' a > {
121
123
fn visit_item ( & mut self , item : & ast:: Item ) {
@@ -128,9 +130,9 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
128
130
}
129
131
}
130
132
131
- // Parse the attributes relating to macro / plugin loading.
132
- let mut macro_selection = Some ( HashSet :: new ( ) ) ; // None => load all
133
- let mut reexport = HashSet :: new ( ) ;
133
+ // Parse the attributes relating to macro loading.
134
+ let mut import = Some ( HashMap :: new ( ) ) ; // None => load all
135
+ let mut reexport = HashMap :: new ( ) ;
134
136
for attr in & item. attrs {
135
137
let mut used = true ;
136
138
match & attr. name ( ) [ ] {
@@ -147,14 +149,14 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
147
149
let names = attr. meta_item_list ( ) ;
148
150
if names. is_none ( ) {
149
151
// no names => load all
150
- macro_selection = None ;
152
+ import = None ;
151
153
}
152
- if let ( Some ( sel) , Some ( names) ) = ( macro_selection . as_mut ( ) , names) {
153
- for name in names {
154
- if let ast:: MetaWord ( ref name) = name . node {
155
- sel. insert ( name. clone ( ) ) ;
154
+ if let ( Some ( sel) , Some ( names) ) = ( import . as_mut ( ) , names) {
155
+ for attr in names {
156
+ if let ast:: MetaWord ( ref name) = attr . node {
157
+ sel. insert ( name. clone ( ) , attr . span ) ;
156
158
} else {
157
- self . sess . span_err ( name . span , "bad macro import" ) ;
159
+ self . sess . span_err ( attr . span , "bad macro import" ) ;
158
160
}
159
161
}
160
162
}
@@ -168,11 +170,11 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
168
170
}
169
171
} ;
170
172
171
- for name in names {
172
- if let ast:: MetaWord ( ref name) = name . node {
173
- reexport. insert ( name. clone ( ) ) ;
173
+ for attr in names {
174
+ if let ast:: MetaWord ( ref name) = attr . node {
175
+ reexport. insert ( name. clone ( ) , attr . span ) ;
174
176
} else {
175
- self . sess . span_err ( name . span , "bad macro reexport" ) ;
177
+ self . sess . span_err ( attr . span , "bad macro reexport" ) ;
176
178
}
177
179
}
178
180
}
@@ -183,7 +185,7 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
183
185
}
184
186
}
185
187
186
- self . load_macros ( item, macro_selection , Some ( reexport) )
188
+ self . load_macros ( item, import , reexport)
187
189
}
188
190
189
191
fn visit_mac ( & mut self , _: & ast:: Mac ) {
@@ -195,10 +197,10 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
195
197
impl < ' a > PluginLoader < ' a > {
196
198
pub fn load_macros < ' b > ( & mut self ,
197
199
vi : & ast:: Item ,
198
- macro_selection : Option < HashSet < token :: InternedString > > ,
199
- reexport : Option < HashSet < token :: InternedString > > ) {
200
- if let ( Some ( sel) , Some ( re ) ) = ( macro_selection . as_ref ( ) , reexport . as_ref ( ) ) {
201
- if sel. is_empty ( ) && re . is_empty ( ) {
200
+ import : Option < MacroSelection > ,
201
+ reexport : MacroSelection ) {
202
+ if let Some ( sel) = import . as_ref ( ) {
203
+ if sel. is_empty ( ) && reexport . is_empty ( ) {
202
204
return ;
203
205
}
204
206
}
@@ -211,19 +213,32 @@ impl<'a> PluginLoader<'a> {
211
213
212
214
let pmd = self . reader . read_plugin_metadata ( CrateOrString :: Krate ( vi) ) ;
213
215
216
+ let mut seen = HashSet :: new ( ) ;
214
217
for mut def in pmd. exported_macros ( ) {
215
218
let name = token:: get_ident ( def. ident ) ;
216
- def. use_locally = match macro_selection. as_ref ( ) {
219
+ seen. insert ( name. clone ( ) ) ;
220
+
221
+ def. use_locally = match import. as_ref ( ) {
217
222
None => true ,
218
- Some ( sel) => sel. contains ( & name) ,
219
- } ;
220
- def. export = if let Some ( ref re) = reexport {
221
- re. contains ( & name)
222
- } else {
223
- false // Don't reexport macros from crates loaded from the command line
223
+ Some ( sel) => sel. contains_key ( & name) ,
224
224
} ;
225
+ def. export = reexport. contains_key ( & name) ;
225
226
self . plugins . macros . push ( def) ;
226
227
}
228
+
229
+ if let Some ( sel) = import. as_ref ( ) {
230
+ for ( name, span) in sel. iter ( ) {
231
+ if !seen. contains ( name) {
232
+ self . sess . span_err ( * span, "imported macro not found" ) ;
233
+ }
234
+ }
235
+ }
236
+
237
+ for ( name, span) in reexport. iter ( ) {
238
+ if !seen. contains ( name) {
239
+ self . sess . span_err ( * span, "reexported macro not found" ) ;
240
+ }
241
+ }
227
242
}
228
243
229
244
pub fn load_plugin < ' b > ( & mut self ,
0 commit comments