diff --git a/src/doc/trpl/plugins.md b/src/doc/trpl/plugins.md index 3dea1a66ffd72..79502f3cd17f7 100644 --- a/src/doc/trpl/plugins.md +++ b/src/doc/trpl/plugins.md @@ -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 diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index a415ff3ed7165..74e921acdb404 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -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}; @@ -1963,6 +1963,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, diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 616af79326d9a..42a6861f452a6 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -214,6 +214,7 @@ impl LintStore { Stability, UnconditionalRecursion, InvalidNoMangleItems, + PluginAsLibrary, ); add_builtin_with_new!(sess, diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index 30d7ec8be639b..0871c36d892c6 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -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, - 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 { + 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 { - 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 diff --git a/src/librustc/metadata/macro_import.rs b/src/librustc/metadata/macro_import.rs new file mode 100644 index 0000000000000..28c98d455f046 --- /dev/null +++ b/src/librustc/metadata/macro_import.rs @@ -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 or the MIT license +// , 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, + reader: CrateReader<'a>, + macros: Vec, +} + +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 { + 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; + +// 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, + 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"); + } + } + } +} diff --git a/src/librustc/metadata/mod.rs b/src/librustc/metadata/mod.rs index 24007380feec1..0bf1e6d198fa2 100644 --- a/src/librustc/metadata/mod.rs +++ b/src/librustc/metadata/mod.rs @@ -18,3 +18,4 @@ pub mod cstore; pub mod csearch; pub mod loader; pub mod filesearch; +pub mod macro_import; diff --git a/src/librustc/plugin/load.rs b/src/librustc/plugin/load.rs index b46454bfdd04e..1895cbcb5421e 100644 --- a/src/librustc/plugin/load.rs +++ b/src/librustc/plugin/load.rs @@ -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>, } -/// Information about loaded plugins. -pub struct Plugins { - /// Imported macros. - pub macros: Vec, - /// Registrars, as function pointers. - pub registrars: Vec, -} - -pub struct PluginLoader<'a> { +struct PluginLoader<'a> { sess: &'a Session, - span_whitelist: HashSet, 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, } /// Read plugin metadata and dynamically load registrar functions. pub fn load_plugins(sess: &Session, krate: &ast::Crate, - addl_plugins: Option>) -> Plugins { + addl_plugins: Option>) -> Vec { 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![]); - } - } - - return loader.plugins; -} - -pub type MacroSelection = HashMap; - -// 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); - } + loader.load_plugin(COMMAND_LINE_SP, &plugin, vec![]); } - - 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, - 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>) { - let registrar = { - let pmd = self.reader.read_plugin_metadata(c); - pmd.plugin_registrar() - }; + fn load_plugin(&mut self, span: Span, name: &str, args: Vec>) { + 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[]) } }; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 12f5041cad14f..5461279f17bfb 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -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); diff --git a/src/test/auxiliary/plugin_with_plugin_lib.rs b/src/test/auxiliary/plugin_with_plugin_lib.rs new file mode 100644 index 0000000000000..cfc8c015324d9 --- /dev/null +++ b/src/test/auxiliary/plugin_with_plugin_lib.rs @@ -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 or the MIT license +// , 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) { } diff --git a/src/test/compile-fail-fulldeps/macro-crate-rlib.rs b/src/test/compile-fail-fulldeps/macro-crate-rlib.rs index 7d38d4352b0de..7a362994b8db6 100644 --- a/src/test/compile-fail-fulldeps/macro-crate-rlib.rs +++ b/src/test/compile-fail-fulldeps/macro-crate-rlib.rs @@ -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() {} diff --git a/src/test/compile-fail-fulldeps/plugin-as-extern-crate.rs b/src/test/compile-fail-fulldeps/plugin-as-extern-crate.rs new file mode 100644 index 0000000000000..c5169b61a2bf9 --- /dev/null +++ b/src/test/compile-fail-fulldeps/plugin-as-extern-crate.rs @@ -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 or the MIT license +// , 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() { } diff --git a/src/test/compile-fail-fulldeps/plugin-plus-extern-crate.rs b/src/test/compile-fail-fulldeps/plugin-plus-extern-crate.rs new file mode 100644 index 0000000000000..3dfd8838ebec4 --- /dev/null +++ b/src/test/compile-fail-fulldeps/plugin-plus-extern-crate.rs @@ -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 or the MIT license +// , 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(); +} diff --git a/src/test/run-pass-fulldeps/plugin-lib-ok-in-plugin.rs b/src/test/run-pass-fulldeps/plugin-lib-ok-in-plugin.rs new file mode 100644 index 0000000000000..c612ee75651ba --- /dev/null +++ b/src/test/run-pass-fulldeps/plugin-lib-ok-in-plugin.rs @@ -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 or the MIT license +// , 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!()); +} diff --git a/src/test/run-pass-fulldeps/plugin-plus-extern-crate.rs b/src/test/run-pass-fulldeps/plugin-plus-extern-crate.rs index 0c27dba9c627f..d1ce83f267788 100644 --- a/src/test/run-pass-fulldeps/plugin-plus-extern-crate.rs +++ b/src/test/run-pass-fulldeps/plugin-plus-extern-crate.rs @@ -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)]