Repository navigation
Description
Current Status
This issue has been closed in favor of more fine-grained tracking issues
~~~Updated Description~~~
Next steps:
- Stabilize
use_extern_macros- waiting on crater
- Stabilize the
proc_macrofeature
Possible Stabilization Showstoppers
- Hygiene is weird
Hygiene is weirder- Supporting module system macros with
macro_rules!and also having pre-1.29 compat is hard
Original Description
RFC.
This RFC proposes an evolution of Rust's procedural macro system (aka syntax
extensions, aka compiler plugins). This RFC specifies syntax for the definition
of procedural macros, a high-level view of their implementation in the compiler,
and outlines how they interact with the compilation process.
At the highest level, macros are defined by implementing functions marked with
a#[macro]attribute. Macros operate on a list of tokens provided by the
compiler and return a list of tokens that the macro use is replaced by. We
provide low-level facilities for operating on these tokens. Higher level
facilities (e.g., for parsing tokens to an AST) should exist as library crates.
Roadmap: #38356 (comment).
Tasks
- Implement
#[proc_macro_attribute](PR Implement#[proc_macro_attribute]#38842). - Implement
#[proc_macro](PR Implement function-like procedural macros (#[proc_macro]) #40129). - Identify and collect uses of
proc_macro_derives in theInvocationCollector(PR [WIP] Expand#[derive(..)]s in the InvocationCollector #39391). - Support macro-expanded
proc_macro_deriveimports.- For example:
#[derive(Trait, OtherTrait)] struct S; // Both these derives should resolve
macro_rules! m { () => {
#[macro_use(Trait)] extern crate derives;
use derives::OtherTrait; // this kind of import is gated behind `#![feature(proc_macro)]`
} }
m!();- Expand items before expanding applied
proc_macro_derives (PR Expand items before their derives #48465). - Implement warnings for unused
#[macro_use]imports (PR Improve unusedextern crateand unused#[macro_use]warnings #39060). - Refactor the parser to consume token trees (PR Refactor the parser to consume token trees #39118).
- Clean up
TokenStreamin preparation for further refactoring (PR RefactorTokenStream#39173). - Remove
TokenTree::Sequence(PR SimplifyTokenTreeand fixmacro_rules!bugs #39419). - Use
TokenStreams instead ofVec<TokenTree>intokenstream::TokenTree'sDelimitedvariant (PR syntax: integrateTokenStream#40202). - Use
Paths andTokenStreams inast::Attributes (PRTokenStream-based attributes, paths in attribute and derive macro invocations #40346).- Support nontrivial paths in attribute/derive macros (e.g.
#[foo::bar],#[derive(foo::Bar)]).
- Support nontrivial paths in attribute/derive macros (e.g.
- Include hygiene information with all tokens, not just identifiers (PR macros: improve
Span's expansion information #40597). - Implement a minimal API for
proc_macro::TokenStreamas outlined in the RFC (PR proc_macro: implementTokenTree,TokenKind, hygienicquote!, and other API #40939).- Include source
TokenStreams for interpolated AST fragments inToken::Interpolatedtokens. - Include a
TokenStreamquoterproc_macro::quote!behind theproc_macrofeature gate.
- Include source
- Provide a way for
proc_macroauthors to create expansions that use items in a predetermined cratefoowithout requiring the macro user to includeextern crate foo;at the crate root (PR proc_macro: implementTokenTree,TokenKind, hygienicquote!, and other API #40939).- Improve ergonomics.
- Include source
TokenStreams for items in the AST. - Stability check (proc-)macros (issue able to invoke unstable macro 2.0 #34079).
- Allow proc macro to initialize a private field with a def_site value (issue Allow proc macro to initialize a private field with a def_site value #47311). (PR macros: improve struct constructor field hygiene, fix span bug #48082)
- Inconsistency between accessing field of braced struct vs tuple struct in proc macro (issue Inconsistency between accessing field of braced struct vs tuple struct in proc macro #47312). (PR Improve tuple struct field access hygiene #48083)
- Make std available to proc macro root in phase 1 (issue Make std available to proc macro root in phase 1 #47314).
- Improve error from invalid syntax inside
proc_macro::quote!(issue Improve error from invalid syntax insideproc_macro::quote!#47315). - Inconsistency between Display and IntoIterator for a TokenStream containing a module (issue Inconsistency between Display and IntoIterator for a TokenStream containing a module #47627).
- #[cfg_attr] makes .to_string() and TokenStream disagree (issue Macros 2.0: #[cfg_attr] makes .to_string() and TokenStream disagree #48644).
- Wishlist for libproc_macro (checklist in Wishlist for libproc_macro #47786).
Activity
aturon commentedon Dec 13, 2016
cc @nrc @jseyfried
abonander commentedon Jan 1, 2017
I'd love for
#[proc_macro_attribute]to be implemented soon. I already have a prototype and test usage that I banged out before realizing there's no compiler support yet 😒 :Prototype: https://github.com/abonander/anterofit/blob/proc_macro/macros/src/lib.rs
Example/Test: https://github.com/abonander/anterofit/blob/proc_macro/examples/post_service_proc_macro.rs
jseyfried commentedon Jan 23, 2017
Tasks
(dtolnay edit: moved the checklist up to the OP)
cc @nrc @petrochenkov @durka @Ralith
abonander commentedon Jan 24, 2017
@jseyfried I ran into an issue where if a legacy macro and an attribute with the same name are imported into the same scope, trying to use the attribute throws an error that macros cannot be used as attributes. Can we make this work so that both can be in the same scope and can be used as intended?
jseyfried commentedon Jan 24, 2017
@abonander All macros (bang, attribute, and derive) share the same namespace, so we can't use two different macros with the same name in the same scope. However, we could improve that error message -- could you open an issue?
SimonSapin commentedon Feb 1, 2017
Sorry I’m late to the party. I’m happy with the direction to expose tokens rather than an AST, but I have some concerns about the specific
TokenStreamAPI proposed in the RFC:It’s not clear if this API was intended as a complete plan that was accepted when the RFC was merged, or just an example to be worked out later.
Generally, this seems far from the "normal" Rust syntax accepted by the compiler outside of macros. While some macros will want to parse some ad-hoc domain-specific language, others will want to parse "actual Rust" syntax and make sense of it.
(Minor) I don’t think
Eofis necessary. AnIteratorwill presumably be used to, well, iterate over aTokenStreamandIterator::nextalready returnsNoneto signal the end of iteration.(Minor) I don’t think
Exclamation,Dollar, orSemicolonare necessary. Matching onPunctuation('!')for example is not more difficult.(Minor) As others have mentioned in the RFC PR, we might want to omit comments that are not doc-comments. (Any use case that wants to preserve comment likely wants to preserve whitespace too.)
As far as I can tell, what to do with multi-character operators (that probably should be a single token each) is still an open question. A possible solution is discussed in PR comments, but it looks like that didn’t make it into RFC text.
Number literals are missing. Are macros supposed to parse
[Punct('1'), Punct('_'), Punct('2'), Punct('3'), Punct('4'), Punct('.'), Punct('5'), Punct('e'), Punct('6')]by themselves to evaluate a literal? They can’t even usestr::parse::<f32>to do that, since the syntax it accepts is not the same as Rust literal syntax (which can have_in the middle, for example).I imagine that there’s a stability concern here. Can we introduce new numeric types like
u128/i128(and possibly in the futuref128,u256, …) and their literals, without breaking changes to the tokens API? One way to make this possible might be:Or maybe something else. But I don’t think "pretend numbers don’t exist" is a good way to do it.
This definition needs to be more precise than that. UAX 31 specifies a couple different variations of identifier syntax, and none of them is called "word". But choosing which exact variation we want is why non-ASCII identifiers are feature-gated at the moment.
Instead, I think this should be defined as "whatever the current compiler accepts as an identifier or keyword" (which can change per Tracking issue for non-ASCII identifiers (feature "non_ascii_idents") #28979). Maybe with a
pub fn is_identifier(&str) -> boolpublic API in libmacro.Unicode strings and byte string literals share a single token variant, which I think is wrong as the memory representations of their values have different types (
strvs[u8]). It’s also not clear if thetext: Symbolcomponent is intended to be a literal slice of the source code or the value after resolving backslash escapes. I think it should definitely be the latter. (For comparison,Char(char)has to be the latter since\u{A0}takes more than onecharto represent literally.)Change tracking issue for `proc_macro` feature to rust-lang#38356
Rollup merge of rust-lang#39454 - abonander:proc_macro_tracking_issue…
Rollup merge of rust-lang#39454 - abonander:proc_macro_tracking_issue…
Rollup merge of rust-lang#39454 - abonander:proc_macro_tracking_issue…
Rollup merge of rust-lang#39454 - abonander:proc_macro_tracking_issue…
204 remaining items
sgrif commentedon Sep 7, 2018
Given the amount of discussion/traffic this issue gets, does it make sense to move
proc_macro_diagnosticto its own tracking issue? I'd also like to figure out what the blockers are for the stabilization of that feature, and see if we can push it through. Diesel uses it, and it's been great so far. The lack of this feature on stable is leading to the community creating funky workarounds, like syn's newest version usingcompile_error!in its place.SergioBenitez commentedon Sep 11, 2018
@sgrif I've opened up such an issue: #54140.
xd009642 commentedon Sep 17, 2018
So I'm interesting in helping to stabilise the methods in Span and the LineColumn struct. I'll look at the open issues in the first comment, but if anyone wants to point a newbie to the compiler in a particular direction I'd appreciate it 👍
jjpe commentedon Sep 28, 2018
The
proc_macro_genfeature gate pointed me here, but in the check list at the top I see nothing that obviously refers to a (proc_)macro that generates other macro definitions. Has this been accounted for (other than in rustc's feature gate)?alexcrichton commentedon Sep 28, 2018
@jjpe it's probably best at this time that we spin off dedicated tracking issues for those feature gates, this issue was largely dedicated to the initial wave of stabilizations
jjpe commentedon Sep 30, 2018
@alexcrichton I'm perfectly fine with that, it's more that in the process of looking at the
proc_macro_genfeature, it referred me here only to find as good as no mention of it. That's a bit odd to me, so I decided to mention it, at least.@xieyuheng What would
CodeString/Codeeven look like i.e. what would its semantics be?Keep in mind that
TokenStreamis nothing more than the source code verbatim except as a series of token values rather than bothersome text.SimonSapin commentedon Sep 30, 2018
The extended API for
TokenStream(withTokenTree) is stable in 1.29. Importing function-like proc macros will be stable in 1.30.CodeSandwich commentedon Sep 30, 2018
It seems that since
rustc 1.30.0-nightly (63d51e89a 2018-09-28)it is no longer possible to traverse code inside module in separate file. If you processmod module;, you getTokenStreamcontainingmod module;, WYSIWYG.I understand, that this is necessary in order to preserver spans, hygiene and consistency with processed code. Is there or will be any way to work with content of modules in separate files? Its lack may be confusing for end users when trivial refactoring of module organization causes change in macro behavior.
alexcrichton commentedon Oct 1, 2018
Ok this issue is massive and has gotten to the point that I don't think it's too useful to keep open any more and track APIs. To that end I've opened #54728 which splits this issue into a number of more fine-grained tracking issues:
quote!macro inproc_macro#54722 - thequote!macroproc_macro::Ident::new_raw#54723 -Ident::new_rawSpan::def_site()#54724 -Span::def_siteproc_macroand diagnosticsproc_macro::Spaninspection APIs #54725 - inspecting aproc_macro::SpanAt this point I'm going to close this, but if I've forgotten to split off any other tracking issues please let me know! I can certainly open up some more follow-ups
Rollup merge of rust-lang#54728 - alexcrichton:renumber-issues, r=nik…
Rollup merge of rust-lang#54728 - alexcrichton:renumber-issues, r=nik…
XX commentedon Nov 23, 2018
@alexcrichton What about of sub-attributes for attribute-like macro?
#38356 (comment)
Is there a issue for this?
petrochenkov commentedon Nov 23, 2018
@XX
Such sub-attributes don't necessarily have to be a language feature?
In case of
deriveregistration of custom attributes is needed because derive macros cannot remove attributes from their input (the input is immutable).Attribute macros can remove
#[other_attribute]s from its input, so they will never get to name resolution and never report the "unresolved attribute" error.(Beside that classic legacy unstable custom attributes mentioned in #38356 (comment) are now compatible with proc macros.)
XX commentedon Nov 23, 2018
@petrochenkov Yes, thanks for the clarification.