]> git.proxmox.com Git - rustc.git/blob - src/doc/unstable-book/src/language-features/proc-macro.md
New upstream version 1.19.0+dfsg1
[rustc.git] / src / doc / unstable-book / src / language-features / proc-macro.md
1 # `proc_macro`
2
3 The tracking issue for this feature is: [#38356]
4
5 [#38356]: https://github.com/rust-lang/rust/issues/38356
6
7 ------------------------
8
9 This feature flag guards the new procedural macro features as laid out by [RFC 1566], which alongside the now-stable
10 [custom derives], provide stabilizable alternatives to the compiler plugin API (which requires the use of
11 perma-unstable internal APIs) for programmatically modifying Rust code at compile-time.
12
13 The two new procedural macro kinds are:
14
15 * Function-like procedural macros which are invoked like regular declarative macros, and:
16
17 * Attribute-like procedural macros which can be applied to any item which built-in attributes can
18 be applied to, and which can take arguments in their invocation as well.
19
20 Additionally, this feature flag implicitly enables the [`use_extern_macros`](language-features/use-extern-macros.html) feature,
21 which allows macros to be imported like any other item with `use` statements, as compared to
22 applying `#[macro_use]` to an `extern crate` declaration. It is important to note that procedural macros may
23 **only** be imported in this manner, and will throw an error otherwise.
24
25 You **must** declare the `proc_macro` feature in both the crate declaring these new procedural macro kinds as well as
26 in any crates that use them.
27
28 ### Common Concepts
29
30 As with custom derives, procedural macros may only be declared in crates of the `proc-macro` type, and must be public
31 functions. No other public items may be declared in `proc-macro` crates, but private items are fine.
32
33 To declare your crate as a `proc-macro` crate, simply add:
34
35 ```toml
36 [lib]
37 proc-macro = true
38 ```
39
40 to your `Cargo.toml`.
41
42 Unlike custom derives, however, the name of the function implementing the procedural macro is used directly as the
43 procedural macro's name, so choose carefully.
44
45 Additionally, both new kinds of procedural macros return a `TokenStream` which *wholly* replaces the original
46 invocation and its input.
47
48 #### Importing
49
50 As referenced above, the new procedural macros are not meant to be imported via `#[macro_use]` and will throw an
51 error if they are. Instead, they are meant to be imported like any other item in Rust, with `use` statements:
52
53 ```rust,ignore
54 #![feature(proc_macro)]
55
56 // Where `my_proc_macros` is some crate of type `proc_macro`
57 extern crate my_proc_macros;
58
59 // And declares a `#[proc_macro] pub fn my_bang_macro()` at its root.
60 use my_proc_macros::my_bang_macro;
61
62 fn main() {
63 println!("{}", my_bang_macro!());
64 }
65 ```
66
67 #### Error Reporting
68
69 Any panics in a procedural macro implementation will be caught by the compiler and turned into an error message pointing
70 to the problematic invocation. Thus, it is important to make your panic messages as informative as possible: use
71 `Option::expect` instead of `Option::unwrap` and `Result::expect` instead of `Result::unwrap`, and inform the user of
72 the error condition as unambiguously as you can.
73
74 #### `TokenStream`
75
76 The `proc_macro::TokenStream` type is hardcoded into the signatures of procedural macro functions for both input and
77 output. It is a wrapper around the compiler's internal representation for a given chunk of Rust code.
78
79 ### Function-like Procedural Macros
80
81 These are procedural macros that are invoked like regular declarative macros. They are declared as public functions in
82 crates of the `proc_macro` type and using the `#[proc_macro]` attribute. The name of the declared function becomes the
83 name of the macro as it is to be imported and used. The function must be of the kind `fn(TokenStream) -> TokenStream`
84 where the sole argument is the input to the macro and the return type is the macro's output.
85
86 This kind of macro can expand to anything that is valid for the context it is invoked in, including expressions and
87 statements, as well as items.
88
89 **Note**: invocations of this kind of macro require a wrapping `[]`, `{}` or `()` like regular macros, but these do not
90 appear in the input, only the tokens between them. The tokens between the braces do not need to be valid Rust syntax.
91
92 <span class="filename">my_macro_crate/src/lib.rs</span>
93
94 ```rust,ignore
95 #![feature(proc_macro)]
96
97 // This is always necessary to get the `TokenStream` typedef.
98 extern crate proc_macro;
99
100 use proc_macro::TokenStream;
101
102 #[proc_macro]
103 pub fn say_hello(_input: TokenStream) -> TokenStream {
104 // This macro will accept any input because it ignores it.
105 // To enforce correctness in macros which don't take input,
106 // you may want to add `assert!(_input.to_string().is_empty());`.
107 "println!(\"Hello, world!\")".parse().unwrap()
108 }
109 ```
110
111 <span class="filename">my_macro_user/Cargo.toml</span>
112
113 ```toml
114 [dependencies]
115 my_macro_crate = { path = "<relative path to my_macro_crate>" }
116 ```
117
118 <span class="filename">my_macro_user/src/lib.rs</span>
119
120 ```rust,ignore
121 #![feature(proc_macro)]
122
123 extern crate my_macro_crate;
124
125 use my_macro_crate::say_hello;
126
127 fn main() {
128 say_hello!();
129 }
130 ```
131
132 As expected, this prints `Hello, world!`.
133
134 ### Attribute-like Procedural Macros
135
136 These are arguably the most powerful flavor of procedural macro as they can be applied anywhere attributes are allowed.
137
138 They are declared as public functions in crates of the `proc-macro` type, using the `#[proc_macro_attribute]` attribute.
139 The name of the function becomes the name of the attribute as it is to be imported and used. The function must be of the
140 kind `fn(TokenStream, TokenStream) -> TokenStream` where:
141
142 The first argument represents any metadata for the attribute (see [the reference chapter on attributes][refr-attr]).
143 Only the metadata itself will appear in this argument, for example:
144
145 * `#[my_macro]` will get an empty string.
146 * `#[my_macro = "string"]` will get `= "string"`.
147 * `#[my_macro(ident)]` will get `(ident)`.
148 * etc.
149
150 The second argument is the item that the attribute is applied to. It can be a function, a type definition,
151 an impl block, an `extern` block, or a module—attribute invocations can take the inner form (`#![my_attr]`)
152 or outer form (`#[my_attr]`).
153
154 The return type is the output of the macro which *wholly* replaces the item it was applied to. Thus, if your intention
155 is to merely modify an item, it *must* be copied to the output. The output must be an item; expressions, statements
156 and bare blocks are not allowed.
157
158 There is no restriction on how many items an attribute-like procedural macro can emit as long as they are valid in
159 the given context.
160
161 <span class="filename">my_macro_crate/src/lib.rs</span>
162
163 ```rust,ignore
164 #![feature(proc_macro)]
165
166 extern crate proc_macro;
167
168 use proc_macro::TokenStream;
169
170 /// Adds a `/// ### Panics` docstring to the end of the input's documentation
171 ///
172 /// Does not assert that its receiver is a function or method.
173 #[proc_macro_attribute]
174 pub fn panics_note(args: TokenStream, input: TokenStream) -> TokenStream {
175 let args = args.to_string();
176 let mut input = input.to_string();
177
178 assert!(args.starts_with("= \""), "`#[panics_note]` requires an argument of the form \
179 `#[panics_note = \"panic note here\"]`");
180
181 // Get just the bare note string
182 let panics_note = args.trim_matches(&['=', ' ', '"'][..]);
183
184 // The input will include all docstrings regardless of where the attribute is placed,
185 // so we need to find the last index before the start of the item
186 let insert_idx = idx_after_last_docstring(&input);
187
188 // And insert our `### Panics` note there so it always appears at the end of an item's docs
189 input.insert_str(insert_idx, &format!("/// # Panics \n/// {}\n", panics_note));
190
191 input.parse().unwrap()
192 }
193
194 // `proc-macro` crates can contain any kind of private item still
195 fn idx_after_last_docstring(input: &str) -> usize {
196 // Skip docstring lines to find the start of the item proper
197 input.lines().skip_while(|line| line.trim_left().starts_with("///")).next()
198 // Find the index of the first non-docstring line in the input
199 // Note: assumes this exact line is unique in the input
200 .and_then(|line_after| input.find(line_after))
201 // No docstrings in the input
202 .unwrap_or(0)
203 }
204 ```
205
206 <span class="filename">my_macro_user/Cargo.toml</span>
207
208 ```toml
209 [dependencies]
210 my_macro_crate = { path = "<relative path to my_macro_crate>" }
211 ```
212
213 <span class="filename">my_macro_user/src/lib.rs</span>
214
215 ```rust,ignore
216 #![feature(proc_macro)]
217
218 extern crate my_macro_crate;
219
220 use my_macro_crate::panics_note;
221
222 /// Do the `foo` thing.
223 #[panics_note = "Always."]
224 pub fn foo() {
225 panic!()
226 }
227 ```
228
229 Then the rendered documentation for `pub fn foo` will look like this:
230
231 > `pub fn foo()`
232 >
233 > ----
234 > Do the `foo` thing.
235 > # Panics
236 > Always.
237
238 [RFC 1566]: https://github.com/rust-lang/rfcs/blob/master/text/1566-proc-macros.md
239 [custom derives]: https://doc.rust-lang.org/book/procedural-macros.html
240 [rust-lang/rust#41430]: https://github.com/rust-lang/rust/issues/41430
241 [refr-attr]: https://doc.rust-lang.org/reference/attributes.html