@@ -6,5 +6,236 @@ The tracking issue for this feature is: [#38356]
66
77------------------------
88
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.
912
13+ The two new procedural macro kinds are:
14+
15+ * Function-like procedural macros which are invoked like regular declarative macros, and:
1016
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
0 commit comments