Warn when linking a plugin into a non-plugin crate

Fixes #22202.
This commit is contained in:
Keegan McAllister 2015-02-11 22:33:07 -08:00
parent 6864792df0
commit b7683fc02b
8 changed files with 152 additions and 1 deletions

View File

@ -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

View File

@ -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 @@ fn id_refers_to_this_method<'tcx>(tcx: &ty::ctxt<'tcx>,
}
}
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,

View File

@ -214,6 +214,7 @@ macro_rules! add_lint_group {
Stability,
UnconditionalRecursion,
InvalidNoMangleItems,
PluginAsLibrary,
);
add_builtin_with_new!(sess,

View 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) { }

View 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() { }

View 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();
}

View 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!());
}

View File

@ -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)]