Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions book.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ use-boolean-and = true
"/items/modules.html#prelude-items" = "../names/preludes.html"
"/items/traits.html#object-safety" = "traits.html#dyn-compatibility"
"/lifetime-elision.html#static-lifetime-elision" = "lifetime-elision.html#const-and-static-elision"
"/macros-by-example.html#path-based-scope" = "macros-by-example.html#the-macro_export-attribute"
"/procedural-macros.html#derive-macros" = "procedural-macros.html#the-proc_macro_derive-attribute"
"/runtime.html#the-panic_handler-attribute" = "panic.html#the-panic_handler-attribute"
"/unsafe-blocks.html" = "unsafe-keyword.html"
Expand Down
2 changes: 1 addition & 1 deletion src/attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ The following is an index of all built-in attributes.
[`link_ordinal`]: items/external-blocks.md#the-link_ordinal-attribute
[`link_section`]: abi.md#the-link_section-attribute
[`link`]: items/external-blocks.md#the-link-attribute
[`macro_export`]: macros-by-example.md#path-based-scope
[`macro_export`]: macros-by-example.md#the-macro_export-attribute
[`macro_use`]: macros-by-example.md#the-macro_use-attribute
[`must_use`]: attributes/diagnostics.md#the-must_use-attribute
[`naked`]: attributes/codegen.md#the-naked-attribute
Expand Down
186 changes: 135 additions & 51 deletions src/macros-by-example.md
Original file line number Diff line number Diff line change
Expand Up @@ -365,37 +365,145 @@ lazy_static!{}
```

r[macro.decl.scope.macro_use.export]
Macros to be imported with `#[macro_use]` must be exported with
`#[macro_export]`, which is described below.
Macros to be imported with `macro_use` must be exported with
[`macro_export`][macro.decl.scope.macro_export].

r[macro.decl.scope.path]
### Path-based scope
<!-- template:attributes -->
r[macro.decl.scope.macro_export]
### The `macro_export` attribute

r[macro.decl.scope.path.intro]
By default, a macro has no path-based scope. However, if it has the
`#[macro_export]` attribute, then it is declared in the crate root scope and can
be referred to normally as such:
r[macro.decl.scope.macro_export.intro]
The *`macro_export` [attribute][attributes]* exports the macro from the crate and makes it available in the root of the crate for path-based resolution.

```rust
self::m!();
m!(); // OK: Path-based lookup finds m in the current module.
> [!EXAMPLE]
> ```rust
> self::m!();
> // ^^^^ OK: Path-based lookup finds `m` in the current module.
> m!(); // As above.
>
> mod inner {
> super::m!();
> crate::m!();
> }
>
> mod mac {
> #[macro_export]
> macro_rules! m {
> () => {};
> }
> }
> ```

mod inner {
super::m!();
crate::m!();
}
r[macro.decl.scope.macro_export.syntax]
The `macro_export` attribute uses the [MetaWord] and [MetaListIdents] syntaxes. With the [MetaListIdents] syntax, it accepts a single [`local_inner_macros`][macro.decl.scope.macro_export.local_inner_macros] value.

mod mac {
#[macro_export]
macro_rules! m {
() => {};
}
}
```
r[macro.decl.scope.macro_export.allowed-positions]
The `macro_export` attribute may be applied to `macro_rules` definitions.

> [!NOTE]
> `rustc` ignores use in other positions but lints against it. This may become an error in the future.

r[macro.decl.scope.macro_export.duplicates]
Only the first use of `macro_export` on a macro has effect.

> [!NOTE]
> `rustc` lints against any use following the first.

r[macro.decl.scope.path.export]
Macros labeled with `#[macro_export]` are always `pub` and can be referred to
by other crates, either by path or by `#[macro_use]` as described above.
r[macro.decl.scope.macro_export.path-based]
By default, macros only have [textual scope][macro.decl.scope.textual] and cannot be resolved by path. When the `macro_export` attribute is used, the macro is made available in the crate root and can be referred to by its path.

> [!EXAMPLE]
> Without `macro_export`, macros only have textual scope, so path-based resolution of the macro fails.
>
> ```rust,compile_fail,E0433
> macro_rules! m {
> () => {};
> }
> self::m!(); // ERROR
> crate::m!(); // ERROR
> # fn main() {}
> ```
>
> With `macro_export`, path-based resolution works.
>
> ```rust
> #[macro_export]
> macro_rules! m {
> () => {};
> }
> self::m!(); // OK
> crate::m!(); // OK
> # fn main() {}
> ```

r[macro.decl.scope.macro_export.export]
The `macro_export` attribute causes a macro to be exported from the crate root so that it can be referred to in other crates by path.

> [!EXAMPLE]
> Given the following in a `log` crate:
>
> ```rust
> #[macro_export]
> macro_rules! warn {
> ($message:expr) => { eprintln!("WARN: {}", $message) };
> }
> ```
>
> From another crate, you can refer to the macro by path:
>
> <!-- ignore: requires external crates -->
> ```rust,ignore
> fn main() {
> log::warn!("example warning");
> }
> ```

r[macro.decl.scope.macro_export.macro_use]
`macro_export` allows the use of [`macro_use`][macro.decl.scope.macro_use] on an `extern crate` to import the macro into the [`macro_use` prelude].

> [!EXAMPLE]
> Given the following in a `log` crate:
>
> ```rust
> #[macro_export]
> macro_rules! warn {
> ($message:expr) => { eprintln!("WARN: {}", $message) };
> }
> ```
>
> Using `macro_use` in a dependent crate allows you to use the macro from the prelude:
>
> <!-- ignore: requires external crates -->
> ```rust,ignore
> #[macro_use]
> extern crate log;
>
> pub mod util {
> pub fn do_thing() {
> // Resolved via macro prelude.
> warn!("example warning");
> }
> }
> ```

r[macro.decl.scope.macro_export.local_inner_macros]
Adding `local_inner_macros` to the `macro_export` attribute causes all single-segment macro invocations in the macro definition to have an implicit `$crate::` prefix.

> [!NOTE]
> This is intended primarily as a tool to migrate code written before [`$crate`] was added to the language to work with Rust 2018's path-based imports of macros. Its use is discouraged in new code.

> [!EXAMPLE]
> ```rust
> #[macro_export(local_inner_macros)]
> macro_rules! helped {
> () => { helper!() } // Automatically converted to $crate::helper!().
> }
>
> #[macro_export]
> macro_rules! helper {
> () => { () }
> }
> ```

r[macro.decl.hygiene]
## Hygiene
Expand Down Expand Up @@ -495,32 +603,8 @@ macro_rules! call_foo {
fn foo() {}
```

> **Version differences**: Prior to Rust 1.30, `$crate` and
> `local_inner_macros` (below) were unsupported. They were added alongside
> path-based imports of macros (described above), to ensure that helper macros
> did not need to be manually imported by users of a macro-exporting crate.
> Crates written for earlier versions of Rust that use helper macros need to be
> modified to use `$crate` or `local_inner_macros` to work well with path-based
> imports.

r[macro.decl.hygiene.local_inner_macros]
When a macro is exported, the `#[macro_export]` attribute can have the
`local_inner_macros` keyword added to automatically prefix all contained macro
invocations with `$crate::`. This is intended primarily as a tool to migrate
code written before `$crate` was added to the language to work with Rust 2018's
path-based imports of macros. Its use is discouraged in new code.

```rust
#[macro_export(local_inner_macros)]
macro_rules! helped {
() => { helper!() } // Automatically converted to $crate::helper!().
}

#[macro_export]
macro_rules! helper {
() => { () }
}
```
> [!NOTE]
> Prior to Rust 1.30, `$crate` and [`local_inner_macros`][macro.decl.scope.macro_export.local_inner_macros] were unsupported. They were added alongside [path-based imports of macros][macro.decl.scope.macro_export], to ensure that helper macros did not need to be manually imported by users of a macro-exporting crate. Crates written for earlier versions of Rust that use helper macros need to be modified to use `$crate` or `local_inner_macros` to work well with path-based imports.

r[macro.decl.follow-set]
## Follow-set ambiguity restrictions
Expand Down
2 changes: 1 addition & 1 deletion src/names.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ to with certain [path qualifiers] or aliases.
[`for`]: expressions/loop-expr.md#iterator-loops
[`if let`]: expressions/if-expr.md#if-let-patterns
[`let` statement]: statements.md#let-statements
[`macro_export` attribute]: macros-by-example.md#path-based-scope
[`macro_export` attribute]: macros-by-example.md#the-macro_export-attribute
[`macro_rules` declarations]: macros-by-example.md
[`macro_use` attribute]: macros-by-example.md#the-macro_use-attribute
[`match`]: expressions/match-expr.md
Expand Down
2 changes: 1 addition & 1 deletion src/names/scopes.md
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ impl ImplExample {
[`if let`]: ../expressions/if-expr.md#if-let-patterns
[`while let`]: ../expressions/loop-expr.md#while-let-patterns
[`let` statement]: ../statements.md#let-statements
[`macro_export`]: ../macros-by-example.md#path-based-scope
[`macro_export`]: ../macros-by-example.md#the-macro_export-attribute
[`macro_use` prelude]: preludes.md#macro_use-prelude
[`macro_use`]: ../macros-by-example.md#the-macro_use-attribute
[`match` arms]: ../expressions/match-expr.md
Expand Down