From 57cff8cd6928c8f55fce4c0ff66aa2cf3055140f Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 13 Jun 2025 10:14:15 -0700 Subject: [PATCH 1/7] Unwrap proc_macro_derive --- src/procedural-macros.md | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/src/procedural-macros.md b/src/procedural-macros.md index 545b48cc95..24c939724d 100644 --- a/src/procedural-macros.md +++ b/src/procedural-macros.md @@ -134,25 +134,18 @@ r[macro.proc.derive] ## Derive macros 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]. +*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]. 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`. +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. 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. +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. -The following is an example of a derive macro. Instead of doing anything -useful with its input, it just appends a function `answer`. +The following is an example of a derive macro. Instead of doing anything useful with its input, it just appends a function `answer`. ```rust,ignore @@ -185,18 +178,12 @@ 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. +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. +For example, the following derive macro defines a helper attribute `helper`, but ultimately doesn't do anything with it. ```rust,ignore From 63cc743f02d7f749d37ae56ab8d1c7a9e67878e0 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 13 Jun 2025 10:22:10 -0700 Subject: [PATCH 2/7] Rename "Derive macros" section header This renames it to follow the attribute template. Although I like the old title, since it describes what it does, I would prefer to not make exceptions and stay consistent. --- src/attributes.md | 2 +- src/attributes/derive.md | 4 ++-- src/items/use-declarations.md | 2 +- src/names/namespaces.md | 2 +- src/procedural-macros.md | 18 ++++++++++++++++-- 5 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/attributes.md b/src/attributes.md index 7179401c9f..d0b311ea8d 100644 --- a/src/attributes.md +++ b/src/attributes.md @@ -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`]: macro.proc.derive [`proc_macro`]: procedural-macros.md#function-like-procedural-macros [`recursion_limit`]: attributes/limits.md#the-recursion_limit-attribute [`repr`]: type-layout.md#representations diff --git a/src/attributes/derive.md b/src/attributes/derive.md index d65431bc01..aece0484b0 100644 --- a/src/attributes/derive.md +++ b/src/attributes/derive.md @@ -103,7 +103,7 @@ The `automatically_derived` attribute has no behavior. [items]: ../items.md [derive macro]: macro.proc.derive -[derive macros]: ../procedural-macros.md#derive-macros +[derive macros]: macro.proc.derive [implementation]: ../items/implementations.md [items]: ../items.md -[procedural macros]: ../procedural-macros.md#derive-macros +[procedural macros]: macro.proc.derive diff --git a/src/items/use-declarations.md b/src/items/use-declarations.md index ec993d737b..3df3e23879 100644 --- a/src/items/use-declarations.md +++ b/src/items/use-declarations.md @@ -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]: macro.proc.derive [Enum variants]: enumerations.md [extern prelude]: ../names/preludes.md#extern-prelude [generic parameters]: generics.md diff --git a/src/names/namespaces.md b/src/names/namespaces.md index feb0e97710..1794b0fd82 100644 --- a/src/names/namespaces.md +++ b/src/names/namespaces.md @@ -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]: macro.proc.derive [entity]: ../glossary.md#entity [Enum variant constructors]: ../items/enumerations.md [enum]: ../items/enumerations.md diff --git a/src/procedural-macros.md b/src/procedural-macros.md index 24c939724d..087599d4b1 100644 --- a/src/procedural-macros.md +++ b/src/procedural-macros.md @@ -131,7 +131,7 @@ 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]. @@ -362,7 +362,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]: macro.proc.derive [Function-like macros]: #function-like-procedural-macros [`$crate`]: macro.decl.hygiene.crate [`Delimiter::None`]: proc_macro::Delimiter::None @@ -396,3 +396,17 @@ their equivalent `#[doc = r"str"]` attributes when passed to macros. [type expressions]: types.md#type-expressions [type]: types.md [union]: items/unions.md + + From 0163ef7b70cace164bcdeabacf42a6207d524133 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 13 Jun 2025 13:52:38 -0700 Subject: [PATCH 3/7] Reword proc_macro_derive intro This is to follow the attribute template. --- src/procedural-macros.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/procedural-macros.md b/src/procedural-macros.md index 087599d4b1..8bcd8be7b6 100644 --- a/src/procedural-macros.md +++ b/src/procedural-macros.md @@ -134,7 +134,7 @@ r[macro.proc.derive] ## 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`. From eb579f64cb4d6293c73dcb276bf03ab45700a39d Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 13 Jun 2025 13:53:38 -0700 Subject: [PATCH 4/7] Move examples into example blocks --- src/procedural-macros.md | 97 ++++++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 44 deletions(-) diff --git a/src/procedural-macros.md b/src/procedural-macros.md index 8bcd8be7b6..4608e4fc47 100644 --- a/src/procedural-macros.md +++ b/src/procedural-macros.md @@ -138,6 +138,35 @@ The *`proc_macro_derive` [attribute][attributes]* defines a *derive macro* which 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`. +> [!EXAMPLE] +> The following is an example of a derive macro. Instead of doing anything useful with its input, it just appends a function `answer`. +> +> +> ```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: +> +> +> ```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.namespace] The `proc_macro_derive` attribute defines the custom derive in the [macro namespace] in the root of the crate. @@ -145,34 +174,13 @@ The `proc_macro_derive` attribute defines the custom derive in the [macro namesp 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. -The following is an example of a derive macro. Instead of doing anything useful with its input, it just appends a function `answer`. - -```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: - -```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.attributes] ### Derive macro helper attributes @@ -183,29 +191,30 @@ Derive macros can add additional [attributes] into the scope of the [item] they 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. - - -```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: - - -```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. +> +> +> ```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: +> +> +> ```rust,ignore +> #[derive(HelperAttr)] +> struct Struct { +> #[helper] field: () +> } +> ``` r[macro.proc.attribute] ## Attribute macros From b70c6478a8f52c17f3f04c53563982390852bbe6 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 13 Jun 2025 13:54:33 -0700 Subject: [PATCH 5/7] Add proc_macro_derive attribute template rules --- src/procedural-macros.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/procedural-macros.md b/src/procedural-macros.md index 4608e4fc47..3fcd57b9d5 100644 --- a/src/procedural-macros.md +++ b/src/procedural-macros.md @@ -136,8 +136,6 @@ r[macro.proc.derive] r[macro.proc.derive.intro] 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`. > [!EXAMPLE] > The following is an example of a derive macro. Instead of doing anything useful with its input, it just appends a function `answer`. > @@ -173,13 +171,26 @@ The `proc_macro_derive` attribute defines the custom derive in the [macro namesp 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: +```grammar,attributes +@root ProcMacroDeriveAttribute -> + `proc_macro_derive` `(` DeriveMacroName ( `,` DeriveMacroAttributes )? `,`? `)` +DeriveMacroName -> SimplePathSegment +DeriveMacroAttributes -> + `attributes` `(` ( SimplePathSegment (`,` SimplePathSegment)* `,`?)? `)` ``` +The [DeriveMacroName] is the name of the derive macro. The optional `attributes` are described in [macro.proc.derive.attributes]. +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. +r[macro.proc.derive.duplicates] +The `proc_macro_derive` attribute may only be specified once on a function. r[macro.proc.derive.attributes] From 1124ff3cb3e8aaedb90caadba85f18150f2759e0 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 13 Jun 2025 13:54:46 -0700 Subject: [PATCH 6/7] Move proc_macro_attribute rules below the templated rules --- src/procedural-macros.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/procedural-macros.md b/src/procedural-macros.md index 3fcd57b9d5..040ebb99b5 100644 --- a/src/procedural-macros.md +++ b/src/procedural-macros.md @@ -166,11 +166,6 @@ The *`proc_macro_derive` [attribute][attributes]* defines a *derive macro* which > } > ``` -r[macro.proc.derive.namespace] -The `proc_macro_derive` attribute defines the custom derive in the [macro namespace] in the root of the crate. - -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: @@ -192,6 +187,11 @@ The `proc_macro_derive` attribute may only be applied to a function with the sig r[macro.proc.derive.duplicates] The `proc_macro_derive` attribute may only be specified once on a function. +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 From 89789f6a91298b532485a3ae3e2d76c112270a09 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Sun, 3 Aug 2025 00:03:33 +0000 Subject: [PATCH 7/7] Revise `proc_macro_derive` text One thing worth highlighting is that we're preferring to say that we "declare" (rather than "define") derive macro helper attributes. A definition is something that says what something is. For these attributes, though, we're just declaring that they exist. In revising, we've clarified that the derive macro function must appear in the root of the crate and that it may be `const` and may use `extern` (with the allowed ABI) but may not use other qualifiers. We've also changed the syntax to use `IDENTIFIER` rather than `SimplePathSegment`. In testing, none of the other things that would be accepted by the latter are allowed, so it seems more correct in terms of user-visible behavior to use `IDENTIFIER` here. --- src/procedural-macros.md | 42 ++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/procedural-macros.md b/src/procedural-macros.md index 040ebb99b5..a26a57eb2e 100644 --- a/src/procedural-macros.md +++ b/src/procedural-macros.md @@ -134,10 +134,10 @@ r[macro.proc.derive] ## The `proc_macro_derive` attribute r[macro.proc.derive.intro] -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]. +Applying the *`proc_macro_derive` [attribute]* to a function defines a *derive macro* that can be invoked by the [`derive` attribute]. These macros are given the token stream of a [struct], [enum], or [union] definition and can emit new [items] after it. They can also declare and use [derive macro helper attributes]. > [!EXAMPLE] -> The following is an example of a derive macro. Instead of doing anything useful with its input, it just appends a function `answer`. +> This derive macro ignores its input and appends tokens that define a function. > > > ```rust,ignore @@ -151,7 +151,7 @@ The *`proc_macro_derive` [attribute][attributes]* defines a *derive macro* which > } > ``` > -> And then using said derive macro: +> To use it, we might write: > > > ```rust,ignore @@ -167,63 +167,63 @@ The *`proc_macro_derive` [attribute][attributes]* defines a *derive macro* which > ``` r[macro.proc.derive.syntax] -The `proc_macro_derive` attribute uses the following syntax: +The syntax for the `proc_macro_derive` attribute is: ```grammar,attributes @root ProcMacroDeriveAttribute -> `proc_macro_derive` `(` DeriveMacroName ( `,` DeriveMacroAttributes )? `,`? `)` -DeriveMacroName -> SimplePathSegment +DeriveMacroName -> IDENTIFIER DeriveMacroAttributes -> - `attributes` `(` ( SimplePathSegment (`,` SimplePathSegment)* `,`?)? `)` + `attributes` `(` ( IDENTIFIER (`,` IDENTIFIER)* `,`?)? `)` ``` -The [DeriveMacroName] is the name of the derive macro. The optional `attributes` are described in [macro.proc.derive.attributes]. +The name of the derive macro is given by [DeriveMacroName]. The optional `attributes` argument is described in [macro.proc.derive.attributes]. 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. +The `proc_macro_derive` attribute may only be applied to a `pub` function with the [Rust ABI][items.fn.extern] defined in the root of the crate with a type of `fn(TokenStream) -> TokenStream` where [`TokenStream`] comes from the [`proc_macro` crate]. The function may be `const` and may use `extern` to explicitly specify the Rust ABI, but it may not use any other [qualifiers][FunctionQualifiers] (e.g. it may not be `async` or `unsafe`). r[macro.proc.derive.duplicates] -The `proc_macro_derive` attribute may only be specified once on a function. +The `proc_macro_derive` attribute may be specified only once on a function. 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. +The `proc_macro_derive` attribute publicly defines the derive macro in the [macro namespace] in the root of the crate. 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. +The input [`TokenStream`] is the token stream of the item to which the `derive` attribute is applied. The output [`TokenStream`] must be a (possibly empty) set of items. These items are appended following the input item within the same [module] or [block]. 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 declare *derive macro helper attributes* to be used within the scope of the [item] to which the derive macro is applied. These [attributes] are [inert]. While their purpose is to be used by the macro that declared them, they can be seen by any macro. -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. +r[macro.proc.derive.attributes.decl] +A helper attribute for a derive macro is declared by adding its identifier to the `attributes` list in the `proc_macro_derive` attribute. > [!EXAMPLE] -> The following derive macro defines a helper attribute `helper`, but ultimately doesn't do anything with it. +> This declares a helper attribute and then ignores it. > > > ```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 { +> # +> #[proc_macro_derive(WithHelperAttr, attributes(helper))] +> pub fn derive_with_helper_attr(_item: TokenStream) -> TokenStream { > TokenStream::new() > } > ``` > -> And then usage on the derive macro on a struct: +> To use it, we might write: > > > ```rust,ignore -> #[derive(HelperAttr)] +> #[derive(WithHelperAttr)] > struct Struct { -> #[helper] field: () +> #[helper] field: (), > } > ```