@@ -17,7 +17,7 @@ use plugin::registry::Registry;
1717use std:: mem;
1818use std:: env;
1919use std:: dynamic_lib:: DynamicLibrary ;
20- use std:: collections:: HashSet ;
20+ use std:: collections:: { HashSet , HashMap } ;
2121use std:: borrow:: ToOwned ;
2222use syntax:: ast;
2323use syntax:: attr;
@@ -116,6 +116,8 @@ pub fn load_plugins(sess: &Session, krate: &ast::Crate,
116116 return loader. plugins ;
117117}
118118
119+ pub type MacroSelection = HashMap < token:: InternedString , Span > ;
120+
119121// note that macros aren't expanded yet, and therefore macros can't add plugins.
120122impl < ' a , ' v > Visitor < ' v > for PluginLoader < ' a > {
121123 fn visit_item ( & mut self , item : & ast:: Item ) {
@@ -128,9 +130,9 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
128130 }
129131 }
130132
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 ( ) ;
134136 for attr in & item. attrs {
135137 let mut used = true ;
136138 match & attr. name ( ) [ ] {
@@ -147,14 +149,14 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
147149 let names = attr. meta_item_list ( ) ;
148150 if names. is_none ( ) {
149151 // no names => load all
150- macro_selection = None ;
152+ import = None ;
151153 }
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 ) ;
156158 } else {
157- self . sess . span_err ( name . span , "bad macro import" ) ;
159+ self . sess . span_err ( attr . span , "bad macro import" ) ;
158160 }
159161 }
160162 }
@@ -168,11 +170,11 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
168170 }
169171 } ;
170172
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 ) ;
174176 } else {
175- self . sess . span_err ( name . span , "bad macro reexport" ) ;
177+ self . sess . span_err ( attr . span , "bad macro reexport" ) ;
176178 }
177179 }
178180 }
@@ -183,7 +185,7 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
183185 }
184186 }
185187
186- self . load_macros ( item, macro_selection , Some ( reexport) )
188+ self . load_macros ( item, import , reexport)
187189 }
188190
189191 fn visit_mac ( & mut self , _: & ast:: Mac ) {
@@ -195,10 +197,10 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
195197impl < ' a > PluginLoader < ' a > {
196198 pub fn load_macros < ' b > ( & mut self ,
197199 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 ( ) {
202204 return ;
203205 }
204206 }
@@ -211,19 +213,32 @@ impl<'a> PluginLoader<'a> {
211213
212214 let pmd = self . reader . read_plugin_metadata ( CrateOrString :: Krate ( vi) ) ;
213215
216+ let mut seen = HashSet :: new ( ) ;
214217 for mut def in pmd. exported_macros ( ) {
215218 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 ( ) {
217222 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) ,
224224 } ;
225+ def. export = reexport. contains_key ( & name) ;
225226 self . plugins . macros . push ( def) ;
226227 }
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+ }
227242 }
228243
229244 pub fn load_plugin < ' b > ( & mut self ,
0 commit comments