-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Implement function-like procedural macros ( #[proc_macro]
)
#40129
Conversation
Unanswered question: did we decide whether or not to include the outer delimiters from the invocation in the input? i.e. |
function_name: Ident, | ||
span: Span, | ||
} | ||
|
||
struct CollectProcMacros<'a> { | ||
derives: Vec<ProcMacroDerive>, | ||
attr_macros: Vec<AttrProcMacro>, | ||
attr_macros: Vec<ProcMacroDef>, | ||
bang_macros: Vec<ProcMacroDef>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm on the fence about reusing the typedef. I didn't see much point to having a unique type with the same signature.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good as is.
pub fn rewrite(input: TokenStream) -> TokenStream { | ||
let input = input.to_string(); | ||
|
||
assert_eq!(input, r#""Hello, world!""#); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might fail the test because the wrapping delimiters might get included. I forget what the executive decision was on whether or not to include those.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, works as-is.
#[proc_macro]
)#[proc_macro]
)
bdbadad
to
fcebcf4
Compare
Looks like I didn't have to do any extra work to support that as-is, very nice. |
@@ -232,7 +257,8 @@ 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 attr.check_name("proc_macro_derive") || attr.check_name("proc_macro_attribute") || | |||
attr.check_name("proc_macro") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Formatting suggestion welcome here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be indented three spaces (to align with first condition) or eight spaces (to distinguish from body).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eh, I don't really like how either of those look so it's your call. I would almost prefer a .check_names()
method which can take a slice or iterator or something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case I'd write:
if PROC_MACRO_KINDS.iter().any(|kind| attr.check_name(kind)) { ... }
where
const PROC_MACRO_KINDS: [&'static str, 3] =
["proc_macro", "proc_macro_attribute", "proc_macro_derive"];
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good. I might use the static-in-const
feature to make that a little shorter too.
@@ -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, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bikeshed: "fnlike" instead of "bang"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer Bang
inside the compiler to avoid overloading "function". Also, we might want to use "proc macro function" for the underlying function item annotated with #[proc_macro*]
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, we might want to use "proc macro function" for the underlying function item annotated with #[proc_macro*].
Clarify?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For #[proc_macro_derive(A)] fn f(..) { .. }
, we would say A
is a [derive] proc macro and f
is the [derive] proc macro function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay. That doesn't affect anything in this PR, though, right? That's purely wording for documentation and stuff?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it's just an argument for "bang proc macro" instead of "function / fnlike procedural macro".
c7035cb
to
e7f258e
Compare
src/libsyntax/feature_gate.rs
Outdated
("proc_macro", Normal, Gated(Stability::Unstable, | ||
"proc_macro", | ||
"function-like proc macros are currently unstable", | ||
cfg_fn!(proc_macro))), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: These should be indented to the same column as Stability::Unstable,
.
} | ||
if let Some(s) = e.downcast_ref::<&'static str>() { | ||
err.help(&format!("message: {}", s)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to factor this out to avoid duplication across macro kinds (not needed for this PR though).
@@ -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"]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I would break after the =
or give each macro kind its own line.
function_name: Ident, | ||
span: Span, | ||
} | ||
|
||
struct CollectProcMacros<'a> { | ||
derives: Vec<ProcMacroDerive>, | ||
attr_macros: Vec<AttrProcMacro>, | ||
attr_macros: Vec<ProcMacroDef>, | ||
bang_macros: Vec<ProcMacroDef>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good as is.
@abonander Looks great! What happens when we |
I'll have to test that, I think we're only checking that in the attribute proc macro codepath. |
Only supporting @abonander Nice. Maybe you'd like to add a misspelled call for a proc macro to this test, so we can test suggestions? They should be working, but it would be good to make sure. |
Yeah |
|
||
// aux-build:bang-macro.rs | ||
|
||
#![allow(warnings)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't. I copy-pasted this from another file to get the copyright and stuff and I must have forgotten to remove that.
@abonander Awesome, thanks. |
489cd50
to
1be0a59
Compare
@jseyfried Last nits fixed and rebased. |
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 | ||
cannot contain any meta items"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"meta item" is compiler jargon -- I'd say "does not accept arguments" (also applies to proc_macro_attribute
).
fn main() { | ||
bang_proc_macro!(println!("Hello, world!")); | ||
//~^ ERROR: procedural macros cannot be imported with `#[macro_use]` | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: trailing newline
r=me modulo comments |
✌️ @abonander can now approve this pull request |
1be0a59
to
2fcbb48
Compare
@bors r=jseyfried |
📌 Commit 2fcbb48 has been approved by |
Implement function-like procedural macros ( `#[proc_macro]`) Adds the `#[proc_macro]` attribute, which expects bare functions of the kind `fn(TokenStream) -> TokenStream`, which can be invoked like `my_macro!()`. cc rust-lang/rfcs#1913, rust-lang#38356 r? @jseyfried cc @nrc
Implement function-like procedural macros ( `#[proc_macro]`) Adds the `#[proc_macro]` attribute, which expects bare functions of the kind `fn(TokenStream) -> TokenStream`, which can be invoked like `my_macro!()`. cc rust-lang/rfcs#1913, rust-lang#38356 r? @jseyfried cc @nrc
Implement function-like procedural macros ( `#[proc_macro]`) Adds the `#[proc_macro]` attribute, which expects bare functions of the kind `fn(TokenStream) -> TokenStream`, which can be invoked like `my_macro!()`. cc rust-lang/rfcs#1913, rust-lang#38356 r? @jseyfried cc @nrc
Adds the
#[proc_macro]
attribute, which expects bare functions of the kindfn(TokenStream) -> TokenStream
, which can be invoked likemy_macro!()
.cc rust-lang/rfcs#1913, #38356
r? @jseyfried
cc @nrc