mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-25 23:14:12 +00:00
Separate macro and plugin loading
Now they just share a bit of code internal to creader. Resolves #22198 to my satisfaction.
This commit is contained in:
parent
6b784bacbf
commit
6864792df0
186
src/librustc/metadata/macro_import.rs
Normal file
186
src/librustc/metadata/macro_import.rs
Normal file
@ -0,0 +1,186 @@
|
||||
// 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -18,3 +18,4 @@ pub mod cstore;
|
||||
pub mod csearch;
|
||||
pub mod loader;
|
||||
pub mod filesearch;
|
||||
pub mod macro_import;
|
||||
|
@ -8,7 +8,7 @@
|
||||
// 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;
|
||||
@ -17,15 +17,10 @@ use plugin::registry::Registry;
|
||||
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.
|
||||
@ -37,51 +32,17 @@ pub struct PluginRegistrar {
|
||||
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;
|
||||
@ -112,140 +73,24 @@ 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) {
|
||||
// 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,
|
||||
});
|
||||
|
@ -12,11 +12,11 @@ use rustc::session::Session;
|
||||
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;
|
||||
@ -409,10 +409,12 @@ pub fn phase_2_configure_and_expand(sess: &Session,
|
||||
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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user