3 The tracking issue for this feature is: [#29597]
5 [#29597]: https://github.com/rust-lang/rust/issues/29597
8 This feature is part of "compiler plugins." It will often be used with the
9 [`plugin_registrar`] and `rustc_private` features.
11 [`plugin_registrar`]: language-features/plugin-registrar.html
13 ------------------------
15 `rustc` can load compiler plugins, which are user-provided libraries that
16 extend the compiler's behavior with new syntax extensions, lint checks, etc.
18 A plugin is a dynamic library crate with a designated *registrar* function that
19 registers extensions with `rustc`. Other crates can load these extensions using
20 the crate attribute `#![plugin(...)]`. See the
21 `rustc_plugin` documentation for more about the
22 mechanics of defining and loading a plugin.
24 If present, arguments passed as `#![plugin(foo(... args ...))]` are not
25 interpreted by rustc itself. They are provided to the plugin through the
26 `Registry`'s `args` method.
28 In the vast majority of cases, a plugin should *only* be used through
29 `#![plugin]` and not through an `extern crate` item. Linking a plugin would
30 pull in all of libsyntax and librustc as dependencies of your crate. This is
31 generally unwanted unless you are building another plugin. The
32 `plugin_as_library` lint checks these guidelines.
34 The usual practice is to put compiler plugins in their own crate, separate from
35 any `macro_rules!` macros or ordinary Rust code meant to be used by consumers
40 Plugins can extend Rust's syntax in various ways. One kind of syntax extension
41 is the procedural macro. These are invoked the same way as [ordinary
42 macros](../book/macros.html), but the expansion is performed by arbitrary Rust
43 code that manipulates syntax trees at
47 [`roman_numerals.rs`](https://github.com/rust-lang/rust/blob/master/src/test/run-pass-fulldeps/auxiliary/roman_numerals.rs)
48 that implements Roman numeral integer literals.
51 #![crate_type="dylib"]
52 #![feature(plugin_registrar, rustc_private)]
56 extern crate rustc_plugin;
58 use syntax::parse::token;
59 use syntax::tokenstream::TokenTree;
60 use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
61 use syntax::ext::build::AstBuilder; // A trait for expr_usize.
62 use syntax::ext::quote::rt::Span;
63 use rustc_plugin::Registry;
65 fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
66 -> Box<MacResult + 'static> {
68 static NUMERALS: &'static [(&'static str, usize)] = &[
69 ("M", 1000), ("CM", 900), ("D", 500), ("CD", 400),
70 ("C", 100), ("XC", 90), ("L", 50), ("XL", 40),
71 ("X", 10), ("IX", 9), ("V", 5), ("IV", 4),
77 &format!("argument should be a single identifier, but got {} arguments", args.len()));
78 return DummyResult::any(sp);
81 let text = match args[0] {
82 TokenTree::Token(_, token::Ident(s)) => s.to_string(),
84 cx.span_err(sp, "argument should be a single identifier");
85 return DummyResult::any(sp);
89 let mut text = &*text;
91 while !text.is_empty() {
92 match NUMERALS.iter().find(|&&(rn, _)| text.starts_with(rn)) {
95 text = &text[rn.len()..];
98 cx.span_err(sp, "invalid Roman numeral");
99 return DummyResult::any(sp);
104 MacEager::expr(cx.expr_usize(sp, total))
108 pub fn plugin_registrar(reg: &mut Registry) {
109 reg.register_macro("rn", expand_rn);
113 Then we can use `rn!()` like any other macro:
117 #![plugin(roman_numerals)]
120 assert_eq!(rn!(MMXV), 2015);
124 The advantages over a simple `fn(&str) -> u32` are:
126 * The (arbitrarily complex) conversion is done at compile time.
127 * Input validation is also performed at compile time.
128 * It can be extended to allow use in patterns, which effectively gives
129 a way to define new literal syntax for any data type.
131 In addition to procedural macros, you can define new
132 [`derive`](../reference/attributes.html#derive)-like attributes and other kinds
133 of extensions. See `Registry::register_syntax_extension` and the
134 `SyntaxExtension` enum. For a more involved macro example, see
135 [`regex_macros`](https://github.com/rust-lang/regex/blob/master/regex_macros/src/lib.rs).
140 Some of the [macro debugging tips](../book/first-edition/macros.html#debugging-macro-code) are applicable.
142 You can use `syntax::parse` to turn token trees into
143 higher-level syntax elements like expressions:
146 fn expand_foo(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
147 -> Box<MacResult+'static> {
149 let mut parser = cx.new_parser_from_tts(args);
151 let expr: P<Expr> = parser.parse_expr();
154 Looking through [`libsyntax` parser
155 code](https://github.com/rust-lang/rust/blob/master/src/libsyntax/parse/parser.rs)
156 will give you a feel for how the parsing infrastructure works.
158 Keep the `Span`s of everything you parse, for better error reporting. You can
159 wrap `Spanned` around your custom data structures.
161 Calling `ExtCtxt::span_fatal` will immediately abort compilation. It's better to
162 instead call `ExtCtxt::span_err` and return `DummyResult` so that the compiler
163 can continue and find further errors.
165 To print syntax fragments for debugging, you can use `span_note` together with
166 `syntax::print::pprust::*_to_string`.
168 The example above produced an integer literal using `AstBuilder::expr_usize`.
169 As an alternative to the `AstBuilder` trait, `libsyntax` provides a set of
170 quasiquote macros. They are undocumented and very rough around the edges.
171 However, the implementation may be a good starting point for an improved
172 quasiquote as an ordinary plugin library.
177 Plugins can extend [Rust's lint
178 infrastructure](../reference/attributes.html#lint-check-attributes) with
179 additional checks for code style, safety, etc. Now let's write a plugin
180 [`lint_plugin_test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/ui-fulldeps/auxiliary/lint_plugin_test.rs)
181 that warns about any item named `lintme`.
184 #![feature(plugin_registrar)]
185 #![feature(box_syntax, rustc_private)]
186 #![feature(macro_vis_matcher)]
187 #![feature(macro_at_most_once_rep)]
191 // Load rustc as a plugin to get macros
194 extern crate rustc_plugin;
196 use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass,
197 EarlyLintPassObject, LintArray};
198 use rustc_plugin::Registry;
201 declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");
205 impl LintPass for Pass {
206 fn get_lints(&self) -> LintArray {
207 lint_array!(TEST_LINT)
211 impl EarlyLintPass for Pass {
212 fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) {
213 if it.ident.as_str() == "lintme" {
214 cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'");
220 pub fn plugin_registrar(reg: &mut Registry) {
221 reg.register_early_lint_pass(box Pass as EarlyLintPassObject);
228 #![plugin(lint_plugin_test)]
233 will produce a compiler warning:
236 foo.rs:4:1: 4:16 warning: item is named 'lintme', #[warn(test_lint)] on by default
237 foo.rs:4 fn lintme() { }
241 The components of a lint plugin are:
243 * one or more `declare_lint!` invocations, which define static `Lint` structs;
245 * a struct holding any state needed by the lint pass (here, none);
248 implementation defining how to check each syntax element. A single
249 `LintPass` may call `span_lint` for several different `Lint`s, but should
250 register them all through the `get_lints` method.
252 Lint passes are syntax traversals, but they run at a late stage of compilation
253 where type information is available. `rustc`'s [built-in
254 lints](https://github.com/rust-lang/rust/blob/master/src/librustc/lint/builtin.rs)
255 mostly use the same infrastructure as lint plugins, and provide examples of how
256 to access type information.
258 Lints defined by plugins are controlled by the usual [attributes and compiler
259 flags](../reference/attributes.html#lint-check-attributes), e.g.
260 `#[allow(test_lint)]` or `-A test-lint`. These identifiers are derived from the
261 first argument to `declare_lint!`, with appropriate case and punctuation
264 You can run `rustc -W help foo.rs` to see a list of lints known to `rustc`,
265 including those provided by plugins loaded by `foo.rs`.