Skip to content

Update proc_macro_derive to use the attribute template #1888

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

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion src/attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ The following is an index of all built-in attributes.
[`panic_handler`]: panic.md#the-panic_handler-attribute
[`path`]: items/modules.md#the-path-attribute
[`proc_macro_attribute`]: procedural-macros.md#attribute-macros
[`proc_macro_derive`]: procedural-macros.md#derive-macros
[`proc_macro_derive`]: procedural-macros.md#the-proc_macro_derive-attribute
[`proc_macro`]: procedural-macros.md#function-like-procedural-macros
[`recursion_limit`]: attributes/limits.md#the-recursion_limit-attribute
[`repr`]: type-layout.md#representations
Expand Down
4 changes: 2 additions & 2 deletions src/attributes/derive.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ detect these automatically generated implementations.

[`impl` item]: ../items/implementations.md
[items]: ../items.md
[derive macros]: ../procedural-macros.md#derive-macros
[derive macros]: ../procedural-macros.md#the-proc_macro_derive-attribute
[implementations]: ../items/implementations.md
[items]: ../items.md
[procedural macros]: ../procedural-macros.md#derive-macros
[procedural macros]: ../procedural-macros.md#the-proc_macro_derive-attribute
2 changes: 1 addition & 1 deletion src/items/use-declarations.md
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ fn main() {
[associated items]: associated-items.md
[Attributes]: ../attributes.md
[Built-in types]: ../types.md
[Derive macros]: ../procedural-macros.md#derive-macros
[Derive macros]: ../procedural-macros.md#the-proc_macro_derive-attribute
[Enum variants]: enumerations.md
[extern prelude]: ../names/preludes.md#extern-prelude
[generic parameters]: generics.md
Expand Down
2 changes: 1 addition & 1 deletion src/names/namespaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ It is still an error for a [`use` import] to shadow another macro, regardless of
[closure]: ../expressions/closure-expr.md
[Constant item declarations]: ../items/constant-items.md
[Derive macro helpers]: ../procedural-macros.md#derive-macro-helper-attributes
[Derive macros]: ../procedural-macros.md#derive-macros
[Derive macros]: ../procedural-macros.md#the-proc_macro_derive-attribute
[entity]: ../glossary.md#entity
[Enum variant constructors]: ../items/enumerations.md
[enum]: ../items/enumerations.md
Expand Down
159 changes: 90 additions & 69 deletions src/procedural-macros.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,94 +131,101 @@ expressions], [item] positions, including items in [`extern` blocks], inherent
and trait [implementations], and [trait definitions].

r[macro.proc.derive]
## Derive macros
## The `proc_macro_derive` attribute

r[macro.proc.derive.intro]
*Derive macros* define new inputs for the [`derive` attribute]. These macros
can create new [items] given the token stream of a [struct], [enum], or [union].
They can also define [derive macro helper attributes].
The *`proc_macro_derive` [attribute][attributes]* defines a *derive macro* which defines an input for the [`derive` attribute]. These macros can create new [items] given the token stream of a [struct], [enum], or [union]. They can also define [derive macro helper attributes].

r[macro.proc.derive.def]
Custom derive macros are defined by a [public] [function] with the
`proc_macro_derive` attribute and a signature of `(TokenStream) -> TokenStream`.

r[macro.proc.derive.namespace]
The `proc_macro_derive` attribute defines the custom derive in the [macro namespace] in the root of the crate.
> [!EXAMPLE]
> The following is an example of a derive macro. Instead of doing anything useful with its input, it just appends a function `answer`.
>
> <!-- ignore: test doesn't support proc-macro -->
> ```rust,ignore
> # #![crate_type = "proc-macro"]
> extern crate proc_macro;
> use proc_macro::TokenStream;
>
> #[proc_macro_derive(AnswerFn)]
> pub fn derive_answer_fn(_item: TokenStream) -> TokenStream {
> "fn answer() -> u32 { 42 }".parse().unwrap()
> }
> ```
>
> And then using said derive macro:
>
> <!-- ignore: requires external crates -->
> ```rust,ignore
> extern crate proc_macro_examples;
> use proc_macro_examples::AnswerFn;
>
> #[derive(AnswerFn)]
> struct Struct;
>
> fn main() {
> assert_eq!(42, answer());
> }
> ```

r[macro.proc.derive.output]
The input [`TokenStream`] is the token stream of the item that has the `derive`
attribute on it. The output [`TokenStream`] must be a set of items that are
then appended to the [module] or [block] that the item from the input
[`TokenStream`] is in.
r[macro.proc.derive.syntax]
The `proc_macro_derive` attribute uses the following syntax:

The following is an example of a derive macro. Instead of doing anything
useful with its input, it just appends a function `answer`.
```grammar,attributes
@root ProcMacroDeriveAttribute ->
`proc_macro_derive` `(` DeriveMacroName ( `,` DeriveMacroAttributes )? `,`? `)`

<!-- ignore: test doesn't support proc-macro -->
```rust,ignore
# #![crate_type = "proc-macro"]
extern crate proc_macro;
use proc_macro::TokenStream;
DeriveMacroName -> SimplePathSegment

#[proc_macro_derive(AnswerFn)]
pub fn derive_answer_fn(_item: TokenStream) -> TokenStream {
"fn answer() -> u32 { 42 }".parse().unwrap()
}
DeriveMacroAttributes ->
`attributes` `(` ( SimplePathSegment (`,` SimplePathSegment)* `,`?)? `)`
```

And then using said derive macro:
The [DeriveMacroName] is the name of the derive macro. The optional `attributes` are described in [macro.proc.derive.attributes].

<!-- ignore: requires external crates -->
```rust,ignore
extern crate proc_macro_examples;
use proc_macro_examples::AnswerFn;
r[macro.proc.derive.allowed-positions]
The `proc_macro_derive` attribute may only be applied to a function with the signature of `pub fn(TokenStream) -> TokenStream` where [`TokenStream`] comes from the [`proc_macro` crate]. It must have the ["Rust" ABI][items.fn.extern]. No other function qualifiers are allowed.

#[derive(AnswerFn)]
struct Struct;
r[macro.proc.derive.duplicates]
The `proc_macro_derive` attribute may only be specified once on a function.

fn main() {
assert_eq!(42, answer());
}
```
r[macro.proc.derive.namespace]
The `proc_macro_derive` attribute publicly defines the custom derive in the [macro namespace] in the root of the crate with the name given in the attribute.

r[macro.proc.derive.output]
The input [`TokenStream`] is the token stream of the item that has the `derive` attribute on it. The output [`TokenStream`] must be a set of items that are then appended to the [module] or [block] that the item from the input [`TokenStream`] is in.

r[macro.proc.derive.attributes]
### Derive macro helper attributes

r[macro.proc.derive.attributes.intro]
Derive macros can add additional [attributes] into the scope of the [item]
they are on. Said attributes are called *derive macro helper attributes*. These
attributes are [inert], and their only purpose is to be fed into the derive
macro that defined them. That said, they can be seen by all macros.
Derive macros can add additional [attributes] into the scope of the [item] they are on. Said attributes are called *derive macro helper attributes*. These attributes are [inert], and their only purpose is to be fed into the derive macro that defined them. That said, they can be seen by all macros.

r[macro.proc.derive.attributes.def]
The way to define helper attributes is to put an `attributes` key in the
`proc_macro_derive` macro with a comma separated list of identifiers that are
the names of the helper attributes.

For example, the following derive macro defines a helper attribute
`helper`, but ultimately doesn't do anything with it.

<!-- ignore: test doesn't support proc-macro -->
```rust,ignore
# #![crate_type="proc-macro"]
# extern crate proc_macro;
# use proc_macro::TokenStream;

#[proc_macro_derive(HelperAttr, attributes(helper))]
pub fn derive_helper_attr(_item: TokenStream) -> TokenStream {
TokenStream::new()
}
```
The way to define helper attributes is to put an `attributes` key in the `proc_macro_derive` macro with a comma separated list of identifiers that are the names of the helper attributes.

And then usage on the derive macro on a struct:

<!-- ignore: requires external crates -->
```rust,ignore
#[derive(HelperAttr)]
struct Struct {
#[helper] field: ()
}
```
> [!EXAMPLE]
> The following derive macro defines a helper attribute `helper`, but ultimately doesn't do anything with it.
>
> <!-- ignore: test doesn't support proc-macro -->
> ```rust,ignore
> # #![crate_type="proc-macro"]
> # extern crate proc_macro;
> # use proc_macro::TokenStream;
>
> #[proc_macro_derive(HelperAttr, attributes(helper))]
> pub fn derive_helper_attr(_item: TokenStream) -> TokenStream {
> TokenStream::new()
> }
> ```
>
> And then usage on the derive macro on a struct:
>
> <!-- ignore: requires external crates -->
> ```rust,ignore
> #[derive(HelperAttr)]
> struct Struct {
> #[helper] field: ()
> }
> ```

r[macro.proc.attribute]
## Attribute macros
Expand Down Expand Up @@ -375,7 +382,7 @@ their equivalent `#[doc = r"str"]` attributes when passed to macros.

[Attribute macros]: #attribute-macros
[Cargo's build scripts]: ../cargo/reference/build-scripts.html
[Derive macros]: #derive-macros
[Derive macros]: #the-proc_macro_derive-attribute
[Function-like macros]: #function-like-procedural-macros
[`$crate`]: macro.decl.hygiene.crate
[`Delimiter::None`]: proc_macro::Delimiter::None
Expand Down Expand Up @@ -409,3 +416,17 @@ their equivalent `#[doc = r"str"]` attributes when passed to macros.
[type expressions]: types.md#type-expressions
[type]: types.md
[union]: items/unions.md

<script>
(function() {
var fragments = {
"#derive-macros": "procedural-macros.html#the-proc_macro_derive-attribute",
};
var target = fragments[window.location.hash];
if (target) {
var url = window.location.toString();
var base = url.substring(0, url.lastIndexOf('/'));
window.location.replace(base + "/" + target);
}
})();
</script>