rustc_plugin: Remove support for syntactic plugins
This commit is contained in:
parent
e41ced3f8d
commit
f89e6c8811
@ -3802,7 +3802,6 @@ dependencies = [
|
||||
"rustc_error_codes",
|
||||
"rustc_metadata",
|
||||
"syntax",
|
||||
"syntax_expand",
|
||||
"syntax_pos",
|
||||
]
|
||||
|
||||
|
@ -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
|
||||
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -37,7 +37,7 @@
|
||||
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;
|
||||
@ -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
|
||||
@ -137,7 +136,6 @@ pub fn configure_and_expand(
|
||||
&crate_name,
|
||||
&resolver_arenas,
|
||||
&*metadata_loader,
|
||||
plugin_info,
|
||||
);
|
||||
let mut resolver = match res {
|
||||
Err(v) => {
|
||||
@ -164,17 +162,13 @@ pub fn to_resolver_outputs(resolver: Rc<RefCell<BoxedResolver>>) -> ResolverOutp
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
@ -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>(
|
||||
@ -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(
|
||||
@ -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");
|
||||
|
@ -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;
|
||||
@ -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>)>,
|
||||
@ -111,7 +111,7 @@ pub fn parse(&self) -> Result<&Query<ast::Crate>> {
|
||||
})
|
||||
}
|
||||
|
||||
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();
|
||||
@ -161,14 +161,13 @@ pub fn expansion(
|
||||
) -> 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)
|
||||
})
|
||||
|
@ -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" }
|
||||
|
@ -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/")]
|
||||
|
||||
|
@ -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;
|
||||
|
||||
@ -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>,
|
||||
}
|
||||
@ -48,7 +41,6 @@ pub fn new(sess: &'a Session, lint_store: &'a mut LintStore, krate_span: Span) -
|
||||
lint_store,
|
||||
args_hidden: None,
|
||||
krate_span,
|
||||
syntax_exts: vec![],
|
||||
llvm_passes: vec![],
|
||||
}
|
||||
}
|
||||
@ -67,24 +59,6 @@ pub fn args(&self) -> &[ast::NestedMetaItem] {
|
||||
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
|
||||
|
@ -880,8 +880,8 @@ fn prohibit_imported_non_macro_attrs(&self, binding: Option<&'a NameBinding<'a>>
|
||||
}
|
||||
}
|
||||
|
||||
/// Compile the macro into a `SyntaxExtension` and possibly replace it with a pre-defined
|
||||
/// extension partially or entirely for built-in macros and legacy plugin macros.
|
||||
/// Compile the macro into a `SyntaxExtension` and possibly replace
|
||||
/// its expander to a pre-defined one for built-in macros.
|
||||
crate fn compile_macro(&mut self, item: &ast::Item, edition: Edition) -> SyntaxExtension {
|
||||
let mut result = compile_declarative_macro(
|
||||
&self.session.parse_sess, self.session.features_untracked(), item, edition
|
||||
@ -890,14 +890,9 @@ fn prohibit_imported_non_macro_attrs(&self, binding: Option<&'a NameBinding<'a>>
|
||||
if result.is_builtin {
|
||||
// The macro was marked with `#[rustc_builtin_macro]`.
|
||||
if let Some(ext) = self.builtin_macros.remove(&item.ident.name) {
|
||||
if ext.is_builtin {
|
||||
// The macro is a built-in, replace only the expander function.
|
||||
result.kind = ext.kind;
|
||||
} else {
|
||||
// The macro is from a plugin, the in-source definition is dummy,
|
||||
// take all the data from the resolver.
|
||||
result = ext;
|
||||
}
|
||||
// The macro is a built-in, replace its expander function
|
||||
// while still taking everything else from the source code.
|
||||
result.kind = ext.kind;
|
||||
} else {
|
||||
let msg = format!("cannot find a built-in macro with name `{}`", item.ident);
|
||||
self.session.span_err(item.span, &msg);
|
||||
|
@ -825,8 +825,6 @@ pub fn expn_data(&self, parent: ExpnId, call_site: Span, descr: Symbol) -> ExpnD
|
||||
}
|
||||
}
|
||||
|
||||
pub type NamedSyntaxExtension = (Name, SyntaxExtension);
|
||||
|
||||
/// Result of resolving a macro invocation.
|
||||
pub enum InvocationRes {
|
||||
Single(Lrc<SyntaxExtension>),
|
||||
|
@ -38,7 +38,6 @@
|
||||
mod util;
|
||||
|
||||
pub mod cmdline_attrs;
|
||||
pub mod plugin_macro_defs;
|
||||
pub mod proc_macro_harness;
|
||||
pub mod standard_library_imports;
|
||||
pub mod test_harness;
|
||||
|
@ -1,58 +0,0 @@
|
||||
//! Each macro must have a definition, so `#[plugin]` attributes
|
||||
//! inject a dummy `macro_rules` item for each macro they define.
|
||||
|
||||
use syntax::ast::*;
|
||||
use syntax::attr;
|
||||
use syntax::edition::Edition;
|
||||
use syntax::ptr::P;
|
||||
use syntax::source_map::respan;
|
||||
use syntax::symbol::sym;
|
||||
use syntax::token;
|
||||
use syntax::tokenstream::*;
|
||||
use syntax_expand::base::{Resolver, NamedSyntaxExtension};
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
use syntax_pos::hygiene::{ExpnData, ExpnKind, AstPass};
|
||||
|
||||
use std::mem;
|
||||
|
||||
fn plugin_macro_def(name: Name, span: Span) -> P<Item> {
|
||||
let rustc_builtin_macro = attr::mk_attr_outer(
|
||||
attr::mk_word_item(Ident::new(sym::rustc_builtin_macro, span)));
|
||||
|
||||
let parens: TreeAndJoint = TokenTree::Delimited(
|
||||
DelimSpan::from_single(span), token::Paren, TokenStream::default()
|
||||
).into();
|
||||
let trees = vec![parens.clone(), TokenTree::token(token::FatArrow, span).into(), parens];
|
||||
|
||||
P(Item {
|
||||
ident: Ident::new(name, span),
|
||||
attrs: vec![rustc_builtin_macro],
|
||||
id: DUMMY_NODE_ID,
|
||||
kind: ItemKind::MacroDef(MacroDef { tokens: TokenStream::new(trees), legacy: true }),
|
||||
vis: respan(span, VisibilityKind::Inherited),
|
||||
span: span,
|
||||
tokens: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn inject(
|
||||
krate: &mut Crate,
|
||||
resolver: &mut dyn Resolver,
|
||||
named_exts: Vec<NamedSyntaxExtension>,
|
||||
edition: Edition,
|
||||
) {
|
||||
if !named_exts.is_empty() {
|
||||
let mut extra_items = Vec::new();
|
||||
let span = DUMMY_SP.fresh_expansion(ExpnData::allow_unstable(
|
||||
ExpnKind::AstPass(AstPass::PluginMacroDefs), DUMMY_SP, edition,
|
||||
[sym::rustc_attrs][..].into(),
|
||||
));
|
||||
for (name, ext) in named_exts {
|
||||
resolver.register_builtin_macro(Ident::with_dummy_span(name), ext);
|
||||
extra_items.push(plugin_macro_def(name, span));
|
||||
}
|
||||
// The `macro_rules` items must be inserted before any other items.
|
||||
mem::swap(&mut extra_items, &mut krate.module.items);
|
||||
krate.module.items.append(&mut extra_items);
|
||||
}
|
||||
}
|
@ -750,7 +750,6 @@ pub enum AstPass {
|
||||
StdImports,
|
||||
TestHarness,
|
||||
ProcMacroHarness,
|
||||
PluginMacroDefs,
|
||||
}
|
||||
|
||||
impl AstPass {
|
||||
@ -759,7 +758,6 @@ fn descr(self) -> &'static str {
|
||||
AstPass::StdImports => "standard library imports",
|
||||
AstPass::TestHarness => "test harness",
|
||||
AstPass::ProcMacroHarness => "proc macro harness",
|
||||
AstPass::PluginMacroDefs => "plugin macro definitions",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +0,0 @@
|
||||
// force-host
|
||||
|
||||
#![feature(plugin_registrar)]
|
||||
#![feature(rustc_private)]
|
||||
|
||||
extern crate rustc_driver;
|
||||
extern crate syntax;
|
||||
extern crate syntax_expand;
|
||||
|
||||
use rustc_driver::plugin::Registry;
|
||||
use syntax_expand::base::SyntaxExtension;
|
||||
use syntax::feature_gate::AttributeType;
|
||||
use syntax::symbol::Symbol;
|
||||
|
||||
#[plugin_registrar]
|
||||
pub fn plugin_registrar(reg: &mut Registry) {
|
||||
reg.register_syntax_extension(
|
||||
Symbol::intern("mac"), SyntaxExtension::dummy_bang(reg.sess.edition())
|
||||
);
|
||||
}
|
10
src/test/ui-fulldeps/auxiliary/empty-plugin.rs
Normal file
10
src/test/ui-fulldeps/auxiliary/empty-plugin.rs
Normal file
@ -0,0 +1,10 @@
|
||||
// force-host
|
||||
|
||||
#![feature(plugin_registrar)]
|
||||
#![feature(rustc_private)]
|
||||
|
||||
extern crate rustc_driver;
|
||||
use rustc_driver::plugin::Registry;
|
||||
|
||||
#[plugin_registrar]
|
||||
pub fn plugin_registrar(_: &mut Registry) {}
|
@ -1,43 +0,0 @@
|
||||
// force-host
|
||||
|
||||
#![feature(plugin_registrar)]
|
||||
#![feature(box_syntax, rustc_private)]
|
||||
|
||||
extern crate syntax;
|
||||
extern crate syntax_expand;
|
||||
extern crate syntax_pos;
|
||||
extern crate rustc;
|
||||
extern crate rustc_driver;
|
||||
|
||||
use std::borrow::ToOwned;
|
||||
use syntax::ast;
|
||||
use syntax_expand::base::{SyntaxExtension, SyntaxExtensionKind};
|
||||
use syntax_expand::base::{TTMacroExpander, ExtCtxt, MacResult, MacEager};
|
||||
use syntax::print::pprust;
|
||||
use syntax::symbol::Symbol;
|
||||
use syntax_pos::Span;
|
||||
use syntax::tokenstream::TokenStream;
|
||||
use rustc_driver::plugin::Registry;
|
||||
|
||||
struct Expander {
|
||||
args: Vec<ast::NestedMetaItem>,
|
||||
}
|
||||
|
||||
impl TTMacroExpander for Expander {
|
||||
fn expand<'cx>(&self,
|
||||
ecx: &'cx mut ExtCtxt,
|
||||
sp: Span,
|
||||
_: TokenStream) -> Box<dyn MacResult+'cx> {
|
||||
let args = self.args.iter().map(|i| pprust::meta_list_item_to_string(i))
|
||||
.collect::<Vec<_>>().join(", ");
|
||||
MacEager::expr(ecx.expr_str(sp, Symbol::intern(&args)))
|
||||
}
|
||||
}
|
||||
|
||||
#[plugin_registrar]
|
||||
pub fn plugin_registrar(reg: &mut Registry) {
|
||||
let args = reg.args().to_owned();
|
||||
reg.register_syntax_extension(Symbol::intern("plugin_args"), SyntaxExtension::default(
|
||||
SyntaxExtensionKind::LegacyBang(Box::new(Expander { args })), reg.sess.edition()
|
||||
));
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
// WARNING WARNING WARNING WARNING WARNING
|
||||
// =======================================
|
||||
//
|
||||
// This code also appears in src/doc/unstable-book/src/language-features/plugin.md.
|
||||
// Please keep the two copies in sync! FIXME: have rustdoc read this file
|
||||
|
||||
// force-host
|
||||
|
||||
#![crate_type="dylib"]
|
||||
#![feature(plugin_registrar, rustc_private)]
|
||||
|
||||
extern crate syntax;
|
||||
extern crate syntax_expand;
|
||||
extern crate syntax_pos;
|
||||
extern crate rustc;
|
||||
extern crate rustc_driver;
|
||||
|
||||
use syntax::token::{self, Token};
|
||||
use syntax::tokenstream::{TokenTree, TokenStream};
|
||||
use syntax_expand::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);
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
// aux-build:attr-plugin-test.rs
|
||||
// aux-build:empty-plugin.rs
|
||||
|
||||
#![plugin(attr_plugin_test)]
|
||||
#![plugin(empty_plugin)]
|
||||
//~^ ERROR compiler plugins are deprecated
|
||||
//~| WARN use of deprecated attribute `plugin`: compiler plugins are deprecated
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
error[E0658]: compiler plugins are deprecated
|
||||
--> $DIR/gated-plugin.rs:3:1
|
||||
|
|
||||
LL | #![plugin(attr_plugin_test)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | #![plugin(empty_plugin)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/29597
|
||||
= help: add `#![feature(plugin)]` to the crate attributes to enable
|
||||
@ -10,8 +10,8 @@ LL | #![plugin(attr_plugin_test)]
|
||||
warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
|
||||
--> $DIR/gated-plugin.rs:3:1
|
||||
|
|
||||
LL | #![plugin(attr_plugin_test)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
|
||||
LL | #![plugin(empty_plugin)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
|
||||
|
|
||||
= note: `#[warn(deprecated)]` on by default
|
||||
|
||||
|
@ -1,10 +1,8 @@
|
||||
// run-pass
|
||||
// aux-build:plugin-args.rs
|
||||
// check-pass
|
||||
// aux-build:empty-plugin.rs
|
||||
// ignore-stage1
|
||||
|
||||
#![feature(plugin)]
|
||||
#![plugin(plugin_args)] //~ WARNING compiler plugins are deprecated
|
||||
#![plugin(empty_plugin)] //~ WARNING compiler plugins are deprecated
|
||||
|
||||
fn main() {
|
||||
assert_eq!(plugin_args!(), "");
|
||||
}
|
||||
fn main() {}
|
||||
|
@ -1,8 +1,8 @@
|
||||
warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
|
||||
--> $DIR/plugin-args-1.rs:6:1
|
||||
|
|
||||
LL | #![plugin(plugin_args)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
|
||||
LL | #![plugin(empty_plugin)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
|
||||
|
|
||||
= note: `#[warn(deprecated)]` on by default
|
||||
|
||||
|
@ -1,10 +1,8 @@
|
||||
// run-pass
|
||||
// aux-build:plugin-args.rs
|
||||
// check-pass
|
||||
// aux-build:empty-plugin.rs
|
||||
// ignore-stage1
|
||||
|
||||
#![feature(plugin)]
|
||||
#![plugin(plugin_args())] //~ WARNING compiler plugins are deprecated
|
||||
#![plugin(empty_plugin())] //~ WARNING compiler plugins are deprecated
|
||||
|
||||
fn main() {
|
||||
assert_eq!(plugin_args!(), "");
|
||||
}
|
||||
fn main() {}
|
||||
|
@ -1,8 +1,8 @@
|
||||
warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
|
||||
--> $DIR/plugin-args-2.rs:6:1
|
||||
|
|
||||
LL | #![plugin(plugin_args())]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
|
||||
LL | #![plugin(empty_plugin())]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
|
||||
|
|
||||
= note: `#[warn(deprecated)]` on by default
|
||||
|
||||
|
@ -1,10 +1,8 @@
|
||||
// run-pass
|
||||
// aux-build:plugin-args.rs
|
||||
// check-pass
|
||||
// aux-build:empty-plugin.rs
|
||||
// ignore-stage1
|
||||
|
||||
#![feature(plugin)]
|
||||
#![plugin(plugin_args(hello(there), how(are="you")))] //~ WARNING compiler plugins are deprecated
|
||||
#![plugin(empty_plugin(hello(there), how(are="you")))] //~ WARNING compiler plugins are deprecated
|
||||
|
||||
fn main() {
|
||||
assert_eq!(plugin_args!(), "hello(there), how(are = \"you\")");
|
||||
}
|
||||
fn main() {}
|
||||
|
@ -1,8 +1,8 @@
|
||||
warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
|
||||
--> $DIR/plugin-args-3.rs:6:1
|
||||
|
|
||||
LL | #![plugin(plugin_args(hello(there), how(are="you")))]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
|
||||
LL | #![plugin(empty_plugin(hello(there), how(are="you")))]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
|
||||
|
|
||||
= note: `#[warn(deprecated)]` on by default
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
// aux-build:attr-plugin-test.rs
|
||||
// aux-build:empty-plugin.rs
|
||||
// ignore-cross-compile
|
||||
//
|
||||
// attr_plugin_test will not compile on a cross-compiled target because
|
||||
// empty_plugin will not compile on a cross-compiled target because
|
||||
// libsyntax is not compiled for it.
|
||||
|
||||
#![deny(plugin_as_library)]
|
||||
|
||||
extern crate attr_plugin_test; //~ ERROR compiler plugin used as an ordinary library
|
||||
extern crate empty_plugin; //~ ERROR compiler plugin used as an ordinary library
|
||||
|
||||
fn main() { }
|
||||
|
@ -1,8 +1,8 @@
|
||||
error: compiler plugin used as an ordinary library
|
||||
--> $DIR/plugin-as-extern-crate.rs:9:1
|
||||
|
|
||||
LL | extern crate attr_plugin_test;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | extern crate empty_plugin;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/plugin-as-extern-crate.rs:7:9
|
||||
|
@ -1,11 +0,0 @@
|
||||
// edition:2018
|
||||
// aux-build:attr-plugin-test.rs
|
||||
// ignore-stage1
|
||||
|
||||
#![feature(plugin)]
|
||||
#![plugin(attr_plugin_test)]
|
||||
//~^ WARN use of deprecated attribute `plugin`
|
||||
|
||||
pub use mac as reexport; //~ ERROR `mac` is private, and cannot be re-exported
|
||||
|
||||
fn main() {}
|
@ -1,23 +0,0 @@
|
||||
error[E0364]: `mac` is private, and cannot be re-exported
|
||||
--> $DIR/plugin-reexport.rs:9:9
|
||||
|
|
||||
LL | pub use mac as reexport;
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: consider marking `mac` as `pub` in the imported module
|
||||
--> $DIR/plugin-reexport.rs:9:9
|
||||
|
|
||||
LL | pub use mac as reexport;
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
|
||||
--> $DIR/plugin-reexport.rs:6:1
|
||||
|
|
||||
LL | #![plugin(attr_plugin_test)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
|
||||
|
|
||||
= note: `#[warn(deprecated)]` on by default
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0364`.
|
@ -1,15 +0,0 @@
|
||||
// run-pass
|
||||
// aux-build:roman-numerals.rs
|
||||
// ignore-stage1
|
||||
|
||||
#![feature(plugin)]
|
||||
#![plugin(roman_numerals)] //~ WARNING compiler plugins are deprecated
|
||||
|
||||
pub fn main() {
|
||||
assert_eq!(rn!(MMXV), 2015);
|
||||
assert_eq!(rn!(MCMXCIX), 1999);
|
||||
assert_eq!(rn!(XXV), 25);
|
||||
assert_eq!(rn!(MDCLXVI), 1666);
|
||||
assert_eq!(rn!(MMMDCCCLXXXVIII), 3888);
|
||||
assert_eq!(rn!(MMXIV), 2014);
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
|
||||
--> $DIR/roman-numerals-macro.rs:6:1
|
||||
|
|
||||
LL | #![plugin(roman_numerals)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
|
||||
|
|
||||
= note: `#[warn(deprecated)]` on by default
|
||||
|
Loading…
Reference in New Issue
Block a user