Skip to content

Commit 182f2c6

Browse files
authored
Merge pull request #1885 from ehuss/macro_export
Update `macro_export` to use the attribute template
2 parents 752eab0 + e7f0a9c commit 182f2c6

File tree

5 files changed

+139
-54
lines changed

5 files changed

+139
-54
lines changed

book.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use-boolean-and = true
3333
"/items/modules.html#prelude-items" = "../names/preludes.html"
3434
"/items/traits.html#object-safety" = "traits.html#dyn-compatibility"
3535
"/lifetime-elision.html#static-lifetime-elision" = "lifetime-elision.html#const-and-static-elision"
36+
"/macros-by-example.html#path-based-scope" = "macros-by-example.html#the-macro_export-attribute"
3637
"/procedural-macros.html#derive-macros" = "procedural-macros.html#the-proc_macro_derive-attribute"
3738
"/runtime.html#the-panic_handler-attribute" = "panic.html#the-panic_handler-attribute"
3839
"/unsafe-blocks.html" = "unsafe-keyword.html"

src/attributes.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ The following is an index of all built-in attributes.
359359
[`link_ordinal`]: items/external-blocks.md#the-link_ordinal-attribute
360360
[`link_section`]: abi.md#the-link_section-attribute
361361
[`link`]: items/external-blocks.md#the-link-attribute
362-
[`macro_export`]: macros-by-example.md#path-based-scope
362+
[`macro_export`]: macros-by-example.md#the-macro_export-attribute
363363
[`macro_use`]: macros-by-example.md#the-macro_use-attribute
364364
[`must_use`]: attributes/diagnostics.md#the-must_use-attribute
365365
[`naked`]: attributes/codegen.md#the-naked-attribute

src/macros-by-example.md

Lines changed: 135 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -365,37 +365,145 @@ lazy_static!{}
365365
```
366366

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

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

374-
r[macro.decl.scope.path.intro]
375-
By default, a macro has no path-based scope. However, if it has the
376-
`#[macro_export]` attribute, then it is declared in the crate root scope and can
377-
be referred to normally as such:
375+
r[macro.decl.scope.macro_export.intro]
376+
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.
378377

379-
```rust
380-
self::m!();
381-
m!(); // OK: Path-based lookup finds m in the current module.
378+
> [!EXAMPLE]
379+
> ```rust
380+
> self::m!();
381+
> // ^^^^ OK: Path-based lookup finds `m` in the current module.
382+
> m!(); // As above.
383+
>
384+
> mod inner {
385+
> super::m!();
386+
> crate::m!();
387+
> }
388+
>
389+
> mod mac {
390+
> #[macro_export]
391+
> macro_rules! m {
392+
> () => {};
393+
> }
394+
> }
395+
> ```
382396
383-
mod inner {
384-
super::m!();
385-
crate::m!();
386-
}
397+
r[macro.decl.scope.macro_export.syntax]
398+
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.
387399
388-
mod mac {
389-
#[macro_export]
390-
macro_rules! m {
391-
() => {};
392-
}
393-
}
394-
```
400+
r[macro.decl.scope.macro_export.allowed-positions]
401+
The `macro_export` attribute may be applied to `macro_rules` definitions.
402+
403+
> [!NOTE]
404+
> `rustc` ignores use in other positions but lints against it. This may become an error in the future.
405+
406+
r[macro.decl.scope.macro_export.duplicates]
407+
Only the first use of `macro_export` on a macro has effect.
408+
409+
> [!NOTE]
410+
> `rustc` lints against any use following the first.
395411
396-
r[macro.decl.scope.path.export]
397-
Macros labeled with `#[macro_export]` are always `pub` and can be referred to
398-
by other crates, either by path or by `#[macro_use]` as described above.
412+
r[macro.decl.scope.macro_export.path-based]
413+
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.
414+
415+
> [!EXAMPLE]
416+
> Without `macro_export`, macros only have textual scope, so path-based resolution of the macro fails.
417+
>
418+
> ```rust,compile_fail,E0433
419+
> macro_rules! m {
420+
> () => {};
421+
> }
422+
> self::m!(); // ERROR
423+
> crate::m!(); // ERROR
424+
> # fn main() {}
425+
> ```
426+
>
427+
> With `macro_export`, path-based resolution works.
428+
>
429+
> ```rust
430+
> #[macro_export]
431+
> macro_rules! m {
432+
> () => {};
433+
> }
434+
> self::m!(); // OK
435+
> crate::m!(); // OK
436+
> # fn main() {}
437+
> ```
438+
439+
r[macro.decl.scope.macro_export.export]
440+
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.
441+
442+
> [!EXAMPLE]
443+
> Given the following in a `log` crate:
444+
>
445+
> ```rust
446+
> #[macro_export]
447+
> macro_rules! warn {
448+
> ($message:expr) => { eprintln!("WARN: {}", $message) };
449+
> }
450+
> ```
451+
>
452+
> From another crate, you can refer to the macro by path:
453+
>
454+
> <!-- ignore: requires external crates -->
455+
> ```rust,ignore
456+
> fn main() {
457+
> log::warn!("example warning");
458+
> }
459+
> ```
460+
461+
r[macro.decl.scope.macro_export.macro_use]
462+
`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].
463+
464+
> [!EXAMPLE]
465+
> Given the following in a `log` crate:
466+
>
467+
> ```rust
468+
> #[macro_export]
469+
> macro_rules! warn {
470+
> ($message:expr) => { eprintln!("WARN: {}", $message) };
471+
> }
472+
> ```
473+
>
474+
> Using `macro_use` in a dependent crate allows you to use the macro from the prelude:
475+
>
476+
> <!-- ignore: requires external crates -->
477+
> ```rust,ignore
478+
> #[macro_use]
479+
> extern crate log;
480+
>
481+
> pub mod util {
482+
> pub fn do_thing() {
483+
> // Resolved via macro prelude.
484+
> warn!("example warning");
485+
> }
486+
> }
487+
> ```
488+
489+
r[macro.decl.scope.macro_export.local_inner_macros]
490+
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.
491+
492+
> [!NOTE]
493+
> 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.
494+
495+
> [!EXAMPLE]
496+
> ```rust
497+
> #[macro_export(local_inner_macros)]
498+
> macro_rules! helped {
499+
> () => { helper!() } // Automatically converted to $crate::helper!().
500+
> }
501+
>
502+
> #[macro_export]
503+
> macro_rules! helper {
504+
> () => { () }
505+
> }
506+
> ```
399507
400508
r[macro.decl.hygiene]
401509
## Hygiene
@@ -495,32 +603,8 @@ macro_rules! call_foo {
495603
fn foo() {}
496604
```
497605

498-
> **Version differences**: Prior to Rust 1.30, `$crate` and
499-
> `local_inner_macros` (below) were unsupported. They were added alongside
500-
> path-based imports of macros (described above), to ensure that helper macros
501-
> did not need to be manually imported by users of a macro-exporting crate.
502-
> Crates written for earlier versions of Rust that use helper macros need to be
503-
> modified to use `$crate` or `local_inner_macros` to work well with path-based
504-
> imports.
505-
506-
r[macro.decl.hygiene.local_inner_macros]
507-
When a macro is exported, the `#[macro_export]` attribute can have the
508-
`local_inner_macros` keyword added to automatically prefix all contained macro
509-
invocations with `$crate::`. This is intended primarily as a tool to migrate
510-
code written before `$crate` was added to the language to work with Rust 2018's
511-
path-based imports of macros. Its use is discouraged in new code.
512-
513-
```rust
514-
#[macro_export(local_inner_macros)]
515-
macro_rules! helped {
516-
() => { helper!() } // Automatically converted to $crate::helper!().
517-
}
518-
519-
#[macro_export]
520-
macro_rules! helper {
521-
() => { () }
522-
}
523-
```
606+
> [!NOTE]
607+
> 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.
524608
525609
r[macro.decl.follow-set]
526610
## Follow-set ambiguity restrictions

src/names.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ to with certain [path qualifiers] or aliases.
137137
[`for`]: expressions/loop-expr.md#iterator-loops
138138
[`if let`]: expressions/if-expr.md#if-let-patterns
139139
[`let` statement]: statements.md#let-statements
140-
[`macro_export` attribute]: macros-by-example.md#path-based-scope
140+
[`macro_export` attribute]: macros-by-example.md#the-macro_export-attribute
141141
[`macro_rules` declarations]: macros-by-example.md
142142
[`macro_use` attribute]: macros-by-example.md#the-macro_use-attribute
143143
[`match`]: expressions/match-expr.md

src/names/scopes.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ impl ImplExample {
343343
[`if let`]: ../expressions/if-expr.md#if-let-patterns
344344
[`while let`]: ../expressions/loop-expr.md#while-let-patterns
345345
[`let` statement]: ../statements.md#let-statements
346-
[`macro_export`]: ../macros-by-example.md#path-based-scope
346+
[`macro_export`]: ../macros-by-example.md#the-macro_export-attribute
347347
[`macro_use` prelude]: preludes.md#macro_use-prelude
348348
[`macro_use`]: ../macros-by-example.md#the-macro_use-attribute
349349
[`match` arms]: ../expressions/match-expr.md

0 commit comments

Comments
 (0)