-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
What exactly token streams are passed to procedural macros 1.2 #50038
Comments
Alternatives:
|
I don't know if this deserves its own issue, but I think there should be a way for a
|
Actually #47786 is probably a better place to suggest that one. |
Thanks for bringing these issues up @petrochenkov! Your proposed solutions sounds pretty good to me, but I wanted to clarify a point or two as well. For For I wanted to clarify, though, are you thinking the delimiter is dropped from the token stream going into |
@alexcrichton Absolute paths in attributes allow them to work at the crate root where they otherwise won't resolve due to scoping rules (#41430, attributes resolve in the parent module but the crate root has no parent). So unless we want to change the inner attribute form to resolve in the current module instead of the parent, absolute paths are the only way to call attributes at the crate root. |
@abonander ah true yeah, but the first pass of stabilization of Macros 1.2 won't stabilize attributes on modules (or crates), only bare items like functions, structs, impls, traits, etc. |
@alexcrichton we're not currently feature gating attribute invocations on modules or at the crate root so that needs to be its own issue. It would be a bit more complex as we'd have to wait until the attribute resolves to a |
Oh sure yeah when I say only allow one element that's just for now, we'd still, I'd imagine, allow absolute paths and more-than-one-element paths behind a feature gate. |
Absolute paths in attributes are already feature gated, actually. Would |
Perhaps yeah, I might be more of a fan of finer-grained feature gates after the next round of stabilization, but either way is fine. |
Yeah, I'm not sure what is better too and tend to leave things as is for now and introduce a separate signature later.
Yes (#35896 (comment)), but that falls more under the "macro modularisation" issue, so I didn't mention it again.
Yes.
Differentiating between |
One more alternative is to keep the delimiter in |
Ok that sounds pretty compelling to me! I thinks it's definitely clear that one work item here is:
When I was thinking that we'd require the
@petrochenkov do you think there's more work items though we need to close this out? |
No, the listed three items seem to cover everything. Except that I planned to outright prohibit attribute syntaxes not matching 5 forms listed in "Proposed solution" in #50038 (comment), some of those 5 forms can be kept unstable on top of that though. |
Sounds fine by me! |
I'm working on these changes and I should have a PR to post soon |
This commit starts to lay some groundwork for the stabilization of custom attribute invocations and general procedural macros. It applies a number of changes discussed on [internals] as well as a [recent issue][issue], namely: * The path used to specify a custom attribute must be of length one and cannot be a global path. This'll help future-proof us against any ambiguities and give us more time to settle the precise syntax. In the meantime though a bare identifier can be used and imported to invoke a custom attribute macro. A new feature gate, `proc_macro_path_invoc`, was added to gate multi-segment paths and absolute paths. * The set of items which can be annotated by a custom procedural attribute has been restricted. Statements, expressions, and modules are disallowed behind two new feature gates: `proc_macro_expr` and `proc_macro_mod`. * The input to procedural macro attributes has been restricted and adjusted. Today an invocation like `#[foo(bar)]` will receive `(bar)` as the input token stream, but after this PR it will only receive `bar` (the delimiters were removed). Invocations like `#[foo]` are still allowed and will be invoked in the same way as `#[foo()]`. This is a **breaking change** for all nightly users as the syntax coming in to procedural macros will be tweaked slightly. * Procedural macros (`foo!()` style) can only be expanded to item-like items by default. A separate feature gate, `proc_macro_non_items`, is required to expand to items like expressions, statements, etc. Closes rust-lang#50038 [internals]: https://internals.rust-lang.org/t/help-stabilize-a-subset-of-macros-2-0/7252 [issue]: rust-lang#50038
…nkov rustc: Tweak custom attribute capabilities This commit starts to lay some groundwork for the stabilization of custom attribute invocations and general procedural macros. It applies a number of changes discussed on [internals] as well as a [recent issue][issue], namely: * The path used to specify a custom attribute must be of length one and cannot be a global path. This'll help future-proof us against any ambiguities and give us more time to settle the precise syntax. In the meantime though a bare identifier can be used and imported to invoke a custom attribute macro. A new feature gate, `proc_macro_path_invoc`, was added to gate multi-segment paths and absolute paths. * The set of items which can be annotated by a custom procedural attribute has been restricted. Statements, expressions, and modules are disallowed behind two new feature gates: `proc_macro_expr` and `proc_macro_mod`. * The input to procedural macro attributes has been restricted and adjusted. Today an invocation like `#[foo(bar)]` will receive `(bar)` as the input token stream, but after this PR it will only receive `bar` (the delimiters were removed). Invocations like `#[foo]` are still allowed and will be invoked in the same way as `#[foo()]`. This is a **breaking change** for all nightly users as the syntax coming in to procedural macros will be tweaked slightly. * Procedural macros (`foo!()` style) can only be expanded to item-like items by default. A separate feature gate, `proc_macro_non_items`, is required to expand to items like expressions, statements, etc. Closes #50038 [internals]: https://internals.rust-lang.org/t/help-stabilize-a-subset-of-macros-2-0/7252 [issue]: #50038
This is an issue that needs to be resolved before stabilization of "Macros 1.2".
Procedural macros that we are going to stabilize currently have two flavors -
proc_macro
andproc_macro_attribute
.proc_macro
macros have signaturefn(TokenStream) -> TokenStream
and can be invoked with "bang" forms like this:Only the
TOKEN_STREAM
part is passed to the macro asTokenStream
, the delimiters (brackets) are NOT passed.Why this is bad:
It was a part of Macro 2.0 promise to give macros control over delimiters in their invocations, so e.g.
vec
-like macros could require square brackets likevec![1, 2, 3]
and reject other brackets.We should not prevent this kind of control being implemented in the future.
Why this is good:
proc_macro_attribute
macros have signaturefn(TokenStream, TokenStream) -> TokenStream
and can be invoked with "attribute" forms like this:TARGET
is a trait/impl/foreign item, or a statement and it's passed to the macro as the secondTokenStream
argument, but we are not interested in it right now.The
TOKEN_STREAM
part is passed to the macro as the firstTokenStream
argument, nothing is ignored.Why this is bad:
Something like
#[a::b :: + -]
seems to match the grammar, but is rejected right now because paths always parsed greedily so::
is interpreted as a path separator rather than a path of the token stream.Annoying questions arise with generic arguments in paths like
#[a<>::b::c<u8>]
. Technically this is a syntactically valid path andc
having type arguments is rather a semantic error and the empty<>
after the modulea
is not an error at all, but rigth now this attribute is interpreted as#[a /* <- PATH | TOKEN_STREAM -> */ <>::b::c<u8>]
.Ideally we'd like to avoid these questions completely and have an unambiguous delimiter.
With plain
#[attr TOKEN_STREAM]
it's pretty clear - the stream ends before the]
(in this sense the situation is simpler than with bang macros), but things start breaking when other macros appear.meta
anymore!proc_macro
macros.m!(a, b, c)
does not include parentheses into the token stream, but#[m(a, b, c)]
does.#[attr]
,#[attr(list)]
,#[attr = literal]
) to being nearly unlimited (i.e. something like#[a::b::c e f + c ,,, ;_:]
being legal) right now.Proposed solution:
Stabilize
proc_macro
as is for "Macros 1.2".In the future extend the set of
proc_macro
plugin interfaces with one more signaturefn(TokenStream, Delimiter) -> TokenStream
that allows controlling delimiters used in macro invocations.In the future possibly support bang macro invocations without delimiters for symmetry with attributes and because they may be legitimately useful (
let x = MACRO_CONST!;
, see https://internals.rust-lang.org/t/idea-elide-parens-brackets-on-unparametrized-macros/6527) (theDelimiter
argument isDelimiter::None
in this case).Restrict attribute syntax accepted by
proc_macro_attribute
for "Macros 1.2" toOr, more radically, do not stabilize the
=
syntax for procedural macros 1.2.This is not a fundamental restriction - arbitrary token streams still can be placed inside the brackets (
#[a::b::c(e f + c ,,, ;_:)]
).The token stream passed to the macro DOES NOT include the delimiters.
In the future extend the set of
proc_macro_attribute
plugin interfaces with one more signaturefn(TokenStream, TokenStream, Delimiter) -> TokenStream
that allows controlling delimiters used in macro invocations (the delimiter isDelimiter::None
for both#[attr]
and#[attr = tt]
forms but they are still discernable by the token stream being empty or not).The text was updated successfully, but these errors were encountered: