Skip to content

Commit a6d3c39

Browse files
authored
Merge pull request #1889 from ehuss/proc_macro_attribute
Update `proc_macro_attribute` to use the attribute template
2 parents 80bd085 + dd41f1f commit a6d3c39

File tree

5 files changed

+92
-80
lines changed

5 files changed

+92
-80
lines changed

book.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use-boolean-and = true
3434
"/items/traits.html#object-safety" = "traits.html#dyn-compatibility"
3535
"/lifetime-elision.html#static-lifetime-elision" = "lifetime-elision.html#const-and-static-elision"
3636
"/macros-by-example.html#path-based-scope" = "macros-by-example.html#the-macro_export-attribute"
37+
"/procedural-macros.html#attribute-macros" = "procedural-macros.html#the-proc_macro_attribute-attribute"
3738
"/procedural-macros.html#derive-macros" = "procedural-macros.html#the-proc_macro_derive-attribute"
3839
"/procedural-macros.html#function-like-procedural-macros" = "procedural-macros.html#the-proc_macro-attribute"
3940
"/runtime.html#the-panic_handler-attribute" = "panic.html#the-panic_handler-attribute"

src/attributes.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ The following is an index of all built-in attributes.
372372
[`non_exhaustive`]: attributes/type_system.md#the-non_exhaustive-attribute
373373
[`panic_handler`]: panic.md#the-panic_handler-attribute
374374
[`path`]: items/modules.md#the-path-attribute
375-
[`proc_macro_attribute`]: procedural-macros.md#attribute-macros
375+
[`proc_macro_attribute`]: procedural-macros.md#the-proc_macro_attribute-attribute
376376
[`proc_macro_derive`]: macro.proc.derive
377377
[`proc_macro`]: procedural-macros.md#the-proc_macro-attribute
378378
[`recursion_limit`]: attributes/limits.md#the-recursion_limit-attribute
@@ -385,7 +385,7 @@ The following is an index of all built-in attributes.
385385
[`used`]: abi.md#the-used-attribute
386386
[`warn`]: attributes/diagnostics.md#lint-check-attributes
387387
[`windows_subsystem`]: runtime.md#the-windows_subsystem-attribute
388-
[attribute macros]: procedural-macros.md#attribute-macros
388+
[attribute macros]: procedural-macros.md#the-proc_macro_attribute-attribute
389389
[block expressions]: expressions/block-expr.md
390390
[built-in attributes]: #built-in-attributes-index
391391
[derive macro helper attributes]: procedural-macros.md#derive-macro-helper-attributes

src/items/functions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,7 @@ fn foo_oof(#[some_inert_attribute] arg: u8) {
472472
[`cfg`]: ../conditional-compilation.md#the-cfg-attribute
473473
[`cfg_attr`]: ../conditional-compilation.md#the-cfg_attr-attribute
474474
[lint check attributes]: ../attributes/diagnostics.md#lint-check-attributes
475-
[procedural macro attributes]: ../procedural-macros.md#attribute-macros
475+
[procedural macro attributes]: macro.proc.attribute
476476
[testing attributes]: ../attributes/testing.md
477477
[`cold`]: ../attributes/codegen.md#the-cold-attribute
478478
[`inline`]: ../attributes/codegen.md#the-inline-attribute

src/names/namespaces.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ It is still an error for a [`use` import] to shadow another macro, regardless of
134134
[Associated const declarations]: ../items/associated-items.md#associated-constants
135135
[Associated function declarations]: ../items/associated-items.md#associated-functions-and-methods
136136
[Associated type declarations]: ../items/associated-items.md#associated-types
137-
[Attribute macros]: ../procedural-macros.md#attribute-macros
137+
[Attribute macros]: ../procedural-macros.md#the-proc_macro_attribute-attribute
138138
[attributes]: ../attributes.md
139139
[bang-style macros]: ../macros.md
140140
[Block labels]: ../expressions/loop-expr.md#labelled-block-expressions

src/procedural-macros.md

Lines changed: 87 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -240,91 +240,102 @@ A helper attribute for a derive macro is declared by adding its identifier to th
240240
> }
241241
> ```
242242
243+
<!-- template:attributes -->
243244
r[macro.proc.attribute]
244-
## Attribute macros
245+
## The `proc_macro_attribute` attribute
245246
246247
r[macro.proc.attribute.intro]
247-
*Attribute macros* define new [outer attributes][attributes] which can be
248-
attached to [items], including items in [`extern` blocks], inherent and trait
249-
[implementations], and [trait definitions].
250-
251-
r[macro.proc.attribute.def]
252-
Attribute macros are defined by a [public]&#32;[function] with the
253-
`proc_macro_attribute` [attribute] that has a signature of `(TokenStream,
254-
TokenStream) -> TokenStream`. The first [`TokenStream`] is the delimited token
255-
tree following the attribute's name, not including the outer delimiters. If
256-
the attribute is written as a bare attribute name, the attribute
257-
[`TokenStream`] is empty. The second [`TokenStream`] is the rest of the [item]
258-
including other [attributes] on the [item]. The returned [`TokenStream`]
259-
replaces the [item] with an arbitrary number of [items].
248+
The *`proc_macro_attribute` [attribute][attributes]* defines an *attribute macro* which can be used as an [outer attribute][attributes].
249+
250+
> [!EXAMPLE]
251+
> This attribute macro takes the input stream and emits it as-is, effectively being a no-op attribute.
252+
>
253+
> <!-- ignore: test doesn't support proc-macro -->
254+
> ```rust,ignore
255+
> # #![crate_type = "proc-macro"]
256+
> # extern crate proc_macro;
257+
> # use proc_macro::TokenStream;
258+
>
259+
> #[proc_macro_attribute]
260+
> pub fn return_as_is(_attr: TokenStream, item: TokenStream) -> TokenStream {
261+
> item
262+
> }
263+
> ```
264+
265+
> [!EXAMPLE]
266+
> This shows, in the output of the compiler, the stringified [`TokenStream`s] that attribute macros see.
267+
>
268+
> <!-- ignore: test doesn't support proc-macro -->
269+
> ```rust,ignore
270+
> // my-macro/src/lib.rs
271+
> # extern crate proc_macro;
272+
> # use proc_macro::TokenStream;
273+
> #[proc_macro_attribute]
274+
> pub fn show_streams(attr: TokenStream, item: TokenStream) -> TokenStream {
275+
> println!("attr: \"{attr}\"");
276+
> println!("item: \"{item}\"");
277+
> item
278+
> }
279+
> ```
280+
>
281+
> <!-- ignore: requires external crates -->
282+
> ```rust,ignore
283+
> // src/lib.rs
284+
> extern crate my_macro;
285+
>
286+
> use my_macro::show_streams;
287+
>
288+
> // Example: Basic function.
289+
> #[show_streams]
290+
> fn invoke1() {}
291+
> // out: attr: ""
292+
> // out: item: "fn invoke1() {}"
293+
>
294+
> // Example: Attribute with input.
295+
> #[show_streams(bar)]
296+
> fn invoke2() {}
297+
> // out: attr: "bar"
298+
> // out: item: "fn invoke2() {}"
299+
>
300+
> // Example: Multiple tokens in the input.
301+
> #[show_streams(multiple => tokens)]
302+
> fn invoke3() {}
303+
> // out: attr: "multiple => tokens"
304+
> // out: item: "fn invoke3() {}"
305+
>
306+
> // Example: Delimiters in the input.
307+
> #[show_streams { delimiters }]
308+
> fn invoke4() {}
309+
> // out: attr: "delimiters"
310+
> // out: item: "fn invoke4() {}"
311+
> ```
312+
313+
r[macro.proc.attribute.syntax]
314+
The `proc_macro_attribute` attribute uses the [MetaWord] syntax.
315+
316+
r[macro.proc.attribute.allowed-positions]
317+
The `proc_macro_attribute` attribute may only be applied to a `pub` function of type `fn(TokenStream, 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.
318+
319+
r[macro.proc.attribute.duplicates]
320+
The `proc_macro_attribute` attribute may only be specified once on a function.
260321
261322
r[macro.proc.attribute.namespace]
262-
The `proc_macro_attribute` attribute defines the attribute in the [macro namespace] in the root of the crate.
323+
The `proc_macro_attribute` attribute defines the attribute in the [macro namespace] in the root of the crate with the same name as the function.
263324
264-
For example, this attribute macro takes the input stream and returns it as is,
265-
effectively being the no-op of attributes.
325+
r[macro.proc.attribute.use-positions]
326+
Attribute macros can only be used on:
266327
267-
<!-- ignore: test doesn't support proc-macro -->
268-
```rust,ignore
269-
# #![crate_type = "proc-macro"]
270-
# extern crate proc_macro;
271-
# use proc_macro::TokenStream;
328+
- [Items]
329+
- Items in [`extern` blocks]
330+
- Inherent and trait [implementations]
331+
- [Trait definitions]
272332
273-
#[proc_macro_attribute]
274-
pub fn return_as_is(_attr: TokenStream, item: TokenStream) -> TokenStream {
275-
item
276-
}
277-
```
333+
r[macro.proc.attribute.behavior]
334+
The first [`TokenStream`] parameter is the delimited token tree following the attribute's name but not including the outer delimiters. If the applied attribute contains only the attribute name or the attribute name followed by empty delimiters, the [`TokenStream`] is empty.
278335
279-
This following example shows the stringified [`TokenStream`s] that the attribute
280-
macros see. The output will show in the output of the compiler. The output is
281-
shown in the comments after the function prefixed with "out:".
282-
283-
<!-- ignore: test doesn't support proc-macro -->
284-
```rust,ignore
285-
// my-macro/src/lib.rs
286-
# extern crate proc_macro;
287-
# use proc_macro::TokenStream;
288-
289-
#[proc_macro_attribute]
290-
pub fn show_streams(attr: TokenStream, item: TokenStream) -> TokenStream {
291-
println!("attr: \"{attr}\"");
292-
println!("item: \"{item}\"");
293-
item
294-
}
295-
```
336+
The second [`TokenStream`] is the rest of the [item], including other [attributes] on the [item].
296337
297-
<!-- ignore: requires external crates -->
298-
```rust,ignore
299-
// src/lib.rs
300-
extern crate my_macro;
301-
302-
use my_macro::show_streams;
303-
304-
// Example: Basic function
305-
#[show_streams]
306-
fn invoke1() {}
307-
// out: attr: ""
308-
// out: item: "fn invoke1() {}"
309-
310-
// Example: Attribute with input
311-
#[show_streams(bar)]
312-
fn invoke2() {}
313-
// out: attr: "bar"
314-
// out: item: "fn invoke2() {}"
315-
316-
// Example: Multiple tokens in the input
317-
#[show_streams(multiple => tokens)]
318-
fn invoke3() {}
319-
// out: attr: "multiple => tokens"
320-
// out: item: "fn invoke3() {}"
321-
322-
// Example:
323-
#[show_streams { delimiters }]
324-
fn invoke4() {}
325-
// out: attr: "delimiters"
326-
// out: item: "fn invoke4() {}"
327-
```
338+
The item to which the attribute is applied is replaced by the zero or more items in the returned [`TokenStream`].
328339
329340
r[macro.proc.token]
330341
## Declarative macro tokens and procedural macro tokens
@@ -393,7 +404,7 @@ Note that neither declarative nor procedural macros support doc comment tokens
393404
(e.g. `/// Doc`), so they are always converted to token streams representing
394405
their equivalent `#[doc = r"str"]` attributes when passed to macros.
395406
396-
[Attribute macros]: #attribute-macros
407+
[Attribute macros]: #the-proc_macro_attribute-attribute
397408
[Cargo's build scripts]: ../cargo/reference/build-scripts.html
398409
[Derive macros]: macro.proc.derive
399410
[Function-like macros]: #the-proc_macro-attribute

0 commit comments

Comments
 (0)