8000 Rollup of 7 pull requests by frewsxcv · Pull Request #40216 · rust-lang/rust · GitHub
[go: up one dir, main page]

Skip to content

Rollup of 7 pull requests #40216

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Mar 2, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Implement function-like procedural macros ( #[proc_macro])
  • Loading branch information
abonander committed Mar 1, 2017
commit 2fcbb48c727e82ea8751d6476d86fd3c6fe16b42
4 changes: 4 additions & 0 deletions src/libproc_macro/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ pub mod __internal {
fn register_attr_proc_macro(&mut self,
name: &str,
expand: fn(TokenStream, TokenStream) -> TokenStream);

fn register_bang_proc_macro(&mut self,
name: &str,
expand: fn(TokenStream) -> TokenStream);
}

// Emulate scoped_thread_local!() here essentially 8000
Expand Down
11 changes: 10 additions & 1 deletion src/librustc_metadata/creader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,7 @@ impl<'a> CrateLoader<'a> {
use proc_macro::__internal::Registry;
use rustc_back::dynamic_lib::DynamicLibrary;
use syntax_ext::deriving::custom::ProcMacroDerive;
use syntax_ext::proc_macro_impl::AttrProcMacro;
use syntax_ext::proc_macro_impl::{AttrProcMacro, BangProcMacro};

let path = match dylib {
Some(dylib) => dylib,
Expand Down Expand Up @@ -630,6 +630,15 @@ impl<'a> CrateLoader<'a> {
);
self.0.push((Symbol::intern(name), Rc::new(expand)));
}

fn register_bang_proc_macro(&mut self,
name: &str,
expand: fn(TokenStream) -> TokenStream) {
let expand = SyntaxExtension::ProcMacro(
Box::new(BangProcMacro { inner: expand })
);
self.0.push((Symbol::intern(name), Rc::new(expand)));
}
}

let mut my_registrar = MyRegistrar(Vec::new());
Expand Down
5 changes: 5 additions & 0 deletions src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,11 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
"attribute proc macros are currently unstable",
cfg_fn!(proc_macro))),

("proc_macro", Normal, Gated(Stability::Unstable,
"proc_macro",
"function-like proc macros are currently unstable",
cfg_fn!(proc_macro))),

("rustc_derive_registrar", Normal, Gated(Stability::Unstable,
"rustc_derive_registrar",
"used internally by rustc",
Expand Down
35 changes: 35 additions & 0 deletions src/libsyntax_ext/proc_macro_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,38 @@ impl base::AttrProcMacro for AttrProcMacro {
}
}
}

pub struct BangProcMacro {
pub inner: fn(TsShim) -> TsShim,
}

impl base::ProcMacro for BangProcMacro {
fn expand<'cx>(&self,
ecx: &'cx mut ExtCtxt,
span: Span,
input: TokenStream)
-> TokenStream {
let input = __internal::token_stream_wrap(input);

let res = __internal::set_parse_sess(&ecx.parse_sess, || {
panic::catch_unwind(panic::AssertUnwindSafe(|| (self.inner)(input)))
});

match res {
Ok(stream) => __internal::token_stream_inner(stream),
Err(e) => {
let msg = "proc macro panicked";
let mut err = ecx.struct_span_fatal(span, msg);
if let Some(s) = e.downcast_ref::<String>() {
err.help(&format!("message: {}", s));
}
if let Some(s) = e.downcast_ref::<&'static str>() {
err.help(&format!("message: {}", s));
}

err.emit();
panic!(FatalError);
}
}
}
}
66 changes: 57 additions & 9 deletions src/libsyntax_ext/proc_macro_registrar.rs
< 6D40 td class="blob-num blob-num-addition empty-cell">
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,25 @@ use syntax_pos::{Span, DUMMY_SP};

use deriving;

const PROC_MACRO_KINDS: [&'static str; 3] =
["proc_macro_derive", "proc_macro_attribute", "proc_macro"];

struct ProcMacroDerive {
trait_name: ast::Name,
function_name: Ident,
span: Span,
attrs: Vec<ast::Name>,
}

struct AttrProcMacro {
struct ProcMacroDef {
function_name: Ident,
span: Span,
}

struct CollectProcMacros<'a> {
derives: Vec<ProcMacroDerive>,
attr_macros: Vec<AttrProcMacro>,
attr_macros: Vec<ProcMacroDef>,
bang_macros: Vec<ProcMacroDef>,
in_root: bool,
handler: &'a errors::Handler,
is_proc_macro_crate: bool,
Expand All @@ -58,17 +62,18 @@ pub fn modify(sess: &ParseSess,
let ecfg = ExpansionConfig::default("proc_macro".to_string());
let mut cx = ExtCtxt::new(sess, ecfg, resolver);

let (derives, attr_macros) = {
let (derives, attr_macros, bang_macros) = {
let mut collect = CollectProcMacros {
derives: Vec::new(),
attr_macros: Vec::new(),
bang_macros: Vec::new(),
in_root: true,
handler: handler,
is_proc_macro_crate: is_proc_macro_crate,
is_test_crate: is_test_crate,
};
visit::walk_crate(&mut collect, &krate);
(collect.derives, collect.attr_macros)
(collect.derives, collect.attr_macros, collect.bang_macros)
};

if !is_proc_macro_crate {
Expand All @@ -83,7 +88,7 @@ pub fn modify(sess: &ParseSess,
return krate;
}

krate.module.items.push(mk_registrar(&mut cx, &derives, &attr_macros));
krate.module.items.push(mk_registrar(&mut cx, &derives, &attr_macros, &bang_macros));

if krate.exported_macros.len() > 0 {
handler.err("cannot export macro_rules! macros from a `proc-macro` \
Expand All @@ -93,6 +98,10 @@ pub fn modify(sess: &ParseSess,
return krate
}

fn is_proc_macro_attr(attr: &ast::Attribute) -> bool {
PROC_MACRO_KINDS.iter().any(|kind| attr.check_name(kind))
}

impl<'a> CollectProcMacros<'a> {
fn check_not_pub_in_root(&self, vis: &ast::Visibility, sp: Span) {
if self.is_proc_macro_crate &&
Expand Down Expand Up @@ -196,12 +205,12 @@ impl<'a> CollectProcMacros<'a> {
fn collect_attr_proc_macro(&mut self, item: &'a ast::Item, attr: &'a ast::Attribute) {
if let Some(_) = attr.meta_item_list() {
self.handler.span_err(attr.span, "`#[proc_macro_attribute]` attribute
cannot contain any meta items");
does not take any arguments");
return;
}

if self.in_root && item.vis == ast::Visibility::Public {
self.attr_macros.push(AttrProcMacro {
self.attr_macros.push(ProcMacroDef {
span: item.span,
function_name: item.ident,
});
Expand All @@ -215,6 +224,29 @@ impl<'a> CollectProcMacros<'a> {
self.handler.span_err(item.span, msg);
}
}

fn collect_bang_proc_macro(&mut self, item: &'a ast::Item, attr: &'a ast::Attribute) {
if let Some(_) = attr.meta_item_list() {
self.handler.span_err(attr.span, "`#[proc_macro]` attribute
does not take any arguments");
return;
}

if self.in_root && item.vis == ast::Visibility::Public {
self.bang_macros.push(ProcMacroDef {
span: item.span,
function_name: item.ident,
});
} else {
let msg = if !self.in_root {
"functions tagged with `#[proc_macro]` must \
currently reside in the root of the crate"
} else {
"functions tagged with `#[proc_macro]` must be `pub`"
};
self.handler.span_err(item.span, msg);
}
}
}

impl<'a> Visitor<'a> for CollectProcMacros<'a> {
Expand All @@ -232,7 +264,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
let mut found_attr: Option<&'a ast::Attribute> = None;

for attr in &item.attrs {
if attr.check_name("proc_macro_derive") || attr.check_name("proc_macro_attribute") {
if is_proc_macro_attr(&attr) {
if let Some(prev_attr) = found_attr {
let msg = if attr.name() == prev_attr.name() {
format!("Only one `#[{}]` attribute is allowed on any given function",
Expand Down Expand Up @@ -285,6 +317,8 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
self.collect_custom_derive(item, attr);
} else if attr.check_name("proc_macro_attribute") {
self.collect_attr_proc_macro(item, attr);
} else if attr.check_name("proc_macro") {
self.collect_bang_proc_macro(item, attr);
};

visit::walk_item(self, item);
Expand Down Expand Up @@ -320,7 +354,8 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
// }
fn mk_registrar(cx: &mut ExtCtxt,
custom_derives: &[ProcMacroDerive],
custom_attrs: &[AttrProcMacro]) -> P<ast::Item> {
custom_attrs: &[ProcMacroDef],
custom_macros: &[ProcMacroDef]) -> P<ast::Item> {
let eid = cx.codemap().record_expansion(ExpnInfo {
call_site: DUMMY_SP,
callee: NameAndSpan {
Expand All @@ -342,6 +377,7 @@ fn mk_registrar(cx: &mut ExtCtxt,
let registrar = Ident::from_str("registrar");
let register_custom_derive = Ident::from_str("register_custom_derive");
let register_attr_proc_macro = Ident::from_str("register_attr_proc_macro");
let register_bang_proc_macro = Ident::from_str("register_bang_proc_macro");

let mut stmts = custom_derives.iter().map(|cd| {
let path = cx.path_global(cd.span, vec![cd.function_name]);
Expand Down Expand Up @@ -371,6 +407,18 @@ fn mk_registrar(cx: &mut ExtCtxt,
vec![registrar, name, cx.expr_path(path)]))
}));

stmts.extend(custom_macros.iter().map(|cm| {
let name = cx.expr_str(cm.span, cm.function_name.name);
let path = cx.path_global(cm.span, vec![cm.function_name]);
let registrar = cx.expr_ident(cm.span, registrar);

let ufcs_path = cx.path(span,
vec![proc_macro, __internal, registry, register_bang_proc_macro]);

cx.stmt_expr(cx.expr_call(span, cx.expr_path(ufcs_path),
vec![registrar, name, cx.expr_path(path)]))
}));

let path = cx.path(span, vec![proc_macro, __internal, registry]);
let registrar_path = cx.ty_path(path);
let arg_ty = cx.ty_rptr(span, registrar_path, None, ast::Mutability::Mutable);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// force-host
// no-prefer-dynamic
#![feature(proc_macro)]
#![crate_type = "proc-macro"]

extern crate proc_macro;

use proc_macro::TokenStream;

#[proc_macro]
pub fn bang_proc_macro(input: TokenStream) -> TokenStream {
input
}
21 changes: 21 additions & 0 deletions src/test/compile-fail-fulldeps/proc-macro/macro-use-bang.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// aux-build:bang_proc_macro.rs

#![feature(proc_macro)]

#[macro_use]
extern crate bang_proc_macro;

fn main() {
bang_proc_macro!(println!("Hello, world!"));
//~^ ERROR: procedural macros cannot be imported with `#[macro_use]`
}
12 changes: 12 additions & 0 deletions src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
// aux-build:derive-foo.rs
// aux-build:derive-clona.rs
// aux-build:attr_proc_macro.rs
// aux-build:bang_proc_macro.rs

#![feature(proc_macro)]

Expand All @@ -19,13 +20,19 @@ extern crate derive_foo;
#[macro_use]
extern crate derive_clona;
extern crate attr_proc_macro;
extern crate bang_proc_macro;

use attr_proc_macro::attr_proc_macro;
use bang_proc_macro::bang_proc_macro;

macro_rules! FooWithLongNam {
() => {}
}

macro_rules! attr_proc_mac {
() => {}
}

#[derive(FooWithLongNan)]
//~^ ERROR cannot find derive macro `FooWithLongNan` in this scope
//~^^ HELP did you mean `FooWithLongName`?
Expand Down Expand Up @@ -61,7 +68,12 @@ fn main() {

attr_proc_macra!();
//~^ ERROR cannot find macro `attr_proc_macra!` in this scope
//~^^ HELP did you mean `attr_proc_mac!`?

Dlona!();
//~^ ERROR cannot find macro `Dlona!` in this scope

bang_proc_macrp!();
//~^ ERROR cannot find macro `bang_proc_macrp!` in this scope
//~^^ HELP did you mean `bang_proc_macro!`?
}
26 changes: 26 additions & 0 deletions src/test/run-pass-fulldeps/proc-macro/auxiliary/bang-macro.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// no-prefer-dynamic
#![feature(proc_macro)]
#![crate_type = "proc-macro"]

extern crate proc_macro;

use proc_macro::TokenStream;

#[proc_macro]
pub fn rewrite(input: TokenStream) -> TokenStream {
let input = input.to_string();

assert_eq!(input, r#""Hello, world!""#);

r#""NOT Hello, world!""#.parse().unwrap()
}
20 changes: 20 additions & 0 deletions src/test/run-pass-fulldeps/proc-macro/bang-macro.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// aux-build:bang-macro.rs

#![feature(proc_macro)]

extern crate bang_macro;
use bang_macro::rewrite;

fn main() {
assert_eq!(rewrite!("Hello, world!"), "NOT Hello, world!");
}
0