Skip to content

Commit

Permalink
Auto merge of #66647 - petrochenkov:nosynt, r=Centril
Browse files Browse the repository at this point in the history
rustc_plugin: Remove support for syntactic plugins

This part of the plugin interface was successfully replaced by token-based procedural macros in theory and in practice.

cc #29597
cc #64675
r? @Centril
  • Loading branch information
bors committed Nov 24, 2019
2 parents 5a1d028 + f89e6c8 commit 412f43a
Show file tree
Hide file tree
Showing 31 changed files with 56 additions and 523 deletions.
1 change: 0 additions & 1 deletion Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3802,7 +3802,6 @@ dependencies = [
"rustc_error_codes",
"rustc_metadata",
"syntax",
"syntax_expand",
"syntax_pos",
]

Expand Down
130 changes: 1 addition & 129 deletions src/doc/unstable-book/src/language-features/plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ This feature is part of "compiler plugins." It will often be used with the
------------------------

`rustc` can load compiler plugins, which are user-provided libraries that
extend the compiler's behavior with new syntax extensions, lint checks, etc.
extend the compiler's behavior with new lint checks, etc.

A plugin is a dynamic library crate with a designated *registrar* function that
registers extensions with `rustc`. Other crates can load these extensions using
Expand All @@ -35,134 +35,6 @@ 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
is the procedural macro. These are invoked the same way as [ordinary
macros](../../book/macros.md), but the expansion is performed by arbitrary Rust
code that manipulates syntax trees at
compile time.

Let's write a plugin
[`roman_numerals.rs`](https://github.com/rust-lang/rust/blob/master/src/test/ui-fulldeps/auxiliary/roman_numerals.rs)
that implements Roman numeral integer literals.

```rust,ignore
#![crate_type="dylib"]
#![feature(plugin_registrar, rustc_private)]
extern crate syntax;
extern crate syntax_pos;
extern crate rustc;
extern crate rustc_driver;
use syntax::parse::token::{self, Token};
use syntax::tokenstream::{TokenTree, TokenStream};
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
use syntax_pos::Span;
use rustc_driver::plugin::Registry;
fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: TokenStream)
-> Box<dyn MacResult + 'static> {
static NUMERALS: &'static [(&'static str, usize)] = &[
("M", 1000), ("CM", 900), ("D", 500), ("CD", 400),
("C", 100), ("XC", 90), ("L", 50), ("XL", 40),
("X", 10), ("IX", 9), ("V", 5), ("IV", 4),
("I", 1)];
if args.len() != 1 {
cx.span_err(
sp,
&format!("argument should be a single identifier, but got {} arguments", args.len()));
return DummyResult::any(sp);
}
let text = match args.into_trees().next().unwrap() {
TokenTree::Token(Token { kind: token::Ident(s, _), .. }) => s.to_string(),
_ => {
cx.span_err(sp, "argument should be a single identifier");
return DummyResult::any(sp);
}
};
let mut text = &*text;
let mut total = 0;
while !text.is_empty() {
match NUMERALS.iter().find(|&&(rn, _)| text.starts_with(rn)) {
Some(&(rn, val)) => {
total += val;
text = &text[rn.len()..];
}
None => {
cx.span_err(sp, "invalid Roman numeral");
return DummyResult::any(sp);
}
}
}
MacEager::expr(cx.expr_usize(sp, total))
}
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
reg.register_macro("rn", expand_rn);
}
```

Then we can use `rn!()` like any other macro:

```rust,ignore
#![feature(plugin)]
#![plugin(roman_numerals)]
fn main() {
assert_eq!(rn!(MMXV), 2015);
}
```

The advantages over a simple `fn(&str) -> u32` are:

* The (arbitrarily complex) conversion is done at compile time.
* Input validation is also performed at compile time.
* It can be extended to allow use in patterns, which effectively gives
a way to define new literal syntax for any data type.

In addition to procedural macros, you can define new
[`derive`](../../reference/attributes/derive.md)-like attributes and other kinds
of extensions. See `Registry::register_syntax_extension` and the
`SyntaxExtension` struct. For a more involved macro example, see
[`regex_macros`](https://github.com/rust-lang/regex/blob/master/regex_macros/src/lib.rs).


## Tips and tricks

You can use `syntax::parse` to turn token trees into
higher-level syntax elements like expressions:

```rust,ignore
fn expand_foo(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
-> Box<MacResult+'static> {
let mut parser = cx.new_parser_from_tts(args);
let expr: P<Expr> = parser.parse_expr();
```

Looking through [`libsyntax` parser
code](https://github.com/rust-lang/rust/blob/master/src/libsyntax/parse/parser.rs)
will give you a feel for how the parsing infrastructure works.

Keep the `Span`s of everything you parse, for better error reporting. You can
wrap `Spanned` around your custom data structures.

Calling `ExtCtxt::span_fatal` will immediately abort compilation. It's better to
instead call `ExtCtxt::span_err` and return `DummyResult` so that the compiler
can continue and find further errors.

To print syntax fragments for debugging, you can use `span_note` together with
`syntax::print::pprust::*_to_string`.

# Lint plugins

Plugins can extend [Rust's lint
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_driver/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ pub fn run_compiler(
}

{
let (_, _, lint_store) = &*compiler.register_plugins()?.peek();
let (_, lint_store) = &*compiler.register_plugins()?.peek();

// Lint plugins are registered; now we can process command line flags.
if sess.opts.describe_lints {
Expand Down
20 changes: 4 additions & 16 deletions src/librustc_interface/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use rustc_traits;
use rustc_typeck as typeck;
use syntax::{self, ast, visit};
use syntax::early_buffered_lints::BufferedEarlyLint;
use syntax_expand::base::{NamedSyntaxExtension, ExtCtxt};
use syntax_expand::base::ExtCtxt;
use syntax::mut_visit::MutVisitor;
use syntax::util::node_count::NodeCounter;
use syntax::symbol::Symbol;
Expand Down Expand Up @@ -119,7 +119,6 @@ pub fn configure_and_expand(
metadata_loader: Box<MetadataLoaderDyn>,
krate: ast::Crate,
crate_name: &str,
plugin_info: PluginInfo,
) -> Result<(ast::Crate, BoxedResolver)> {
// Currently, we ignore the name resolution data structures for the purposes of dependency
// tracking. Instead we will run name resolution and include its output in the hash of each
Expand All @@ -137,7 +136,6 @@ pub fn configure_and_expand(
&crate_name,
&resolver_arenas,
&*metadata_loader,
plugin_info,
);
let mut resolver = match res {
Err(v) => {
Expand All @@ -164,17 +162,13 @@ impl BoxedResolver {
}
}

pub struct PluginInfo {
syntax_exts: Vec<NamedSyntaxExtension>,
}

pub fn register_plugins<'a>(
sess: &'a Session,
metadata_loader: &'a dyn MetadataLoader,
register_lints: impl Fn(&Session, &mut lint::LintStore),
mut krate: ast::Crate,
crate_name: &str,
) -> Result<(ast::Crate, PluginInfo, Lrc<lint::LintStore>)> {
) -> Result<(ast::Crate, Lrc<lint::LintStore>)> {
krate = time(sess, "attributes injection", || {
syntax_ext::cmdline_attrs::inject(
krate, &sess.parse_sess, &sess.opts.debugging_opts.crate_attr
Expand Down Expand Up @@ -240,10 +234,9 @@ pub fn register_plugins<'a>(
}
});

let Registry { syntax_exts, llvm_passes, .. } = registry;
*sess.plugin_llvm_passes.borrow_mut() = llvm_passes;
*sess.plugin_llvm_passes.borrow_mut() = registry.llvm_passes;

Ok((krate, PluginInfo { syntax_exts }, Lrc::new(lint_store)))
Ok((krate, Lrc::new(lint_store)))
}

fn configure_and_expand_inner<'a>(
Expand All @@ -253,7 +246,6 @@ fn configure_and_expand_inner<'a>(
crate_name: &str,
resolver_arenas: &'a ResolverArenas<'a>,
metadata_loader: &'a MetadataLoaderDyn,
plugin_info: PluginInfo,
) -> Result<(ast::Crate, Resolver<'a>)> {
time(sess, "pre-AST-expansion lint checks", || {
lint::check_ast_crate(
Expand Down Expand Up @@ -290,10 +282,6 @@ fn configure_and_expand_inner<'a>(

util::check_attr_crate_type(&krate.attrs, &mut resolver.lint_buffer());

syntax_ext::plugin_macro_defs::inject(
&mut krate, &mut resolver, plugin_info.syntax_exts, sess.edition()
);

// Expand all macros
krate = time(sess, "expansion", || {
let _prof_timer = sess.prof.generic_activity("macro_expand_crate");
Expand Down
9 changes: 4 additions & 5 deletions src/librustc_interface/queries.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::interface::{Compiler, Result};
use crate::passes::{self, BoxedResolver, BoxedGlobalCtxt, PluginInfo};
use crate::passes::{self, BoxedResolver, BoxedGlobalCtxt};

use rustc_incremental::DepGraphFuture;
use rustc_data_structures::sync::Lrc;
Expand Down Expand Up @@ -79,7 +79,7 @@ pub(crate) struct Queries {
dep_graph_future: Query<Option<DepGraphFuture>>,
parse: Query<ast::Crate>,
crate_name: Query<String>,
register_plugins: Query<(ast::Crate, PluginInfo, Lrc<LintStore>)>,
register_plugins: Query<(ast::Crate, Lrc<LintStore>)>,
expansion: Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>,
dep_graph: Query<DepGraph>,
lower_to_hir: Query<(Steal<hir::map::Forest>, Steal<ResolverOutputs>)>,
Expand Down Expand Up @@ -111,7 +111,7 @@ impl Compiler {
})
}

pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, PluginInfo, Lrc<LintStore>)>> {
pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, Lrc<LintStore>)>> {
self.queries.register_plugins.compute(|| {
let crate_name = self.crate_name()?.peek().clone();
let krate = self.parse()?.take();
Expand Down Expand Up @@ -161,14 +161,13 @@ impl Compiler {
) -> Result<&Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>> {
self.queries.expansion.compute(|| {
let crate_name = self.crate_name()?.peek().clone();
let (krate, plugin_info, lint_store) = self.register_plugins()?.take();
let (krate, lint_store) = self.register_plugins()?.take();
passes::configure_and_expand(
self.sess.clone(),
lint_store.clone(),
self.codegen_backend().metadata_loader(),
krate,
&crate_name,
plugin_info,
).map(|(krate, resolver)| {
(krate, Steal::new(Rc::new(RefCell::new(resolver))), lint_store)
})
Expand Down
1 change: 0 additions & 1 deletion src/librustc_plugin_impl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,5 @@ doctest = false
rustc = { path = "../librustc" }
rustc_metadata = { path = "../librustc_metadata" }
syntax = { path = "../libsyntax" }
syntax_expand = { path = "../libsyntax_expand" }
syntax_pos = { path = "../libsyntax_pos" }
rustc_error_codes = { path = "../librustc_error_codes" }
49 changes: 2 additions & 47 deletions src/librustc_plugin_impl/lib.rs
Original file line number Diff line number Diff line change
@@ -1,55 +1,10 @@
//! Infrastructure for compiler plugins.
//!
//! Plugins are Rust libraries which extend the behavior of `rustc`
//! in various ways.
//!
//! Plugin authors will use the `Registry` type re-exported by
//! this module, along with its methods. The rest of the module
//! is for use by `rustc` itself.
//!
//! To define a plugin, build a dylib crate with a
//! `#[plugin_registrar]` function:
//!
//! ```no_run
//! #![crate_name = "myplugin"]
//! #![crate_type = "dylib"]
//! #![feature(plugin_registrar)]
//! #![feature(rustc_private)]
//!
//! extern crate rustc_driver;
//! extern crate syntax;
//! extern crate syntax_pos;
//!
//! use rustc_driver::plugin::Registry;
//! use syntax_expand::base::{ExtCtxt, MacResult};
//! use syntax_pos::Span;
//! use syntax::tokenstream::TokenTree;
//!
//! #[plugin_registrar]
//! pub fn plugin_registrar(reg: &mut Registry) {
//! reg.register_macro("mymacro", expand_mymacro);
//! }
//!
//! fn expand_mymacro(cx: &mut ExtCtxt, span: Span, tt: &[TokenTree]) -> Box<MacResult> {
//! unimplemented!()
//! }
//!
//! # fn main() {}
//! ```
//!
//! WARNING: We currently don't check that the registrar function
//! has the appropriate type!
//!
//! To use a plugin while compiling another crate:
//!
//! ```rust
//! #![feature(plugin)]
//! #![plugin(myplugin)]
//! ```
//! Plugins are a deprecated way to extend the behavior of `rustc` in various ways.
//!
//! See the [`plugin`
//! feature](https://doc.rust-lang.org/nightly/unstable-book/language-features/plugin.html)
//! of the Unstable Book for more examples.
//! of the Unstable Book for some examples.

#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]

Expand Down
26 changes: 0 additions & 26 deletions src/librustc_plugin_impl/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@

use rustc::lint::LintStore;
use rustc::session::Session;

use syntax_expand::base::{SyntaxExtension, SyntaxExtensionKind, NamedSyntaxExtension};
use syntax_expand::base::MacroExpanderFn;
use syntax::symbol::Symbol;
use syntax::ast;
use syntax_pos::Span;

Expand Down Expand Up @@ -33,9 +29,6 @@ pub struct Registry<'a> {
#[doc(hidden)]
pub krate_span: Span,

#[doc(hidden)]
pub syntax_exts: Vec<NamedSyntaxExtension>,

#[doc(hidden)]
pub llvm_passes: Vec<String>,
}
Expand All @@ -48,7 +41,6 @@ impl<'a> Registry<'a> {
lint_store,
args_hidden: None,
krate_span,
syntax_exts: vec![],
llvm_passes: vec![],
}
}
Expand All @@ -67,24 +59,6 @@ impl<'a> Registry<'a> {
self.args_hidden.as_ref().map(|v| &v[..]).unwrap_or(&[])
}

/// Register a syntax extension of any kind.
///
/// This is the most general hook into `libsyntax`'s expansion behavior.
pub fn register_syntax_extension(&mut self, name: ast::Name, extension: SyntaxExtension) {
self.syntax_exts.push((name, extension));
}

/// Register a macro of the usual kind.
///
/// This is a convenience wrapper for `register_syntax_extension`.
/// It builds for you a `SyntaxExtensionKind::LegacyBang` that calls `expander`,
/// and also takes care of interning the macro's name.
pub fn register_macro(&mut self, name: &str, expander: MacroExpanderFn) {
let kind = SyntaxExtensionKind::LegacyBang(Box::new(expander));
let ext = SyntaxExtension::default(kind, self.sess.edition());
self.register_syntax_extension(Symbol::intern(name), ext);
}

/// Register an LLVM pass.
///
/// Registration with LLVM itself is handled through static C++ objects with
Expand Down
Loading

0 comments on commit 412f43a

Please sign in to comment.