Skip to content

Commit 21f0da7

Browse files
committed
Merge remote-tracking branch 'kmc/plugin'
2 parents 69a0f68 + 21aacba commit 21f0da7

File tree

1 file changed

+93
-0
lines changed

1 file changed

+93
-0
lines changed

active/0000-plugin-registrar.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
- Start Date: 2014-05-22
2+
- RFC PR #:
3+
- Rust Issue #:
4+
5+
# Summary
6+
7+
Generalize the `#[macro_registrar]` feature so it can register other kinds of compiler plugins.
8+
9+
# Motivation
10+
11+
I want to implement [loadable lints](https://github.com/mozilla/rust/issues/14067) and use them for project-specific static analysis passes in Servo. Landing this first will allow more evolution of the plugin system without breaking source compatibility for existing users.
12+
13+
# Detailed design
14+
15+
To register a procedural macro in current Rust:
16+
17+
~~~ .rs
18+
use syntax::ast::Name;
19+
use syntax::parse::token;
20+
use syntax::ext::base::{SyntaxExtension, BasicMacroExpander, NormalTT};
21+
22+
#[macro_registrar]
23+
pub fn macro_registrar(register: |Name, SyntaxExtension|) {
24+
register(token::intern("named_entities"),
25+
NormalTT(box BasicMacroExpander {
26+
expander: named_entities::expand,
27+
span: None
28+
},
29+
None));
30+
}
31+
~~~
32+
33+
I propose an interface like
34+
35+
~~~ .rs
36+
use syntax::parse::token;
37+
use syntax::ext::base::{BasicMacroExpander, NormalTT};
38+
39+
use rustc::plugin::Registry;
40+
41+
#[plugin_registrar]
42+
pub fn plugin_registrar(reg: &mut Registry) {
43+
reg.register_macro(token::intern("named_entities"),
44+
NormalTT(box BasicMacroExpander {
45+
expander: named_entities::expand,
46+
span: None
47+
},
48+
None));
49+
}
50+
~~~
51+
52+
Then the struct `Registry` could provide additional methods such as `register_lint` as those features are implemented.
53+
54+
It could also provide convenience methods:
55+
56+
~~~ .rs
57+
use rustc::plugin::Registry;
58+
59+
#[plugin_registrar]
60+
pub fn plugin_registrar(reg: &mut Registry) {
61+
reg.register_simple_macro("named_entities", named_entities::expand);
62+
}
63+
~~~
64+
65+
`phase(syntax)` becomes `phase(plugin)`, with the former as a deprecated synonym that warns. This is to avoid silent breakage of the very common `#[phase(syntax)] extern crate log`.
66+
67+
We only need one phase of loading plugin crates, even though the plugins we load may be used at different points (or not at all).
68+
69+
# Drawbacks
70+
71+
Breaking change for existing procedural macros.
72+
73+
More moving parts.
74+
75+
`Registry` is provided by `librustc`, because it will have methods for registering lints and other `librustc` things. This means that syntax extensions must link `librustc`, when before they only needed `libsyntax` (but could link `librustc` anyway if desired). This was discussed [on the RFC PR](https://github.com/rust-lang/rfcs/pull/86) and [the Rust PR](https://github.com/mozilla/rust/pull/14554) and [on IRC](https://botbot.me/mozilla/rust-internals/2014-05-22/?msg=15075433&page=5).
76+
77+
`#![feature(macro_registrar)]` becomes unknown, contradicting a comment in `feature_gate.rs`:
78+
79+
> This list can never shrink, it may only be expanded (in order to prevent old programs from failing to compile)
80+
81+
Since when do we ensure that old programs will compile? ;) The `#[macro_registrar]` attribute wouldn't work anyway.
82+
83+
# Alternatives
84+
85+
We could add `#[lint_registrar]` etc. alongside `#[macro_registrar]`. This seems like it will produce more duplicated effort all around. It doesn't provide convenience methods, and it won't support API evolution as well.
86+
87+
We could support the old `#[macro_registrar]` by injecting an adapter shim. This is significant extra work to support a feature with no stability guarantee.
88+
89+
# Unresolved questions
90+
91+
Naming bikeshed.
92+
93+
What set of convenience methods should we provide?

0 commit comments

Comments
 (0)