Skip to content

Commit 28da271

Browse files
committed
Typecheck the plugin registrar
Fixes rust-lang#14841.
1 parent 21d1f4d commit 28da271

File tree

7 files changed

+134
-22
lines changed

7 files changed

+134
-22
lines changed

src/librustc/driver/driver.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -376,11 +376,6 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
376376
time(time_passes, "looking for entry point", (),
377377
|_| middle::entry::find_entry_point(&sess, &ast_map));
378378

379-
sess.plugin_registrar_fn.set(
380-
time(time_passes, "looking for plugin registrar", (), |_|
381-
plugin::build::find_plugin_registrar(
382-
sess.diagnostic(), krate)));
383-
384379
let (freevars, capture_modes) =
385380
time(time_passes, "freevar finding", (), |_|
386381
freevars::annotate_freevars(&def_map, krate));
@@ -454,6 +449,9 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
454449
&reachable_map)
455450
});
456451

452+
time(time_passes, "looking for plugin registrar", (), |_|
453+
plugin::build::find_plugin_registrar(&ty_cx, krate));
454+
457455
time(time_passes, "lint checking", (), |_|
458456
lint::check_crate(&ty_cx, &exported_items));
459457

src/librustc/plugin/build.rs

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,10 @@
1010

1111
//! Used by `rustc` when compiling a plugin crate.
1212
13-
use syntax::ast;
14-
use syntax::attr;
13+
use middle::ty;
14+
15+
use syntax::{ast, abi, attr, visit};
1516
use syntax::codemap::Span;
16-
use syntax::diagnostic;
17-
use syntax::visit;
1817
use syntax::visit::Visitor;
1918

2019
struct RegistrarFinder {
@@ -38,24 +37,64 @@ impl<'v> Visitor<'v> for RegistrarFinder {
3837
}
3938

4039
/// Find the function marked with `#[plugin_registrar]`, if any.
41-
pub fn find_plugin_registrar(diagnostic: &diagnostic::SpanHandler,
42-
krate: &ast::Crate) -> Option<ast::NodeId> {
40+
pub fn find_plugin_registrar(tcx: &ty::ctxt, krate: &ast::Crate) {
4341
let mut finder = RegistrarFinder { registrars: Vec::new() };
4442
visit::walk_crate(&mut finder, krate);
4543

4644
match finder.registrars.len() {
47-
0 => None,
45+
0 => (),
4846
1 => {
49-
let (node_id, _) = finder.registrars.pop().unwrap();
50-
Some(node_id)
51-
},
47+
let (id, span) = finder.registrars.pop().unwrap();
48+
tcx.sess.plugin_registrar_fn.set(Some(id));
49+
typecheck_plugin_registrar(tcx, id, span);
50+
}
5251
_ => {
53-
diagnostic.handler().err("multiple plugin registration functions found");
52+
tcx.sess.err("multiple plugin registration functions found");
5453
for &(_, span) in finder.registrars.iter() {
55-
diagnostic.span_note(span, "one is here");
54+
tcx.sess.span_note(span, "one is here");
55+
}
56+
}
57+
}
58+
59+
tcx.sess.abort_if_errors();
60+
}
61+
62+
/// Typecheck the plugin registrar.
63+
fn typecheck_plugin_registrar(tcx: &ty::ctxt, id: ast::NodeId, span: Span) {
64+
match ty::get(ty::node_id_to_type(tcx, id)).sty {
65+
ty::ty_bare_fn(ty::BareFnTy { fn_style: ast::NormalFn, abi: abi::Rust, ref sig }) => {
66+
match sig.inputs.as_slice() {
67+
[arg_t] => match ty::get(arg_t).sty {
68+
ty::ty_rptr(_, ty::mt { mutbl: ast::MutMutable, ty })
69+
if ty_is_registry(tcx, ty) => (),
70+
_ => tcx.sess.span_err(span, "plugin registrar arg should be \
71+
&mut rustc::plugin::Registry"),
72+
},
73+
_ => tcx.sess.span_err(span, "plugin registrar should have one argument"),
5674
}
57-
diagnostic.handler().abort_if_errors();
58-
unreachable!();
75+
match ty::get(sig.output).sty {
76+
ty::ty_nil => (),
77+
_ => tcx.sess.span_err(span, "plugin registrar should not return anything"),
78+
}
79+
}
80+
81+
_ => tcx.sess.span_err(span, "plugin registrar should be a normal Rust function"),
82+
}
83+
}
84+
85+
/// Check if the given type is rustc::plugin::Registry.
86+
fn ty_is_registry(tcx: &ty::ctxt, ty: ty::t) -> bool {
87+
match ty::get(ty).sty {
88+
ty::ty_struct(def, ref sub) => {
89+
if !sub.is_noop() {
90+
return false;
91+
}
92+
93+
// Because users can bind any crate at any name, this check is
94+
// neither sound nor complete. But it will catch the vast majority
95+
// of mistakes.
96+
ty::item_path_str(tcx, def).as_slice() == "rustc::plugin::registry::Registry"
5997
}
98+
_ => false,
6099
}
61100
}

src/librustc/plugin/mod.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,6 @@
3838
* fn expand_mymacro(...) { // details elided
3939
* ```
4040
*
41-
* WARNING: We currently don't check that the registrar function
42-
* has the appropriate type!
43-
*
4441
* To use a plugin while compiling another crate:
4542
*
4643
* ```rust
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// error-pattern: plugin registrar
12+
13+
#![feature(plugin_registrar)]
14+
15+
#[plugin_registrar]
16+
pub fn reg() {}
17+
18+
fn main() {}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// error-pattern: plugin registrar
12+
13+
#![feature(plugin_registrar)]
14+
15+
extern crate rustc;
16+
17+
#[plugin_registrar]
18+
pub fn reg(r: &mut rustc::plugin::Registry, x: int) {}
19+
20+
fn main() {}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// error-pattern: plugin registrar
12+
13+
#![feature(plugin_registrar)]
14+
15+
pub struct Registry;
16+
17+
#[plugin_registrar]
18+
pub fn reg(x: &mut Registry) {}
19+
20+
fn main() {}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// error-pattern: plugin registrar
12+
13+
#![feature(plugin_registrar)]
14+
15+
extern crate rustc;
16+
17+
#[plugin_registrar]
18+
pub fn reg(x: &mut rustc::plugin::Registry) -> int { 3 }
19+
20+
fn main() {}

0 commit comments

Comments
 (0)