diff --git a/src/attributes.md b/src/attributes.md index ccb7bca64aab6..d5fca6c288eea 100644 --- a/src/attributes.md +++ b/src/attributes.md @@ -35,8 +35,7 @@ Attributes may appear as any of: _Inner attributes_, written with a bang ("!") after the hash ("#"), apply to the item that the attribute is declared within. _Outer attributes_, written without -the bang after the hash, apply to the item or generic parameter that follow the -attribute. +the bang after the hash, apply to the thing that follows the attribute. Attributes may be applied to many things in the language: @@ -82,6 +81,24 @@ fn some_unused_variables() { } ``` +There are three kinds of attributes: + +* Built-in attributes +* Macro attributes +* Derive mode helper attributes + +## Active and inert attributes + +An attribute is either active or inert. During attribute processing, *active +attributes* remove themselves from the thing they are on while *inert attriutes* +stay on. + +The `cfg` and `cfg_attr` attributes are active. The `test` attribute is inert +when compiling for tests and active otherwise. Attribute macros are active. +All other attributes are inert. + +--- + The rest of this page describes or links to descriptions of which attribute names have meaning. @@ -161,14 +178,20 @@ which can be used to control type layout. - `macro_reexport` on an `extern crate` — re-export the named macros. -- `macro_export` - export a macro for cross-crate usage. +- `macro_export` - export a `macro_rules` macro for cross-crate usage. - `no_link` on an `extern crate` — even if we load this crate for macros, don't link it into the output. See the [macros section of the first edition of the book](../book/first-edition/macros.html#scoping-and-macro-importexport) for more -information on macro scope. +information on `macro_rules` macro scope. + +- `proc_macro` - Defines a [bang macro]. + +- `proc_macro_derive` - Defines a [derive macro]. + +- `proc_macro_attribute` - Defines an [attribute macro]. ## Miscellaneous attributes @@ -525,9 +548,11 @@ You can implement `derive` for your own traits through [procedural macros]. [match expressions]: expressions/match-expr.html [external blocks]: items/external-blocks.html [items]: items.html +[attribute macro]: procedural-macros.html#attribute-macros +[bang macro]: procedural-macros.html#bang-macros [conditional compilation]: conditional-compilation.html -[trait]: items/traits.html -[main]: crates-and-source-files.html +[derive macro]: procedural-macros.html#derive-macros +[trait]: items/traits.html[main]: crates-and-source-files.html [`Termination`]: ../std/process/trait.Termination.html [where clause]: items/where-clauses.html [trait or lifetime bounds]: trait-bounds.html diff --git a/src/conditional-compilation.md b/src/conditional-compilation.md index 56835773ab1b5..7df8566e76804 100644 --- a/src/conditional-compilation.md +++ b/src/conditional-compilation.md @@ -84,6 +84,8 @@ The following configurations must be defined by the implementation: This can be used to enable extra debugging code in development but not in production. For example, it controls the behavior of the standard library's `debug_assert!` macro. +* `proc_macro` - Set when the crate being compiled is being compiled with the + `proc_macro` [crate type]. You can also set another [attribute] based on a `cfg` variable with `cfg_attr`: @@ -96,4 +98,5 @@ This is the same as `#[b]` if `a` is set by `cfg`, and nothing otherwise. Lastly, configuration options can be used in expressions by invoking the `cfg!` macro: `cfg!(a)` evaluates to `true` if `a` is set, and `false` otherwise. -[attribute]: attributes.html \ No newline at end of file +[attribute]: attributes.html +[crate type]: linkage.html \ No newline at end of file diff --git a/src/items/functions.md b/src/items/functions.md index fab09563bd593..92af422a483c6 100644 --- a/src/items/functions.md +++ b/src/items/functions.md @@ -134,7 +134,8 @@ fn test_only() { The attributes that have meaning on a function are [`cfg`], [`deprecated`], [`doc`], `export_name`, `link_section`, `no_mangle`, [the lint check -attributes], [`must_use`], [the testing attributes], and [the optimization hint +attributes], [`must_use`], [the procedural macro attributes], [the testing +attributes], and [the optimization hint attributes]. [external blocks]: items/external-blocks.html @@ -147,6 +148,7 @@ attributes]. [attributes]: attributes.html [`cfg`]: conditional-compilation.html [the lint check attributes]: attributes.html#lint-check-attributes +[the procedural macro attributes]: procedural-macros.html [the testing attributes]: attributes.html#testing [the optimization hint attributes]: attributes.html#optimization-hints [`deprecated`]: attributes.html#deprecation diff --git a/src/linkage.md b/src/linkage.md index 3e004315a6db4..691e4658465b7 100644 --- a/src/linkage.md +++ b/src/linkage.md @@ -1,8 +1,11 @@ # Linkage -The Rust compiler supports various methods to link crates together both +> Note: This section is described more in terms of the compiler than of +> the language. + +The compiler supports various methods to link crates together both statically and dynamically. This section will explore the various methods to -link Rust crates together, and more information about native libraries can be +link crates together, and more information about native libraries can be found in the [FFI section of the book][ffi]. [ffi]: ../book/ffi.html @@ -35,7 +38,7 @@ be ignored in favor of only building the artifacts specified by command line. * `--crate-type=staticlib`, `#[crate_type = "staticlib"]` - A static system library will be produced. This is different from other library outputs in that - the Rust compiler will never attempt to link to `staticlib` outputs. The + the compiler will never attempt to link to `staticlib` outputs. The purpose of this output type is to create a static library containing all of the local crate's code along with all upstream dependencies. The static library is actually a `*.a` archive on linux and osx and a `*.lib` file on @@ -44,7 +47,7 @@ be ignored in favor of only building the artifacts specified by command line. dynamic dependencies on other Rust code. * `--crate-type=cdylib`, `#[crate_type = "cdylib"]` - A dynamic system - library will be produced. This is used when compiling Rust code as + library will be produced. This is used when compiling a dynamic library to be loaded from another language. This output type will create `*.so` files on Linux, `*.dylib` files on macOS, and `*.dll` files on Windows. @@ -52,7 +55,7 @@ be ignored in favor of only building the artifacts specified by command line. * `--crate-type=rlib`, `#[crate_type = "rlib"]` - A "Rust library" file will be produced. This is used as an intermediate artifact and can be thought of as a "static Rust library". These `rlib` files, unlike `staticlib` files, are - interpreted by the Rust compiler in future linkage. This essentially means + interpreted by the compiler in future linkage. This essentially means that `rustc` will look for metadata in `rlib` files like it looks for metadata in dynamic libraries. This form of output is used to produce statically linked executables as well as `staticlib` outputs. @@ -60,12 +63,13 @@ be ignored in favor of only building the artifacts specified by command line. * `--crate-type=proc-macro`, `#[crate_type = "proc-macro"]` - The output produced is not specified, but if a `-L` path is provided to it then the compiler will recognize the output artifacts as a macro and it can be loaded - for a program. If a crate is compiled with the `proc-macro` crate type it - will forbid exporting any items in the crate other than those functions - tagged `#[proc_macro_derive]` and those functions must also be placed at the - crate root. Finally, the compiler will automatically set the - `cfg(proc_macro)` annotation whenever any crate type of a compilation is the - `proc-macro` crate type. + for a program. Crates compiled with this crate type must only export + [procedural macros]. The compiler will automatically set the `proc_macro` + [configuration option]. The crates are always compiled with the same target + that the compiler itself was built with. For example, if you are executing + the compiler from Linux with an `x86_64` CPU, the target will be + `x86_64-unknown-linux-gnu` even if the crate is a dependency of another crate + being built for a different target. Note that these outputs are stackable in the sense that if multiple are specified, then the compiler will produce each form of output at once without @@ -124,7 +128,7 @@ dependencies will be used: In general, `--crate-type=bin` or `--crate-type=lib` should be sufficient for all compilation needs, and the other options are just available if more -fine-grained control is desired over the output format of a Rust crate. +fine-grained control is desired over the output format of a crate. ## Static and dynamic C runtimes @@ -205,3 +209,6 @@ a statically linked binary on MSVC you would execute: ```ignore,notrust RUSTFLAGS='-C target-feature=+crt-static' cargo build --target x86_64-pc-windows-msvc ``` + +[configuration option]: conditional-compilation.html +[procedural macros]: procedural-macros.html \ No newline at end of file diff --git a/src/procedural-macros.md b/src/procedural-macros.md index 993bd0e445ded..a5d07835745aa 100644 --- a/src/procedural-macros.md +++ b/src/procedural-macros.md @@ -1,24 +1,295 @@ ## Procedural Macros *Procedural macros* allow creating syntax extensions as execution of a function. -Procedural macros can be used to implement custom [derive] on your own -types. See [the book][procedural macros] for a tutorial. +Procedural macros come in one of three flavors: -Procedural macros involve a few different parts of the language and its -standard libraries. First is the `proc_macro` crate, included with Rust, -that defines an interface for building a procedural macro. The -`#[proc_macro_derive(Foo)]` attribute is used to mark the deriving -function. This function must have the type signature: +* [Function-like macros] - `custom!(...)` +* [Derive mode macros] - `#[derive(CustomMode)]` +* [Attribute macros] - `#[CustomAttribute]` + +Procedural macros allow you to run code at compile time that operates over Rust +syntax, both consuming and producing Rust syntax. You can sort of think of +procedural macros as functions from an AST to another AST. + +Procedural macros must be defined in a crate with the [crate type] of +`proc-macro`. + +> **Note**: When using Cargo, Procedural macro crates are defined with the +> `proc-macro` key in your manfiest: +> +> ```toml +> [lib] +> proc-macro = true +> ``` + +As functions, they must either return syntax, panic, or loop endlessly. Returned +syntax either replaces or adds the syntax depending on the kind of procedural +macro. Panics are caught by the compiler and are turned into a compiler error. +Endless loops are not caught by the compiler which hangs the compiler. + +Procedural macros run during compilation, and thus have the same resources that +the compiler has. For example, standard input, error, and output are the same +that the compiler has access to. Similarly, file access is the same. Because +of this, procedural macros have the same security concerns that [Cargo's +build scripts] have. + +Procedural macros have two ways of reporting errors. The first is to panic. The +second is to emit a [`compile_error`] macro invocation. + +### The `proc_macro` crate + +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. + +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 +*token stream* is roughly equivalent to `Vec` where a `TokenTree` +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. + +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. You can modify +the `Span` of any token. + +### Procedural macro hygiene + +Procedural macros are *unhygienic*. This means they behave as if the output +token stream was simply written inline to the code it's next to. This means that +it's affected by external items and also affects external imports. + +Macro authors need to be careful to ensure their macros work in as many contexts +as possible given this limitation. This often includes using absolute paths to +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`). + +### Function-like procedural macros + +*Function-like procedural macros* are procedural macros that are invoked using +the macro invocation operator (`!`). + +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. It may contain an +arbitrary number of [items]. These macros cannot expand to syntax that defines +new `macro_rule` style macros. + +For example, the following macro definition ignores its input and outputs a +function `answer` into its scope. ```rust,ignore +extern crate proc_macro; use proc_macro::TokenStream; -#[proc_macro_derive(Hello)] -pub fn hello_world(input: TokenStream) -> TokenStream +#[proc_macro] +pub fn make_answer(_item: TokenStream) -> TokenStream { + "fn answer() -> u32 { 42 }".parse().unwrap() +} ``` -Finally, procedural macros must be in their own crate, with the `proc-macro` -crate type. +And then we use it 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()); +} +``` + +These macros are only invokable in [modules]. They cannot even be invoked to +create [item declaration statements]. Furthermore, they must either be invoked +with curly braces and no semicolon or a different delimiter followed by a +semicolon. For example, `make_answer` from the previous example can be invoked +as `make_answer!{}`, `make_answer!();` or `make_answer![];`. + +### Derive mode macros + +*Derive mode macros* define new modes for the `derive` [attribute]. These macros +define new [items] given the token stream of a [struct], [enum], or [union]. +They also define [derive mode helper attributes]. + +Custom deriver modes are defined by a [public] [function] with the +`proc_macro_derive` attribute and a signature of `(TokenStream) -> TokenStream`. + +The input [`TokenStream`] is the token stream of the item that has the `derive` +attribute on it. The output [`TokenStream`] must be a set of items that are +then appended to the [module] or [block] that the item from the input +[`TokenStream`] is in. + +The following is an example of a derive mode macro. Instead of doing anything +useful with its input, it just appends a function `answer`. + +```rust,ignore +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_derive(AnswerFn)] +pub fn derive_answer_fn(_item: TokenStream) -> TokenStream { + "fn answer() -> u32 { 42 }".parse().unwrap() +} +``` + +And then using said derive mode: + +```rust,ignore +extern crate proc_macro_examples; +use proc_macro_examples::AnswerFn; + +#[derive(AnswerFn)] +struct Struct; + +fn main() { + assert_eq!(42, answer()); +} +``` + +#### Derive mode helper attributes + +Derive mode macros can add additional [attributes] into the scope of the [item] +they are on. Said attributes are called *derive mode helper attributes*. These +attributes are [inert], and their only purpose is to be fed into the derive +mode macro that defined them. That said, they can be seen by all macros. + +The way to define helper attributes is to put an `attributes` key in the +`proc_macro_derive` macro with a comma separated list of identifiers that are +the names of the helper attributes. + +For example, the following derive mode macro defines a helper attribute +`helper`, but ultimately doesn't do anything with it. + +```rust,ignore +# #[crate_type="proc-macro"] +# extern crate proc_macro; +# use proc_macro::TokenStream; + +#[proc_macro_derive(HelperAttr, attributes(helper))] +pub fn derive_helper_attr(_item: TokenStream) -> TokenStream { + TokenStream::new(); +} +``` + +And then usage on the derive mode on a struct: + +```rust,ignore +# #![crate_type="proc-macro"] +# extern crate proc_macro_examples; +# use proc_macro_examples::HelperAttr; + +#[derive(HelperAttr)] +struct Struct { + #[helper] field: () +} +``` + +### Attribute macros + +*Attribute macros* define new [attributes] which can be attached to [items]. + +Attribute macros are defined by a [public] [function] with the +`proc_macro_attribute` [attribute] that a signature of +`(TokenStream, TokenStream) -> TokenStream`. The first [`TokenStream`] is the +attribute's metaitems, not including the delimiters. If the attribute is written +without a metaitem, the attribute [`TokenStream`] is empty. The second +[`TokenStream`] is of the rest of the [item] including other [attributes] on the +[item]. The returned [`TokenStream`] replaces the [item] with an arbitrary +number of [items]. These macros cannot expand to syntax that defines new +`macro_rule` style macros. + +For example, this attribute macro takes the input stream and returns it as is, +effectively being the no-op of attributes. + +```rust,ignore +# #![crate_type = "proc-macro"] +# extern crate proc_macro; +# use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn return_as_is(_attr: TokenStream, item: TokenStream) -> TokenStream { + item +} +``` + +This following example shows the stringified [`TokenStream`s] that the attribute +macros see. The output will show in the output of the compiler. The output is +shown in the comments after the function prefixed with "out:". + +```rust,ignore +// my-macro/src/lib.rs +# extern crate proc_macro; +# use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn show_streams(attr: TokenStream, input: TokenStream) -> TokenStream { + println!("attr: \"{}\"", attr.to_string()); + println!("item: \"{}\"', input.to_string()); + item +} +``` + +```rust,ignore +// src/lib.rs +extern crate my_macro; + +use my_macro::show_streams; + +// Example: Basic function +#[show_streams] +fn invoke1() {} +// out: attr: "" +// out: item: "fn invoke1() { }" + +// Example: Attribute has a metaitem +#[show_streams(bar)] +fn invoke2() {} +// out: attr: "bar" +// out: item: "fn invoke2() {}" + +// Example: Multiple words in metaitem +#[show_streams(multiple words)] +fn invoke3() {} +// out: attr: "multiple words" +// out: item: "fn invoke3() {}" + +// Example: +#[show_streams { delimiters }] +fn invoke4() {} +// out: "delimiters" +// out: "fn invoke4() {}" +``` -[derive]: attributes.html#derive -[procedural macros]: ../book/first-edition/procedural-macros.html \ No newline at end of file +[`TokenStream`]: ../proc_macro/struct.TokenStream.html +[`TokenStream`s]: ../proc_macro/struct.TokenStream.html +[`compile_error`]: ../std/macro.compile_error.html +[`derive`]: attributes.html#derive +[`proc_macro` crate]: ../proc_macro/index.html +[Cargo's build scripts]: ../cargo/reference/build-scripts.html +[Derive mode macros]: #derive-mode-macros +[Attribute macros]: #attribute-macros +[Function-like macros]: #function-like-procedural-macros +[attribute]: attributes.html +[attributes]: attributes.html +[custom attributes]: attributes.html +[crate type]: linkage.html +[derive mode helper attributes]: #derive-mode-helper-attributes +[enum]: items/enumerations.html +[inert]: attributes.html#active-and-inert-attributes +[item]: items.html +[item declaration statements]: statements.html#item-declarations +[items]: items.html +[function]: items/functions.html +[macro]: macros.html +[module]: items/modules.html +[modules]: items/modules.html +[procedural macro tutorial]: ../book/2018-edition/appendix-04-macros.html#procedural-macros-for-custom-derive +[public]: visibility-and-privacy.html +[struct]: items/structs.html +[unions]: items/unions.html