Macros

Macros are a method of using code to write code. They can be used to extend Rust with extra syntactical parts (such as the variable number of arguments in ), make writing lots of duplicate code easier (e.g. macros are used to generate the identical methods of the primitive integer types in std), or to create entirely different sub-languages within Rust (e.g. ).

There are two types of macro in Rust: declarative macros and procedural macros, or proc-macros. Declarative macros are defined using, and provide a simple method of substituting a macro invocation for code. Procedural macros have to be defined in their own crate, and allow any arbitrary Rust code to run which will transform Rust code into different Rust code. Procedural macros are far more powerful, but are more difficult to write and slow down the compilation process (as they have to be both compiled and run during the compilation process).

Declarative macros
Declarative macros are defined with. They use a -like syntax to determine which "branch" to use. Here is a simple macro that takes no arguments and expands to the string literal "Hello World!":

This macro has one arm which takes no arguments. Attempting to call the macro with an argument will result in an error as no arms match. Its body is delimited with braces, which aren't included in the expansion. The trailing semicolon is optional for the last match arm, but is required for all other match arms.

It can be invoked in three ways:


 * Using parenthesis:
 * Using brackets:
 * Using braces:

All three are completely equivalent, and whichever one is used is up to the user. There are conventions, however; function-like macros such as  are written with parenthesis (like a function call), array-like macros such as   are written with brackets (like an array literal) and macros that take in larger blocks of code are written with braces (like code blocks).

Macro parameters
Any code written in the parameters of a macro will only be accepted if it matches exactly (excluding whitespace); for example  will match   and   but not   or. To accept variable parameters to the macro use a dollar sign, followed by the variable's name, followed by a colon, followed by the variable's type; for example,  will accept any expression and bind it to the variable. Then, in the body of the macro  will be expanded to the expression given to the macro. The following types are available:

Repeats
Declarative macros can specify parts to be repeated multiple times, by writing  where   is one of ,   or. specifies that the area should be repeated zero or one times,  specifies zero or more and   specifies one or more. Any token can be placed before the suffix to cause that token to have to appear in between each repeat. Using these features, a common pattern to allow trailing commas is.

In the body of the macro the same rules apply to expand the repeated variables. The source code of the macro can be approximated using this:

Visibility of declarative macros
Declarative macros, unlike all other items, cannot use things like  and   to control their visibility. Instead, macros must be either public or private. Macros can be made public by adding the  attribute to it:

It will then be visible at the crate root.

To make the macro behave (somewhat) like any other  item, you have to do this:

will now be visible at the crate root as well as inside the module it's defined in.

If you only need a visibility of  or less, then you can omit the. In this case,  will not be visible at the crate root.

Macros, unlike other items must be declared before they are used, i.e. this is invalid:

If a macro is defined in a child module, you must put the module declaration before the use of the macro, and if it is defined in a parent module the parent module must place the child's mod declaration after the declaration of the macro.

In order to use macros from other modules in your crate, you must annotate the module declaration with. In the 2015 edition, you must also annotate  declarations with   in order to use the macros inside it. will import all exported macros into the current scope - you can't specify only one or two.

Accessing items in the current crate
If you are exporting a macro, it often needs to access items from the crate it came from. However, simply writing in the crate name won't work, as the user may have renamed the crate to something else. To solve this, you can use the  prefix in your macro. As an example:

Token munching
Token munching is a technique for writing declarative macros where the macro takes in, which will match anything. The macro can then recursively call itself until it finishes parsing. Here is a (horribly inefficient, both at compile-time and run-time) recursive implementation of the macro:

Declarative macros 2.0
Currently, declarative macros are hard to write in and have lots of weird edge cases. To solve this, the declarative macros 2.0 RFC was written, describing a new macro system. However, this RFC does not specify many concrete details and importantly the actual syntax of the new macros has yet to be decided. The new syntax will likely look like:

All that is definitively stated in the RFC is that the  keyword will be used instead of the out of place-looking   we have today.

Procedural macros
Procedural macros, or proc-macros, are a type of macro that allows for macros to run arbitrary Rust code during compilation. Procedural macros must be made in their own crate, which can contain nothing but procedural macros. To create a procedural macro crate, you must put this somewhere in your :

Then all public functions in your library become procedural macros.

Procedural macros operate on token trees. A token tree is the fundamental unit of Rust source code after raw Unicode characters and before the AST. The types that define token trees are in the crate; procedural macros are merely functions that take and return sequences of token trees (known as token streams).

There are three types of proc macro: function-like, attribute and derive. Function-like macros are called the same way declarative macros are, but unlike declarative macros can't yet be used inside expressions on stable (they can only be used in a crate or module). Attribute macros are applied as attributes to an item - for example,. They take the item as input and replace it with their output. Derive macros are applied with the  attribute - for example,. The standard library contains many derive macros such as, , , etc. Derive macros, unlike attribute macros can only add items (usually impl blocks) next to the item they were applied to, whereas attribute macros completely destroy it. Attribute macros and derive macros also must always operate on a valid Rust AST, but function-like macros can operate on any sequence of tokens.

All the tokens in come with a. A span is an opaque structure representing where in the source code the tokens came from. It is good to hold onto them, because they can be used for many things such as nice error messages.

Reporting errors
There are three ways to report errors from within a proc macro. The simplest way is just to panic with an error message. Rustc will catch this panic and display an error message to the user. However, this isn't very good - it won't point the user to where the error occurred, it will just point to the entire macro invocation, making it very hard to fix it for a large macro. Moreover, warnings and additional notes on the error message can't be displayed using this, and only one error can be displayed per compilation.

The second method is using - by returning an invocation of   with the Span of where the error occurred in the input, you can easily report multiple more precise errors to the user. This is far better than panics, but still doesn't allow for warnings or notes on your error message.

The third method is nightly-only, but it provides the complete power of rustc's error reporting. The type allows for many precise errors, warnings and notes to be displayed to the user. All code should eventually move to using this, but for now using  is the best option.

Finally, the crate provides an easy to use API for reporting errors similar to the old  -based method, but using   and   under the hood, which leads to very nice error messages.

The types from the crate can only be used from within proc macros. If used outside it, it will compile, but it will panic. This is because  is actually implemented using IPC directly to , and so cannot be used without it. To solve this issue, the crate was created, which has an identical API to , and first attempts to use the native   implementation but if that fails falls back on its own implementation. As a result, types from  can be used in any context,   or not. If you are doing anything with proc macros you should be using.

Quoting with
Constructing token trees by hand is hard and verbose. The crate helps a lot, by providing a macro which automatically generates a   from simple Rust code. Here is a comparison of quote and the construction method constructing the expression :

See quote's documentation for more.

Working with token trees: and
Working directly with token trees is hard. As token trees are implemented using IPC under the hood, it prevents them from being easily introspectable and easily usable. The crate solves this by proving a similar API to proc_macro and proc_macro2, but being much more easy to use and transparent. For simple proc-macros, this is probably what you want to use.

For more complex proc macros, especially ones which take in Rust source code, the crate can be used. It provides an AST and a parser for any Rust source code, and is also easily extendable to support your own custom ASTs.

Testing procedural macros
Procedural macro crates can't invoke their own procedural macros, so you have to find workarounds in order to test your macros.

If you have written the main logic of your program using, then you can test your macro by calling the logic of your macro and comparing it to the expected output, using   to easily generate token streams. One hitch is that none of the types from  or   implement , so you can't use a simple. To solve this, you can convert both streams to strings via, and then   that.

Another common pattern to test proc macros is to have your wrapper crate around the proc macros contain tests for them, as the wrapper crate can invoke the implementation crate's proc macros.