Now they just share a bit of code internal to creader.
Resolves #22198 to my satisfaction.
--- /dev/null
+// Copyright 2012-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.
+
+//! Used by `rustc` when loading a crate with exported macros.
+
+use session::Session;
+use metadata::creader::CrateReader;
+
+use std::collections::{HashSet, HashMap};
+use syntax::ast;
+use syntax::attr;
+use syntax::codemap::Span;
+use syntax::parse::token;
+use syntax::visit;
+use syntax::visit::Visitor;
+use syntax::attr::AttrMetaMethods;
+
+struct MacroLoader<'a> {
+ sess: &'a Session,
+ span_whitelist: HashSet<Span>,
+ reader: CrateReader<'a>,
+ macros: Vec<ast::MacroDef>,
+}
+
+impl<'a> MacroLoader<'a> {
+ fn new(sess: &'a Session) -> MacroLoader<'a> {
+ MacroLoader {
+ sess: sess,
+ span_whitelist: HashSet::new(),
+ reader: CrateReader::new(sess),
+ macros: vec![],
+ }
+ }
+}
+
+/// Read exported macros.
+pub fn read_macro_defs(sess: &Session, krate: &ast::Crate) -> Vec<ast::MacroDef> {
+ let mut loader = MacroLoader::new(sess);
+
+ // We need to error on `#[macro_use] extern crate` when it isn't at the
+ // crate root, because `$crate` won't work properly. Identify these by
+ // spans, because the crate map isn't set up yet.
+ for item in &krate.module.items {
+ if let ast::ItemExternCrate(_) = item.node {
+ loader.span_whitelist.insert(item.span);
+ }
+ }
+
+ visit::walk_crate(&mut loader, krate);
+
+ loader.macros
+}
+
+pub type MacroSelection = HashMap<token::InternedString, Span>;
+
+// note that macros aren't expanded yet, and therefore macros can't add macro imports.
+impl<'a, 'v> Visitor<'v> for MacroLoader<'a> {
+ fn visit_item(&mut self, item: &ast::Item) {
+ // We're only interested in `extern crate`.
+ match item.node {
+ ast::ItemExternCrate(_) => {}
+ _ => {
+ visit::walk_item(self, item);
+ return;
+ }
+ }
+
+ // Parse the attributes relating to macros.
+ 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()[] {
+ "phase" => {
+ self.sess.span_err(attr.span, "#[phase] is deprecated");
+ }
+ "plugin" => {
+ self.sess.span_err(attr.span, "#[plugin] on `extern crate` is deprecated");
+ self.sess.span_help(attr.span, &format!("use a crate attribute instead, \
+ i.e. #![plugin({})]",
+ item.ident.as_str())[]);
+ }
+ "macro_use" => {
+ let names = attr.meta_item_list();
+ if names.is_none() {
+ // no names => load all
+ import = None;
+ }
+ 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(attr.span, "bad macro import");
+ }
+ }
+ }
+ }
+ "macro_reexport" => {
+ let names = match attr.meta_item_list() {
+ Some(names) => names,
+ None => {
+ self.sess.span_err(attr.span, "bad macro reexport");
+ continue;
+ }
+ };
+
+ for attr in names {
+ if let ast::MetaWord(ref name) = attr.node {
+ reexport.insert(name.clone(), attr.span);
+ } else {
+ self.sess.span_err(attr.span, "bad macro reexport");
+ }
+ }
+ }
+ _ => used = false,
+ }
+ if used {
+ attr::mark_used(attr);
+ }
+ }
+
+ self.load_macros(item, import, reexport)
+ }
+
+ fn visit_mac(&mut self, _: &ast::Mac) {
+ // bummer... can't see macro imports inside macros.
+ // do nothing.
+ }
+}
+
+impl<'a> MacroLoader<'a> {
+ fn load_macros<'b>(&mut self,
+ vi: &ast::Item,
+ import: Option<MacroSelection>,
+ reexport: MacroSelection) {
+ if let Some(sel) = import.as_ref() {
+ if sel.is_empty() && reexport.is_empty() {
+ return;
+ }
+ }
+
+ if !self.span_whitelist.contains(&vi.span) {
+ self.sess.span_err(vi.span, "an `extern crate` loading macros must be at \
+ the crate root");
+ return;
+ }
+
+ let macros = self.reader.read_exported_macros(vi);
+ let mut seen = HashSet::new();
+
+ for mut def in macros {
+ let name = token::get_ident(def.ident);
+ seen.insert(name.clone());
+
+ def.use_locally = match import.as_ref() {
+ None => true,
+ Some(sel) => sel.contains_key(&name),
+ };
+ def.export = reexport.contains_key(&name);
+ self.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 mod csearch;
pub mod loader;
pub mod filesearch;
+pub mod macro_import;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! Used by `rustc` when loading a plugin, or a crate with exported macros.
+//! Used by `rustc` when loading a plugin.
use session::Session;
use metadata::creader::CrateReader;
use std::mem;
use std::env;
use std::dynamic_lib::DynamicLibrary;
-use std::collections::{HashSet, HashMap};
use std::borrow::ToOwned;
use syntax::ast;
-use syntax::attr;
use syntax::codemap::{Span, COMMAND_LINE_SP};
-use syntax::parse::token;
use syntax::ptr::P;
-use syntax::visit;
-use syntax::visit::Visitor;
use syntax::attr::AttrMetaMethods;
/// Pointer to a registrar function.
pub args: Vec<P<ast::MetaItem>>,
}
-/// Information about loaded plugins.
-pub struct Plugins {
- /// Imported macros.
- pub macros: Vec<ast::MacroDef>,
- /// Registrars, as function pointers.
- pub registrars: Vec<PluginRegistrar>,
-}
-
-pub struct PluginLoader<'a> {
+struct PluginLoader<'a> {
sess: &'a Session,
- span_whitelist: HashSet<Span>,
reader: CrateReader<'a>,
- pub plugins: Plugins,
-}
-
-impl<'a> PluginLoader<'a> {
- fn new(sess: &'a Session) -> PluginLoader<'a> {
- PluginLoader {
- sess: sess,
- reader: CrateReader::new(sess),
- span_whitelist: HashSet::new(),
- plugins: Plugins {
- macros: vec!(),
- registrars: vec!(),
- },
- }
- }
+ plugins: Vec<PluginRegistrar>,
}
/// Read plugin metadata and dynamically load registrar functions.
pub fn load_plugins(sess: &Session, krate: &ast::Crate,
- addl_plugins: Option<Vec<String>>) -> Plugins {
+ addl_plugins: Option<Vec<String>>) -> Vec<PluginRegistrar> {
let mut loader = PluginLoader::new(sess);
- // We need to error on `#[macro_use] extern crate` when it isn't at the
- // crate root, because `$crate` won't work properly. Identify these by
- // spans, because the crate map isn't set up yet.
- for item in &krate.module.items {
- if let ast::ItemExternCrate(_) = item.node {
- loader.span_whitelist.insert(item.span);
- }
- }
-
- visit::walk_crate(&mut loader, krate);
-
for attr in &krate.attrs {
if !attr.check_name("plugin") {
continue;
}
}
- 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) {
- // We're only interested in `extern crate`.
- match item.node {
- ast::ItemExternCrate(_) => {}
- _ => {
- visit::walk_item(self, item);
- return;
- }
- }
-
- // 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()[] {
- "phase" => {
- self.sess.span_err(attr.span, "#[phase] is deprecated");
- }
- "plugin" => {
- self.sess.span_err(attr.span, "#[plugin] on `extern crate` is deprecated");
- self.sess.span_help(attr.span, &format!("use a crate attribute instead, \
- i.e. #![plugin({})]",
- item.ident.as_str())[]);
- }
- "macro_use" => {
- let names = attr.meta_item_list();
- if names.is_none() {
- // no names => load all
- import = None;
- }
- 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(attr.span, "bad macro import");
- }
- }
- }
- }
- "macro_reexport" => {
- let names = match attr.meta_item_list() {
- Some(names) => names,
- None => {
- self.sess.span_err(attr.span, "bad macro reexport");
- continue;
- }
- };
-
- for attr in names {
- if let ast::MetaWord(ref name) = attr.node {
- reexport.insert(name.clone(), attr.span);
- } else {
- self.sess.span_err(attr.span, "bad macro reexport");
- }
- }
- }
- _ => used = false,
- }
- if used {
- attr::mark_used(attr);
- }
- }
-
- self.load_macros(item, import, reexport)
- }
-
- fn visit_mac(&mut self, _: &ast::Mac) {
- // bummer... can't see plugins inside macros.
- // do nothing.
- }
+ loader.plugins
}
impl<'a> PluginLoader<'a> {
- pub fn load_macros<'b>(&mut self,
- vi: &ast::Item,
- import: Option<MacroSelection>,
- reexport: MacroSelection) {
- if let Some(sel) = import.as_ref() {
- if sel.is_empty() && reexport.is_empty() {
- return;
- }
- }
-
- if !self.span_whitelist.contains(&vi.span) {
- self.sess.span_err(vi.span, "an `extern crate` loading macros must be at \
- the crate root");
- return;
- }
-
- let macros = self.reader.read_exported_macros(vi);
- let mut seen = HashSet::new();
-
- for mut def in macros {
- let name = token::get_ident(def.ident);
- seen.insert(name.clone());
-
- def.use_locally = match import.as_ref() {
- None => true,
- 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");
- }
+ fn new(sess: &'a Session) -> PluginLoader<'a> {
+ PluginLoader {
+ sess: sess,
+ reader: CrateReader::new(sess),
+ plugins: vec![],
}
}
- pub fn load_plugin(&mut self, span: Span, name: &str, args: Vec<P<ast::MetaItem>>) {
+ fn load_plugin(&mut self, span: Span, name: &str, args: Vec<P<ast::MetaItem>>) {
let registrar = self.reader.find_plugin_registrar(span, name);
if let Some((lib, symbol)) = registrar {
let fun = self.dylink_registrar(span, lib, symbol);
- self.plugins.registrars.push(PluginRegistrar {
+ self.plugins.push(PluginRegistrar {
fun: fun,
args: args,
});
use rustc::session::config::{self, Input, OutputFilenames};
use rustc::session::search_paths::PathKind;
use rustc::lint;
+use rustc::metadata;
use rustc::metadata::creader::CrateReader;
use rustc::middle::{stability, ty, reachable};
use rustc::middle::dependency_format;
use rustc::middle;
-use rustc::plugin::load::Plugins;
use rustc::plugin::registry::Registry;
use rustc::plugin;
use rustc::util::common::time;
syntax::std_inject::maybe_inject_crates_ref(krate,
sess.opts.alt_std_name.clone()));
+ let macros = time(time_passes, "macro loading", (), |_|
+ metadata::macro_import::read_macro_defs(sess, &krate));
+
let mut addl_plugins = Some(addl_plugins);
- let Plugins { macros, registrars }
- = time(time_passes, "plugin loading", (), |_|
- plugin::load::load_plugins(sess, &krate, addl_plugins.take().unwrap()));
+ let registrars = time(time_passes, "plugin loading", (), |_|
+ plugin::load::load_plugins(sess, &krate, addl_plugins.take().unwrap()));
let mut registry = Registry::new(sess, &krate);