Rollup merge of #22241 - kmcallister:macro-plugin-cleanup, r=sfackler
This commit is contained in:
commit
901d2c7b0d
@ -39,6 +39,16 @@ If present, arguments passed as `#![plugin(foo(... args ...))]` are not
|
||||
interpreted by rustc itself. They are provided to the plugin through the
|
||||
`Registry`'s [`args` method](../rustc/plugin/registry/struct.Registry.html#method.args).
|
||||
|
||||
In the vast majority of cases, a plugin should *only* be used through
|
||||
`#![plugin]` and not through an `extern crate` item. Linking a plugin would
|
||||
pull in all of libsyntax and librustc as dependencies of your crate. This is
|
||||
generally unwanted unless you are building another plugin. The
|
||||
`plugin_as_library` lint checks these guidelines.
|
||||
|
||||
The usual practice is to put compiler plugins in their own crate, separate from
|
||||
any `macro_rules!` macros or ordinary Rust code meant to be used by consumers
|
||||
of a library.
|
||||
|
||||
# Syntax extensions
|
||||
|
||||
Plugins can extend Rust's syntax in various ways. One kind of syntax extension
|
||||
|
@ -26,7 +26,7 @@
|
||||
//! a `pub fn new()`.
|
||||
use self::MethodContext::*;
|
||||
|
||||
use metadata::csearch;
|
||||
use metadata::{csearch, decoder};
|
||||
use middle::def::*;
|
||||
use middle::subst::Substs;
|
||||
use middle::ty::{self, Ty};
|
||||
@ -1964,6 +1964,48 @@ impl LintPass for UnconditionalRecursion {
|
||||
}
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
PLUGIN_AS_LIBRARY,
|
||||
Warn,
|
||||
"compiler plugin used as ordinary library in non-plugin crate"
|
||||
}
|
||||
|
||||
#[derive(Copy)]
|
||||
pub struct PluginAsLibrary;
|
||||
|
||||
impl LintPass for PluginAsLibrary {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array![PLUGIN_AS_LIBRARY]
|
||||
}
|
||||
|
||||
fn check_item(&mut self, cx: &Context, it: &ast::Item) {
|
||||
if cx.sess().plugin_registrar_fn.get().is_some() {
|
||||
// We're compiling a plugin; it's fine to link other plugins.
|
||||
return;
|
||||
}
|
||||
|
||||
match it.node {
|
||||
ast::ItemExternCrate(..) => (),
|
||||
_ => return,
|
||||
};
|
||||
|
||||
let md = match cx.sess().cstore.find_extern_mod_stmt_cnum(it.id) {
|
||||
Some(cnum) => cx.sess().cstore.get_crate_data(cnum),
|
||||
None => {
|
||||
// Probably means we aren't linking the crate for some reason.
|
||||
//
|
||||
// Not sure if / when this could happen.
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if decoder::get_plugin_registrar_fn(md.data()).is_some() {
|
||||
cx.span_lint(PLUGIN_AS_LIBRARY, it.span,
|
||||
"compiler plugin used as an ordinary library");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
pub UNUSED_IMPORTS,
|
||||
Warn,
|
||||
|
@ -214,6 +214,7 @@ impl LintStore {
|
||||
Stability,
|
||||
UnconditionalRecursion,
|
||||
InvalidNoMangleItems,
|
||||
PluginAsLibrary,
|
||||
);
|
||||
|
||||
add_builtin_with_new!(sess,
|
||||
|
@ -121,12 +121,10 @@ fn register_native_lib(sess: &Session,
|
||||
sess.cstore.add_used_library(name, kind);
|
||||
}
|
||||
|
||||
pub struct PluginMetadata<'a> {
|
||||
sess: &'a Session,
|
||||
// Extra info about a crate loaded for plugins or exported macros.
|
||||
struct ExtensionCrate {
|
||||
metadata: PMDSource,
|
||||
dylib: Option<Path>,
|
||||
info: CrateInfo,
|
||||
vi_span: Span,
|
||||
target_only: bool,
|
||||
}
|
||||
|
||||
@ -451,21 +449,7 @@ impl<'a> CrateReader<'a> {
|
||||
}).collect()
|
||||
}
|
||||
|
||||
pub fn read_plugin_metadata<'b>(&'b mut self,
|
||||
krate: CrateOrString<'b>) -> PluginMetadata<'b> {
|
||||
let (info, span) = match krate {
|
||||
CrateOrString::Krate(c) => {
|
||||
(self.extract_crate_info(c).unwrap(), c.span)
|
||||
}
|
||||
CrateOrString::Str(sp, s) => {
|
||||
(CrateInfo {
|
||||
name: s.to_string(),
|
||||
ident: s.to_string(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
should_link: false,
|
||||
}, sp)
|
||||
}
|
||||
};
|
||||
fn read_extension_crate(&mut self, span: Span, info: &CrateInfo) -> ExtensionCrate {
|
||||
let target_triple = &self.sess.opts.target_triple[];
|
||||
let is_cross = target_triple != config::host_triple();
|
||||
let mut should_link = info.should_link && !is_cross;
|
||||
@ -517,30 +501,21 @@ impl<'a> CrateReader<'a> {
|
||||
PMDSource::Owned(library.metadata)
|
||||
};
|
||||
|
||||
PluginMetadata {
|
||||
sess: self.sess,
|
||||
ExtensionCrate {
|
||||
metadata: metadata,
|
||||
dylib: dylib.map(|p| p.0),
|
||||
info: info,
|
||||
vi_span: span,
|
||||
target_only: target_only,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy)]
|
||||
pub enum CrateOrString<'a> {
|
||||
Krate(&'a ast::Item),
|
||||
Str(Span, &'a str)
|
||||
}
|
||||
/// Read exported macros.
|
||||
pub fn read_exported_macros(&mut self, krate: &ast::Item) -> Vec<ast::MacroDef> {
|
||||
let ci = self.extract_crate_info(krate).unwrap();
|
||||
let ekrate = self.read_extension_crate(krate.span, &ci);
|
||||
|
||||
impl<'a> PluginMetadata<'a> {
|
||||
/// Read exported macros
|
||||
pub fn exported_macros(&self) -> Vec<ast::MacroDef> {
|
||||
let imported_from = Some(token::intern(&self.info.ident[]).ident());
|
||||
let source_name = format!("<{} macros>", &self.info.ident[]);
|
||||
let source_name = format!("<{} macros>", krate.ident);
|
||||
let mut macros = vec![];
|
||||
decoder::each_exported_macro(self.metadata.as_slice(),
|
||||
decoder::each_exported_macro(ekrate.metadata.as_slice(),
|
||||
&*self.sess.cstore.intr,
|
||||
|name, attrs, body| {
|
||||
// NB: Don't use parse::parse_tts_from_source_str because it parses with
|
||||
@ -558,7 +533,7 @@ impl<'a> PluginMetadata<'a> {
|
||||
attrs: attrs,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: span,
|
||||
imported_from: imported_from,
|
||||
imported_from: Some(krate.ident),
|
||||
// overridden in plugin/load.rs
|
||||
export: false,
|
||||
use_locally: false,
|
||||
@ -572,28 +547,35 @@ impl<'a> PluginMetadata<'a> {
|
||||
}
|
||||
|
||||
/// Look for a plugin registrar. Returns library path and symbol name.
|
||||
pub fn plugin_registrar(&self) -> Option<(Path, String)> {
|
||||
if self.target_only {
|
||||
pub fn find_plugin_registrar(&mut self, span: Span, name: &str) -> Option<(Path, String)> {
|
||||
let ekrate = self.read_extension_crate(span, &CrateInfo {
|
||||
name: name.to_string(),
|
||||
ident: name.to_string(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
should_link: false,
|
||||
});
|
||||
|
||||
if ekrate.target_only {
|
||||
// Need to abort before syntax expansion.
|
||||
let message = format!("plugin crate `{}` is not available for triple `{}` \
|
||||
let message = format!("plugin `{}` is not available for triple `{}` \
|
||||
(only found {})",
|
||||
self.info.ident,
|
||||
name,
|
||||
config::host_triple(),
|
||||
self.sess.opts.target_triple);
|
||||
self.sess.span_err(self.vi_span, &message[]);
|
||||
self.sess.span_err(span, &message[]);
|
||||
self.sess.abort_if_errors();
|
||||
}
|
||||
|
||||
let registrar = decoder::get_plugin_registrar_fn(self.metadata.as_slice())
|
||||
.map(|id| decoder::get_symbol(self.metadata.as_slice(), id));
|
||||
let registrar = decoder::get_plugin_registrar_fn(ekrate.metadata.as_slice())
|
||||
.map(|id| decoder::get_symbol(ekrate.metadata.as_slice(), id));
|
||||
|
||||
match (self.dylib.as_ref(), registrar) {
|
||||
match (ekrate.dylib.as_ref(), registrar) {
|
||||
(Some(dylib), Some(reg)) => Some((dylib.clone(), reg)),
|
||||
(None, Some(_)) => {
|
||||
let message = format!("plugin crate `{}` only found in rlib format, \
|
||||
let message = format!("plugin `{}` only found in rlib format, \
|
||||
but must be available in dylib format",
|
||||
self.info.ident);
|
||||
self.sess.span_err(self.vi_span, &message[]);
|
||||
name);
|
||||
self.sess.span_err(span, &message[]);
|
||||
// No need to abort because the loading code will just ignore this
|
||||
// empty dylib.
|
||||
None
|
||||
|
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,24 +8,19 @@
|
||||
// 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::{CrateOrString, CrateReader};
|
||||
use metadata::creader::CrateReader;
|
||||
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;
|
||||
@ -102,156 +63,34 @@ pub fn load_plugins(sess: &Session, krate: &ast::Crate,
|
||||
}
|
||||
|
||||
let args = plugin.meta_item_list().map(ToOwned::to_owned).unwrap_or_default();
|
||||
loader.load_plugin(CrateOrString::Str(plugin.span, &*plugin.name()),
|
||||
args);
|
||||
loader.load_plugin(plugin.span, &*plugin.name(), args);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(plugins) = addl_plugins {
|
||||
for plugin in plugins {
|
||||
loader.load_plugin(CrateOrString::Str(COMMAND_LINE_SP, &plugin), vec![]);
|
||||
loader.load_plugin(COMMAND_LINE_SP, &plugin, vec![]);
|
||||
}
|
||||
}
|
||||
|
||||
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 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);
|
||||
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<'b>(&mut self,
|
||||
c: CrateOrString<'b>,
|
||||
args: Vec<P<ast::MetaItem>>) {
|
||||
let registrar = {
|
||||
let pmd = self.reader.read_plugin_metadata(c);
|
||||
pmd.plugin_registrar()
|
||||
};
|
||||
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(c, lib, symbol);
|
||||
self.plugins.registrars.push(PluginRegistrar {
|
||||
let fun = self.dylink_registrar(span, lib, symbol);
|
||||
self.plugins.push(PluginRegistrar {
|
||||
fun: fun,
|
||||
args: args,
|
||||
});
|
||||
@ -259,8 +98,8 @@ impl<'a> PluginLoader<'a> {
|
||||
}
|
||||
|
||||
// Dynamically link a registrar function into the compiler process.
|
||||
fn dylink_registrar<'b>(&mut self,
|
||||
c: CrateOrString<'b>,
|
||||
fn dylink_registrar(&mut self,
|
||||
span: Span,
|
||||
path: Path,
|
||||
symbol: String) -> PluginRegistrarFun {
|
||||
// Make sure the path contains a / or the linker will search for it.
|
||||
@ -272,11 +111,7 @@ impl<'a> PluginLoader<'a> {
|
||||
// inside this crate, so continue would spew "macro undefined"
|
||||
// errors
|
||||
Err(err) => {
|
||||
if let CrateOrString::Krate(cr) = c {
|
||||
self.sess.span_fatal(cr.span, &err[])
|
||||
} else {
|
||||
self.sess.fatal(&err[])
|
||||
}
|
||||
self.sess.span_fatal(span, &err[])
|
||||
}
|
||||
};
|
||||
|
||||
@ -288,11 +123,7 @@ impl<'a> PluginLoader<'a> {
|
||||
}
|
||||
// again fatal if we can't register macros
|
||||
Err(err) => {
|
||||
if let CrateOrString::Krate(cr) = c {
|
||||
self.sess.span_fatal(cr.span, &err[])
|
||||
} else {
|
||||
self.sess.fatal(&err[])
|
||||
}
|
||||
self.sess.span_fatal(span, &err[])
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
22
src/test/auxiliary/plugin_with_plugin_lib.rs
Normal file
22
src/test/auxiliary/plugin_with_plugin_lib.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// 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.
|
||||
|
||||
// force-host
|
||||
|
||||
#![feature(plugin_registrar)]
|
||||
#![deny(plugin_as_library)] // should have no effect in a plugin crate
|
||||
|
||||
extern crate macro_crate_test;
|
||||
extern crate rustc;
|
||||
|
||||
use rustc::plugin::Registry;
|
||||
|
||||
#[plugin_registrar]
|
||||
pub fn plugin_registrar(_: &mut Registry) { }
|
@ -16,6 +16,6 @@
|
||||
|
||||
#![feature(plugin)]
|
||||
#![plugin(rlib_crate_test)]
|
||||
//~^ ERROR: plugin crate `rlib_crate_test` only found in rlib format, but must be available in dylib format
|
||||
//~^ ERROR: plugin `rlib_crate_test` only found in rlib format, but must be available in dylib format
|
||||
|
||||
fn main() {}
|
||||
|
22
src/test/compile-fail-fulldeps/plugin-as-extern-crate.rs
Normal file
22
src/test/compile-fail-fulldeps/plugin-as-extern-crate.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2013-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:macro_crate_test.rs
|
||||
// ignore-stage1
|
||||
// ignore-cross-compile
|
||||
//
|
||||
// macro_crate_test will not compile on a cross-compiled target because
|
||||
// libsyntax is not compiled for it.
|
||||
|
||||
#![deny(plugin_as_library)]
|
||||
|
||||
extern crate macro_crate_test; //~ ERROR compiler plugin used as an ordinary library
|
||||
|
||||
fn main() { }
|
27
src/test/compile-fail-fulldeps/plugin-plus-extern-crate.rs
Normal file
27
src/test/compile-fail-fulldeps/plugin-plus-extern-crate.rs
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright 2013-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:macro_crate_test.rs
|
||||
// ignore-stage1
|
||||
// ignore-cross-compile
|
||||
//
|
||||
// macro_crate_test will not compile on a cross-compiled target because
|
||||
// libsyntax is not compiled for it.
|
||||
|
||||
#![deny(plugin_as_library)]
|
||||
#![feature(plugin)]
|
||||
#![plugin(macro_crate_test)]
|
||||
|
||||
extern crate macro_crate_test; //~ ERROR compiler plugin used as an ordinary library
|
||||
|
||||
fn main() {
|
||||
assert_eq!(1, make_a_1!());
|
||||
macro_crate_test::foo();
|
||||
}
|
26
src/test/run-pass-fulldeps/plugin-lib-ok-in-plugin.rs
Normal file
26
src/test/run-pass-fulldeps/plugin-lib-ok-in-plugin.rs
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright 2013-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:macro_crate_test.rs
|
||||
// aux-build:plugin_with_plugin_lib.rs
|
||||
// ignore-stage1
|
||||
// ignore-cross-compile
|
||||
//
|
||||
// macro_crate_test will not compile on a cross-compiled target because
|
||||
// libsyntax is not compiled for it.
|
||||
|
||||
#![deny(plugin_as_library)]
|
||||
#![feature(plugin)]
|
||||
#![plugin(macro_crate_test)]
|
||||
#![plugin(plugin_with_plugin_lib)]
|
||||
|
||||
fn main() {
|
||||
assert_eq!(1, make_a_1!());
|
||||
}
|
@ -15,6 +15,7 @@
|
||||
// macro_crate_test will not compile on a cross-compiled target because
|
||||
// libsyntax is not compiled for it.
|
||||
|
||||
#![allow(plugin_as_library)]
|
||||
#![feature(plugin)]
|
||||
#![plugin(macro_crate_test)]
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user