Skip to content
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

rustc: Tweak custom attribute capabilities #50120

Merged
merged 1 commit into from
Apr 21, 2018

Conversation

alexcrichton
Copy link
Member

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, 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

@alexcrichton
Copy link
Member Author

r? @petrochenkov

cc @nrc, @dtolnay

@alexcrichton alexcrichton force-pushed the more-proc-macro-gates branch 3 times, most recently from 21ad04d to de1e1a7 Compare April 20, 2018 16:22
@pietroalbini pietroalbini added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Apr 20, 2018
@@ -539,6 +541,45 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}
}

fn extract_proc_macro_attr_input(&self, tokens: TokenStream, span: Span) -> TokenStream {
match tokens.trees().next() {
Some(TokenTree::Delimited(_, delim)) => delim.tts.into(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still accepts #[attr(delimited token stream) + anything else].
Could you add a test making sure that the example above and also #[attr = "something"] are rejected.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aha excellent point, tests added and fixed

ExpansionKind::Items => return,
ExpansionKind::TraitItems => return,
ExpansionKind::ImplItems => return,
ExpansionKind::ForeignItems => return,
Copy link
Contributor

@petrochenkov petrochenkov Apr 20, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if a proc macro attribute is applied to something else, like match arm (match 0 { #[attr] _ => {} }), or a generic parameter (fn f<#[attr] T>), or enum variant?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect it already produces some kind of error, but it would be good to have a test.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting! Turns out we don't expand procedural macros in those locations right now so you get an "unknown attribute" error. I've added a test to ensure it's at least an error.

@petrochenkov petrochenkov added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Apr 20, 2018
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
@alexcrichton
Copy link
Member Author

Updated!

@petrochenkov
Copy link
Contributor

@bors r+

@bors
Copy link
Contributor

bors commented Apr 21, 2018

📌 Commit 79630d4 has been approved by petrochenkov

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Apr 21, 2018
@bors
Copy link
Contributor

bors commented Apr 21, 2018

⌛ Testing commit 79630d4 with merge 222551f...

bors added a commit that referenced this pull request Apr 21, 2018
…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
@bors
Copy link
Contributor

bors commented Apr 21, 2018

☀️ Test successful - status-appveyor, status-travis
Approved by: petrochenkov
Pushing 222551f to master...

@bors bors merged commit 79630d4 into rust-lang:master Apr 21, 2018
@kennytm-githubbot
Copy link

📣 Toolstate changed by #50120!

Tested on commit 222551f.
Direct link to PR: #50120

💔 clippy-driver on windows: test-pass → test-fail (cc @Manishearth @llogiq @mcarton @oli-obk).
💔 clippy-driver on linux: test-pass → test-fail (cc @Manishearth @llogiq @mcarton @oli-obk).

kennytm-githubbot added a commit to rust-lang-nursery/rust-toolstate that referenced this pull request Apr 21, 2018
Tested on commit rust-lang/rust@222551f.
Direct link to PR: <rust-lang/rust#50120>

💔 clippy-driver on windows: test-pass → test-fail (cc @Manishearth @llogiq @mcarton @oli-obk).
💔 clippy-driver on linux: test-pass → test-fail (cc @Manishearth @llogiq @mcarton @oli-obk).
@nrc
Copy link
Member

nrc commented Apr 22, 2018

@alexcrichton

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.

What's the motivation for this change? The previous behaviour was intentional and spec'ed in the RFC. What's the long-term plan for handling delimiters?

@alexcrichton alexcrichton deleted the more-proc-macro-gates branch April 23, 2018 14:24
@alexcrichton
Copy link
Member Author

@nrc most of the discussion happend in #50038 with the tl;dr; (as I understand it) as:

  • Invocations like foo!() don't have their delimiters in the token stream
  • Eventually we want foo!() to know what delimiter it has (so macros like vec![] require [])
  • Path parsing in attributes is somewhat weird, is #[ a :: b ] macro a or macro a::b? @petrochenkov also has some good comments with the meta matcher in the OP of What exactly token streams are passed to procedural macros 1.2 #50038.
  • In terms of ambiguity, the most conservative route seems to be to only allow #[a ( ... )] which still allows arbitrary syntax but just not next to the name.
  • Eventually though we'd want to support #[a = b], and the thinking is that just like with foo!() you can learn about the delimiter, and if the delimiter is None then it's #[a = b] rather than #[a ( = b )].

Does that make sense? @petrochenkov may be better able to fill in some holes as well.

@SergioBenitez
Copy link
Contributor

SergioBenitez commented Apr 27, 2018

The proc_macro_path_invoc feature gate line shouldn't be applied to invocations of decl-macros. Alternatively, the decl_macro feature should imply proc_macro_path_invoc.

@jcsoo
Copy link

jcsoo commented Apr 27, 2018

This seems to break crates that are using #![feature(use_extern_macros)] and invoking them like this:

error[E0658]: paths of length greater than one in macro invocations are currently unstable
    --> /Users/jcsoo/bobbin-dev/bobbin-dev/mcu/bobbin-stm32/stm32f74x/src/irq.rs:1413:1
     |
1413 | ::bobbin_mcu::irq!(::dma::Dma2Stream7, IrqDma, Irq70);
     | ^^^^^^^^^^^^^^^^^
     |
     = help: add #![feature(proc_macro_path_invoc)] to the crate attributes to enable

Is that intended?

@alexcrichton
Copy link
Member Author

Ah oops yes indeed! I don't think that bang-style macros have the same ambiguity with attribute-related macros, so we should be able to unambiguously allow path-like invocations of bang macros (both decl_macro and #[proc_macro] macros).

@jcsoo or @SergioBenitez want to file a bug to track this?

@SergioBenitez
Copy link
Contributor

@alexcrichton Submitted a PR instead: #50295

bors added a commit that referenced this pull request Apr 28, 2018
Don't feature gate bang macros on 'proc_macro_path_invoc'.

Fixes oversight from #50120.
ngg added a commit to ngg/futures-rs that referenced this pull request Apr 29, 2018
After rust-lang/rust#50120 procedural
macros do not receive the parentheses as part of their attributes
TokenStream. Also the proc_macro_non_items feature is necessary
to use async_block.
ngg added a commit to ngg/futures-rs that referenced this pull request Apr 29, 2018
After rust-lang/rust#50120 procedural
macros do not receive the parentheses as part of their attributes
TokenStream. Also the proc_macro_non_items feature is necessary
to use async_block.
ngg added a commit to ngg/futures-rs that referenced this pull request Apr 30, 2018
After rust-lang/rust#50120 procedural
macros do not receive the parentheses as part of their attributes
TokenStream. Also the proc_macro_non_items feature is necessary
to use async_block.
cramertj pushed a commit to rust-lang/futures-rs that referenced this pull request Apr 30, 2018
After rust-lang/rust#50120 procedural
macros do not receive the parentheses as part of their attributes
TokenStream. Also the proc_macro_non_items feature is necessary
to use async_block.
mystor referenced this pull request in mystor/synstructure Nov 6, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants