about summary refs log tree commit diff
diff options
context:
space:
mode:
authorKeegan McAllister <kmcallister@mozilla.com>2015-02-11 22:33:07 -0800
committerKeegan McAllister <kmcallister@mozilla.com>2015-02-12 12:44:31 -0800
commitb7683fc02b35cafc849b7097556f4f67c3adcfe9 (patch)
tree60abc58eaaa004f2e5954e7e4f3858403b6abec8
parent6864792df002a4430634ea6ae096dd7e524560c2 (diff)
downloadrust-b7683fc02b35cafc849b7097556f4f67c3adcfe9.tar.gz
rust-b7683fc02b35cafc849b7097556f4f67c3adcfe9.zip
Warn when linking a plugin into a non-plugin crate
Fixes #22202.
-rw-r--r--src/doc/trpl/plugins.md10
-rw-r--r--src/librustc/lint/builtin.rs44
-rw-r--r--src/librustc/lint/context.rs1
-rw-r--r--src/test/auxiliary/plugin_with_plugin_lib.rs22
-rw-r--r--src/test/compile-fail-fulldeps/plugin-as-extern-crate.rs22
-rw-r--r--src/test/compile-fail-fulldeps/plugin-plus-extern-crate.rs27
-rw-r--r--src/test/run-pass-fulldeps/plugin-lib-ok-in-plugin.rs26
-rw-r--r--src/test/run-pass-fulldeps/plugin-plus-extern-crate.rs1
8 files changed, 152 insertions, 1 deletions
diff --git a/src/doc/trpl/plugins.md b/src/doc/trpl/plugins.md
index 3dea1a66ffd..79502f3cd17 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 a415ff3ed71..74e921acdb4 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};
@@ -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,
     "imports that are never used"
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index 616af79326d..42a6861f452 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/test/auxiliary/plugin_with_plugin_lib.rs b/src/test/auxiliary/plugin_with_plugin_lib.rs
new file mode 100644
index 00000000000..cfc8c015324
--- /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 <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) { }
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 00000000000..c5169b61a2b
--- /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 <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() { }
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 00000000000..3dfd8838ebe
--- /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 <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();
+}
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 00000000000..c612ee75651
--- /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 <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!());
+}
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 0c27dba9c62..d1ce83f2677 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)]