From e22e1c8d2be4eb3ba27592b4ce75ea34961bc619 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 11 Jun 2025 17:25:28 -0700 Subject: [PATCH 01/11] Unwrap proc_macro --- src/procedural-macros.md | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/procedural-macros.md b/src/procedural-macros.md index 28c93080ea..05f6def8ec 100644 --- a/src/procedural-macros.md +++ b/src/procedural-macros.md @@ -83,20 +83,15 @@ r[macro.proc.function] ## Function-like procedural macros r[macro.proc.function.intro] -*Function-like procedural macros* are procedural macros that are invoked using -the macro invocation operator (`!`). +*Function-like procedural macros* are procedural macros that are invoked using the macro invocation operator (`!`). r[macro.proc.function.def] -These macros are defined by a [public] [function] with the `proc_macro` -[attribute] and a signature of `(TokenStream) -> TokenStream`. The input -[`TokenStream`] is what is inside the delimiters of the macro invocation and the -output [`TokenStream`] replaces the entire macro invocation. +These macros are defined by a [public] [function] with the `proc_macro` [attribute] and a signature of `(TokenStream) -> TokenStream`. The input [`TokenStream`] is what is inside the delimiters of the macro invocation and the output [`TokenStream`] replaces the entire macro invocation. r[macro.proc.function.namespace] The `proc_macro` attribute defines the macro in the [macro namespace] in the root of the crate. -For example, the following macro definition ignores its input and outputs a -function `answer` into its scope. +For example, the following macro definition ignores its input and outputs a function `answer` into its scope. ```rust,ignore @@ -125,10 +120,7 @@ fn main() { ``` r[macro.proc.function.invocation] -Function-like procedural macros may be invoked in any macro invocation -position, which includes [statements], [expressions], [patterns], [type -expressions], [item] positions, including items in [`extern` blocks], inherent -and trait [implementations], and [trait definitions]. +Function-like procedural macros may be invoked in any macro invocation position, which includes [statements], [expressions], [patterns], [type expressions], [item] positions, including items in [`extern` blocks], inherent and trait [implementations], and [trait definitions]. r[macro.proc.derive] From 541422c2d5bae7a096d0dc10a0f2582e4576c5bd Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 11 Jun 2025 18:08:51 -0700 Subject: [PATCH 02/11] Rename "Function-like procedural macros" section This renames this section 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. --- book.toml | 1 + src/attributes.md | 2 +- src/names/namespaces.md | 2 +- src/procedural-macros.md | 7 ++++--- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/book.toml b/book.toml index e4dced2e64..fe4b86f1f2 100644 --- a/book.toml +++ b/book.toml @@ -35,6 +35,7 @@ use-boolean-and = true "/lifetime-elision.html#static-lifetime-elision" = "lifetime-elision.html#const-and-static-elision" "/macros-by-example.html#path-based-scope" = "macros-by-example.html#the-macro_export-attribute" "/procedural-macros.html#derive-macros" = "procedural-macros.html#the-proc_macro_derive-attribute" +"/procedural-macros.html#function-like-procedural-macros" = "procedural-macros.html#the-proc_macro-attribute" "/runtime.html#the-panic_handler-attribute" = "panic.html#the-panic_handler-attribute" "/unsafe-blocks.html" = "unsafe-keyword.html" "/unsafe-functions.html" = "unsafe-keyword.html" diff --git a/src/attributes.md b/src/attributes.md index a2a927bef0..6d9115b43b 100644 --- a/src/attributes.md +++ b/src/attributes.md @@ -374,7 +374,7 @@ The following is an index of all built-in attributes. [`path`]: items/modules.md#the-path-attribute [`proc_macro_attribute`]: procedural-macros.md#attribute-macros [`proc_macro_derive`]: macro.proc.derive -[`proc_macro`]: procedural-macros.md#function-like-procedural-macros +[`proc_macro`]: procedural-macros.md#the-proc_macro-attribute [`recursion_limit`]: attributes/limits.md#the-recursion_limit-attribute [`repr`]: type-layout.md#representations [`should_panic`]: attributes/testing.md#the-should_panic-attribute diff --git a/src/names/namespaces.md b/src/names/namespaces.md index 1794b0fd82..116c7a1fe6 100644 --- a/src/names/namespaces.md +++ b/src/names/namespaces.md @@ -153,7 +153,7 @@ It is still an error for a [`use` import] to shadow another macro, regardless of [field expression]: ../expressions/field-expr.md [Function declarations]: ../items/functions.md [function parameters]: ../items/functions.md#function-parameters -[Function-like procedural macros]: ../procedural-macros.md#function-like-procedural-macros +[Function-like procedural macros]: ../procedural-macros.md#the-proc_macro-attribute [Generic const parameters]: ../items/generics.md#const-generics [Generic lifetime parameters]: ../items/generics.md [Generic type parameters]: ../items/generics.md diff --git a/src/procedural-macros.md b/src/procedural-macros.md index 05f6def8ec..a81c8a53a9 100644 --- a/src/procedural-macros.md +++ b/src/procedural-macros.md @@ -79,8 +79,9 @@ items in libraries (for example, `::std::option::Option` instead of `Option`) or by ensuring that generated functions have names that are unlikely to clash with other functions (like `__internal_foo` instead of `foo`). -r[macro.proc.function] -## Function-like procedural macros + +r[macro.proc.proc_macro] +## The `proc_macro` attribute r[macro.proc.function.intro] *Function-like procedural macros* are procedural macros that are invoked using the macro invocation operator (`!`). @@ -376,7 +377,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]: macro.proc.derive -[Function-like macros]: #function-like-procedural-macros +[Function-like macros]: #the-proc_macro-attribute [`$crate`]: macro.decl.hygiene.crate [`Delimiter::None`]: proc_macro::Delimiter::None [`Group`]: proc_macro::Group From 1858756352230a6492e58918f8ecce70e47dfa88 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 11 Jun 2025 18:09:51 -0700 Subject: [PATCH 03/11] Rename proc_macro crate rules to avoid rule name conflict Trying to avoid conflict with the `proc_macro` attribute rule. (Though that rule name may also change later.) --- src/procedural-macros.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/procedural-macros.md b/src/procedural-macros.md index a81c8a53a9..21c1e6c8e1 100644 --- a/src/procedural-macros.md +++ b/src/procedural-macros.md @@ -42,15 +42,15 @@ r[macro.proc.error] Procedural macros have two ways of reporting errors. The first is to panic. The second is to emit a [`compile_error`] macro invocation. -r[macro.proc.proc_macro] +r[macro.proc.proc_macro-crate] ## The `proc_macro` crate -r[macro.proc.proc_macro.intro] +r[macro.proc.proc_macro-crate.intro] Procedural macro crates almost always will link to the compiler-provided [`proc_macro` crate]. The `proc_macro` crate provides types required for writing procedural macros and facilities to make it easier. -r[macro.proc.proc_macro.token-stream] +r[macro.proc.proc_macro-crate.token-stream] This crate primarily contains a [`TokenStream`] type. Procedural macros operate over *token streams* instead of AST nodes, which is a far more stable interface over time for both the compiler and for procedural macros to target. A @@ -59,7 +59,7 @@ can roughly be thought of as lexical token. For example `foo` is an `Ident` token, `.` is a `Punct` token, and `1.2` is a `Literal` token. The `TokenStream` type, unlike `Vec`, is cheap to clone. -r[macro.proc.proc_macro.span] +r[macro.proc.proc_macro-crate.span] All tokens have an associated `Span`. A `Span` is an opaque value that cannot be modified but can be manufactured. `Span`s represent an extent of source code within a program and are primarily used for error reporting. While you From 26054e2156b863ae4817a7d20a3fa45819089f92 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 11 Jun 2025 18:10:30 -0700 Subject: [PATCH 04/11] Reword proc_macro intro rule Reworded to follow the attribute template. --- src/procedural-macros.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/procedural-macros.md b/src/procedural-macros.md index 21c1e6c8e1..68f9635661 100644 --- a/src/procedural-macros.md +++ b/src/procedural-macros.md @@ -83,8 +83,8 @@ other functions (like `__internal_foo` instead of `foo`). r[macro.proc.proc_macro] ## The `proc_macro` attribute -r[macro.proc.function.intro] -*Function-like procedural macros* are procedural macros that are invoked using the macro invocation operator (`!`). +r[macro.proc.proc_macro.intro] +The *`proc_macro` [attribute][attributes]* defines a procedural macro for [function-like macros][macro.invocation]. r[macro.proc.function.def] These macros are defined by a [public] [function] with the `proc_macro` [attribute] and a signature of `(TokenStream) -> TokenStream`. The input [`TokenStream`] is what is inside the delimiters of the macro invocation and the output [`TokenStream`] replaces the entire macro invocation. From f8ca506a953555e2df4f5923f6ca77582c8492b5 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 11 Jun 2025 18:11:37 -0700 Subject: [PATCH 05/11] Move proc_macro example to the intro and into an example block --- src/procedural-macros.md | 50 ++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/src/procedural-macros.md b/src/procedural-macros.md index 68f9635661..c28dae776d 100644 --- a/src/procedural-macros.md +++ b/src/procedural-macros.md @@ -92,33 +92,39 @@ These macros are defined by a [public] [function] with the `proc_macro` [att r[macro.proc.function.namespace] The `proc_macro` attribute defines the macro in the [macro namespace] in the root of the crate. -For example, the following macro definition ignores its input and outputs a function `answer` into its scope. - - -```rust,ignore -# #![crate_type = "proc-macro"] -extern crate proc_macro; -use proc_macro::TokenStream; +> [!EXAMPLE] +> The following macro definition ignores its input and outputs a function `answer` into its scope. +> +> +> ```rust,ignore +> # #![crate_type = "proc-macro"] +> extern crate proc_macro; +> use proc_macro::TokenStream; +> +> #[proc_macro] +> pub fn make_answer(_item: TokenStream) -> TokenStream { +> "fn answer() -> u32 { 42 }".parse().unwrap() +> } +> ``` +> +> And then we use it in a binary crate to print "42" to standard output. +> +> +> ```rust,ignore +> extern crate proc_macro_examples; +> use proc_macro_examples::make_answer; +> +> make_answer!(); +> +> fn main() { +> println!("{}", answer()); +> } +> ``` -#[proc_macro] -pub fn make_answer(_item: TokenStream) -> TokenStream { - "fn answer() -> u32 { 42 }".parse().unwrap() -} -``` -And then we use it in a binary crate to print "42" to standard output. - -```rust,ignore -extern crate proc_macro_examples; -use proc_macro_examples::make_answer; -make_answer!(); -fn main() { - println!("{}", answer()); -} -``` r[macro.proc.function.invocation] Function-like procedural macros may be invoked in any macro invocation position, which includes [statements], [expressions], [patterns], [type expressions], [item] positions, including items in [`extern` blocks], inherent and trait [implementations], and [trait definitions]. From 08d9205ab803eba2a04db275b227e689fe7a07bc Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 11 Jun 2025 18:12:51 -0700 Subject: [PATCH 06/11] Rename and reword proc_macro namespace rule This is a slight rewording to clarify that the name of the function is what is inserted in the root. --- src/procedural-macros.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/procedural-macros.md b/src/procedural-macros.md index c28dae776d..8d8704d7a1 100644 --- a/src/procedural-macros.md +++ b/src/procedural-macros.md @@ -89,8 +89,6 @@ The *`proc_macro` [attribute][attributes]* defines a procedural macro for [funct r[macro.proc.function.def] These macros are defined by a [public] [function] with the `proc_macro` [attribute] and a signature of `(TokenStream) -> TokenStream`. The input [`TokenStream`] is what is inside the delimiters of the macro invocation and the output [`TokenStream`] replaces the entire macro invocation. -r[macro.proc.function.namespace] -The `proc_macro` attribute defines the macro in the [macro namespace] in the root of the crate. > [!EXAMPLE] > The following macro definition ignores its input and outputs a function `answer` into its scope. @@ -124,6 +122,8 @@ The `proc_macro` attribute defines the macro in the [macro namespace] in the roo +r[macro.proc.function.namespace] +The `proc_macro` attribute publicly defines the macro in the [macro namespace] in the root of the crate with the same name as the function. r[macro.proc.function.invocation] From 52a4e5c3ed91904ef81b88bf46a05552fd357dc3 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 11 Jun 2025 18:13:43 -0700 Subject: [PATCH 07/11] Rework proc_macro to use attribute template rules --- src/procedural-macros.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/procedural-macros.md b/src/procedural-macros.md index 8d8704d7a1..f6f5ff5295 100644 --- a/src/procedural-macros.md +++ b/src/procedural-macros.md @@ -86,10 +86,6 @@ r[macro.proc.proc_macro] r[macro.proc.proc_macro.intro] The *`proc_macro` [attribute][attributes]* defines a procedural macro for [function-like macros][macro.invocation]. -r[macro.proc.function.def] -These macros are defined by a [public] [function] with the `proc_macro` [attribute] and a signature of `(TokenStream) -> TokenStream`. The input [`TokenStream`] is what is inside the delimiters of the macro invocation and the output [`TokenStream`] replaces the entire macro invocation. - - > [!EXAMPLE] > The following macro definition ignores its input and outputs a function `answer` into its scope. > @@ -119,12 +115,20 @@ These macros are defined by a [public] [function] with the `proc_macro` [att > } > ``` +r[macro.proc.proc_macro.syntax] +The `proc_macro` attribute uses the [MetaWord] syntax and thus does not take any inputs. +r[macro.proc.proc_macro.allowed-positions] +The `proc_macro` 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.proc_macro.duplicates] +The `proc_macro` attribute may only be specified once on a function. -r[macro.proc.function.namespace] +r[macro.proc.proc_macro.namespace] The `proc_macro` attribute publicly defines the macro in the [macro namespace] in the root of the crate with the same name as the function. +r[macro.proc.proc_macro.behavior] +A function-like macro invocation of a function-like procedural macro will pass what is inside the delimiters of the macro invocation as the input [`TokenStream`] argument, and replace the entire macro invocation with the output [`TokenStream`] of the function. r[macro.proc.function.invocation] Function-like procedural macros may be invoked in any macro invocation position, which includes [statements], [expressions], [patterns], [type expressions], [item] positions, including items in [`extern` blocks], inherent and trait [implementations], and [trait definitions]. From bad56ccad52977e53642b5dee0f8ae0190f9aa80 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 11 Jun 2025 18:14:04 -0700 Subject: [PATCH 08/11] Rename macro.proc.function.invocation To follow the attribute template rename. --- 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 f6f5ff5295..9aec1165fb 100644 --- a/src/procedural-macros.md +++ b/src/procedural-macros.md @@ -130,7 +130,7 @@ The `proc_macro` attribute publicly defines the macro in the [macro namespace] i r[macro.proc.proc_macro.behavior] A function-like macro invocation of a function-like procedural macro will pass what is inside the delimiters of the macro invocation as the input [`TokenStream`] argument, and replace the entire macro invocation with the output [`TokenStream`] of the function. -r[macro.proc.function.invocation] +r[macro.proc.proc_macro.invocation] Function-like procedural macros may be invoked in any macro invocation position, which includes [statements], [expressions], [patterns], [type expressions], [item] positions, including items in [`extern` blocks], inherent and trait [implementations], and [trait definitions]. From e79f0bc905e0e7832bc1b90da389d9a690d5d31b Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 29 Jun 2025 18:04:09 -0700 Subject: [PATCH 09/11] Convert long embedded list to a normal list --- src/procedural-macros.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/procedural-macros.md b/src/procedural-macros.md index 9aec1165fb..e91ac9ce59 100644 --- a/src/procedural-macros.md +++ b/src/procedural-macros.md @@ -131,7 +131,15 @@ r[macro.proc.proc_macro.behavior] A function-like macro invocation of a function-like procedural macro will pass what is inside the delimiters of the macro invocation as the input [`TokenStream`] argument, and replace the entire macro invocation with the output [`TokenStream`] of the function. r[macro.proc.proc_macro.invocation] -Function-like procedural macros may be invoked in any macro invocation position, which includes [statements], [expressions], [patterns], [type expressions], [item] positions, including items in [`extern` blocks], inherent and trait [implementations], and [trait definitions]. +Function-like procedural macros may be invoked in any macro invocation position, which includes: + +- [statements] +- [expressions] +- [patterns] +- [type expressions] +- [item] positions, including items in [`extern` blocks] +- inherent and trait [implementations] +- [trait definitions] r[macro.proc.derive] From 5d2e25ed65bb61bcff0dfbf0340f61b014948e67 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 7 Oct 2025 13:44:53 -0700 Subject: [PATCH 10/11] Update proc_macro for updated attribute template --- src/procedural-macros.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/procedural-macros.md b/src/procedural-macros.md index e91ac9ce59..e2a32f4177 100644 --- a/src/procedural-macros.md +++ b/src/procedural-macros.md @@ -80,6 +80,7 @@ by ensuring that generated functions have names that are unlikely to clash with other functions (like `__internal_foo` instead of `foo`). + r[macro.proc.proc_macro] ## The `proc_macro` attribute @@ -116,7 +117,7 @@ The *`proc_macro` [attribute][attributes]* defines a procedural macro for [funct > ``` r[macro.proc.proc_macro.syntax] -The `proc_macro` attribute uses the [MetaWord] syntax and thus does not take any inputs. +The `proc_macro` attribute uses the [MetaWord] syntax. r[macro.proc.proc_macro.allowed-positions] The `proc_macro` 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. From b4fbe46d445eab36119ad6822127dbdcd227aae8 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Tue, 21 Oct 2025 19:40:03 +0000 Subject: [PATCH 11/11] Revise `proc_macro` text --- src/procedural-macros.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/procedural-macros.md b/src/procedural-macros.md index e2a32f4177..be6ff36111 100644 --- a/src/procedural-macros.md +++ b/src/procedural-macros.md @@ -85,10 +85,10 @@ r[macro.proc.proc_macro] ## The `proc_macro` attribute r[macro.proc.proc_macro.intro] -The *`proc_macro` [attribute][attributes]* defines a procedural macro for [function-like macros][macro.invocation]. +The *`proc_macro` [attribute][attributes]* defines a [function-like][macro.invocation] procedural macro. > [!EXAMPLE] -> The following macro definition ignores its input and outputs a function `answer` into its scope. +> This macro definition ignores its input and emits a function `answer` into its scope. > > > ```rust,ignore @@ -102,7 +102,7 @@ The *`proc_macro` [attribute][attributes]* defines a procedural macro for [funct > } > ``` > -> And then we use it in a binary crate to print "42" to standard output. +> We can use it in a binary crate to print "42" to standard output. > > > ```rust,ignore @@ -120,7 +120,7 @@ r[macro.proc.proc_macro.syntax] The `proc_macro` attribute uses the [MetaWord] syntax. r[macro.proc.proc_macro.allowed-positions] -The `proc_macro` 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` attribute may only be applied to a `pub` function of type `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. It must be located in the root of the crate. r[macro.proc.proc_macro.duplicates] The `proc_macro` attribute may only be specified once on a function. @@ -129,18 +129,18 @@ r[macro.proc.proc_macro.namespace] The `proc_macro` attribute publicly defines the macro in the [macro namespace] in the root of the crate with the same name as the function. r[macro.proc.proc_macro.behavior] -A function-like macro invocation of a function-like procedural macro will pass what is inside the delimiters of the macro invocation as the input [`TokenStream`] argument, and replace the entire macro invocation with the output [`TokenStream`] of the function. +A function-like macro invocation of a function-like procedural macro will pass what is inside the delimiters of the macro invocation as the input [`TokenStream`] argument and replace the entire macro invocation with the output [`TokenStream`] of the function. r[macro.proc.proc_macro.invocation] Function-like procedural macros may be invoked in any macro invocation position, which includes: -- [statements] -- [expressions] -- [patterns] -- [type expressions] -- [item] positions, including items in [`extern` blocks] -- inherent and trait [implementations] -- [trait definitions] +- [Statements] +- [Expressions] +- [Patterns] +- [Type expressions] +- [Item] positions, including items in [`extern` blocks] +- Inherent and trait [implementations] +- [Trait definitions] r[macro.proc.derive]