about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/plugin/load.rs67
-rw-r--r--src/test/compile-fail/macro-reexport-undef.rs20
-rw-r--r--src/test/compile-fail/macro-use-undef.rs19
3 files changed, 80 insertions, 26 deletions
diff --git a/src/librustc/plugin/load.rs b/src/librustc/plugin/load.rs
index a2ce474eda8..b46454bfdd0 100644
--- a/src/librustc/plugin/load.rs
+++ b/src/librustc/plugin/load.rs
@@ -17,7 +17,7 @@ use plugin::registry::Registry;
 use std::mem;
 use std::env;
 use std::dynamic_lib::DynamicLibrary;
-use std::collections::HashSet;
+use std::collections::{HashSet, HashMap};
 use std::borrow::ToOwned;
 use syntax::ast;
 use syntax::attr;
@@ -116,6 +116,8 @@ pub fn load_plugins(sess: &Session, krate: &ast::Crate,
     return loader.plugins;
 }
 
+pub type MacroSelection = HashMap<token::InternedString, Span>;
+
 // note that macros aren't expanded yet, and therefore macros can't add plugins.
 impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
     fn visit_item(&mut self, item: &ast::Item) {
@@ -128,9 +130,9 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
             }
         }
 
-        // Parse the attributes relating to macro / plugin loading.
-        let mut macro_selection = Some(HashSet::new());  // None => load all
-        let mut reexport = HashSet::new();
+        // Parse the attributes relating to macro loading.
+        let mut import = Some(HashMap::new());  // None => load all
+        let mut reexport = HashMap::new();
         for attr in &item.attrs {
             let mut used = true;
             match &attr.name()[] {
@@ -147,14 +149,14 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
                     let names = attr.meta_item_list();
                     if names.is_none() {
                         // no names => load all
-                        macro_selection = None;
+                        import = None;
                     }
-                    if let (Some(sel), Some(names)) = (macro_selection.as_mut(), names) {
-                        for name in names {
-                            if let ast::MetaWord(ref name) = name.node {
-                                sel.insert(name.clone());
+                    if let (Some(sel), Some(names)) = (import.as_mut(), names) {
+                        for attr in names {
+                            if let ast::MetaWord(ref name) = attr.node {
+                                sel.insert(name.clone(), attr.span);
                             } else {
-                                self.sess.span_err(name.span, "bad macro import");
+                                self.sess.span_err(attr.span, "bad macro import");
                             }
                         }
                     }
@@ -168,11 +170,11 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
                         }
                     };
 
-                    for name in names {
-                        if let ast::MetaWord(ref name) = name.node {
-                            reexport.insert(name.clone());
+                    for attr in names {
+                        if let ast::MetaWord(ref name) = attr.node {
+                            reexport.insert(name.clone(), attr.span);
                         } else {
-                            self.sess.span_err(name.span, "bad macro reexport");
+                            self.sess.span_err(attr.span, "bad macro reexport");
                         }
                     }
                 }
@@ -183,7 +185,7 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
             }
         }
 
-        self.load_macros(item, macro_selection, Some(reexport))
+        self.load_macros(item, import, reexport)
     }
 
     fn visit_mac(&mut self, _: &ast::Mac) {
@@ -195,10 +197,10 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
 impl<'a> PluginLoader<'a> {
     pub fn load_macros<'b>(&mut self,
                            vi: &ast::Item,
-                           macro_selection: Option<HashSet<token::InternedString>>,
-                           reexport: Option<HashSet<token::InternedString>>) {
-        if let (Some(sel), Some(re)) = (macro_selection.as_ref(), reexport.as_ref()) {
-            if sel.is_empty() && re.is_empty() {
+                           import: Option<MacroSelection>,
+                           reexport: MacroSelection) {
+        if let Some(sel) = import.as_ref() {
+            if sel.is_empty() && reexport.is_empty() {
                 return;
             }
         }
@@ -211,19 +213,32 @@ impl<'a> PluginLoader<'a> {
 
         let pmd = self.reader.read_plugin_metadata(CrateOrString::Krate(vi));
 
+        let mut seen = HashSet::new();
         for mut def in pmd.exported_macros() {
             let name = token::get_ident(def.ident);
-            def.use_locally = match macro_selection.as_ref() {
+            seen.insert(name.clone());
+
+            def.use_locally = match import.as_ref() {
                 None => true,
-                Some(sel) => sel.contains(&name),
-            };
-            def.export = if let Some(ref re) = reexport {
-                re.contains(&name)
-            } else {
-                false // Don't reexport macros from crates loaded from the command line
+                Some(sel) => sel.contains_key(&name),
             };
+            def.export = reexport.contains_key(&name);
             self.plugins.macros.push(def);
         }
+
+        if let Some(sel) = import.as_ref() {
+            for (name, span) in sel.iter() {
+                if !seen.contains(name) {
+                    self.sess.span_err(*span, "imported macro not found");
+                }
+            }
+        }
+
+        for (name, span) in reexport.iter() {
+            if !seen.contains(name) {
+                self.sess.span_err(*span, "reexported macro not found");
+            }
+        }
     }
 
     pub fn load_plugin<'b>(&mut self,
diff --git a/src/test/compile-fail/macro-reexport-undef.rs b/src/test/compile-fail/macro-reexport-undef.rs
new file mode 100644
index 00000000000..e9b3ceff83d
--- /dev/null
+++ b/src/test/compile-fail/macro-reexport-undef.rs
@@ -0,0 +1,20 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:two_macros.rs
+// ignore-stage1
+
+#[macro_use(macro_two)]
+#[macro_reexport(no_way)] //~ ERROR reexported macro not found
+extern crate two_macros;
+
+pub fn main() {
+    macro_two!();
+}
diff --git a/src/test/compile-fail/macro-use-undef.rs b/src/test/compile-fail/macro-use-undef.rs
new file mode 100644
index 00000000000..a5a350bd30e
--- /dev/null
+++ b/src/test/compile-fail/macro-use-undef.rs
@@ -0,0 +1,19 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:two_macros.rs
+// ignore-stage1
+
+#[macro_use(macro_two, no_way)] //~ ERROR imported macro not found
+extern crate two_macros;
+
+pub fn main() {
+    macro_two!();
+}