2016-02-11 09:28:06 +08:00
|
|
|
- Feature Name: N/A (part of other unstable features)
|
|
|
|
- Start Date: 2016-02-11
|
2017-11-01 21:29:36 +08:00
|
|
|
- RFC PR: [rust-lang/rfcs#1561](https://github.com/rust-lang/rfcs/pull/1561)
|
|
|
|
- Rust Issue: [rust-lang/rust#35896](https://github.com/rust-lang/rust/issues/35896)
|
2016-02-11 09:28:06 +08:00
|
|
|
|
|
|
|
# Summary
|
|
|
|
[summary]: #summary
|
|
|
|
|
|
|
|
Naming and modularisation for macros.
|
|
|
|
|
|
|
|
This RFC proposes making macros a first-class citizen in the Rust module system.
|
|
|
|
Both macros by example (`macro_rules` macros) and procedural macros (aka syntax
|
|
|
|
extensions) would use the same naming and modularisation scheme as other items
|
|
|
|
in Rust.
|
|
|
|
|
|
|
|
For procedural macros, this RFC could be implemented immediately or as part of a
|
|
|
|
larger effort to reform procedural macros. For macros by example, this would be
|
|
|
|
part of a macros 2.0 feature, the rest of which will be described in a separate
|
|
|
|
RFC. This RFC depends on the changes to name resolution described in
|
|
|
|
[RFC 1560](https://github.com/rust-lang/rfcs/pull/1560).
|
|
|
|
|
|
|
|
# Motivation
|
|
|
|
[motivation]: #motivation
|
|
|
|
|
|
|
|
Currently, procedural macros are not modularised at all (beyond the crate
|
|
|
|
level). Macros by example have a [custom modularisation
|
|
|
|
scheme](https://github.com/rust-lang/rfcs/blob/master/text/0453-macro-reform.md)
|
|
|
|
which involves modules to some extent, but relies on source ordering and
|
|
|
|
attributes which are not used for other items. Macros cannot be imported or
|
|
|
|
named using the usual syntax. It is confusing that macros use their own system
|
|
|
|
for modularisation. It would be far nicer if they were a more regular feature of
|
|
|
|
Rust in this respect.
|
|
|
|
|
|
|
|
|
|
|
|
# Detailed design
|
|
|
|
[design]: #detailed-design
|
|
|
|
|
|
|
|
## Defining macros
|
|
|
|
|
|
|
|
This RFC does not propose changes to macro definitions. It is envisaged that
|
|
|
|
definitions of procedural macros will change, see [this blog post](http://ncameron.org/blog/macro-plans-syntax/)
|
|
|
|
for some rough ideas. I'm assuming that procedural macros will be defined in
|
|
|
|
some function-like way and that these functions will be defined in modules in
|
|
|
|
their own crate (to start with).
|
|
|
|
|
|
|
|
Ordering of macro definitions in the source text will no longer be significant.
|
|
|
|
A macro may be used before it is defined, as long as it can be named. That is,
|
|
|
|
macros follow the same rules regarding ordering as other items. E.g., this will
|
|
|
|
work:
|
|
|
|
|
|
|
|
```
|
|
|
|
foo!();
|
|
|
|
|
2016-04-05 10:08:18 +08:00
|
|
|
macro! foo { ... }
|
2016-02-11 09:28:06 +08:00
|
|
|
```
|
|
|
|
|
2022-10-08 13:45:29 +08:00
|
|
|
(Note, I'm using a hypothetical `macro!` definition which I will define in a future
|
2016-04-05 10:08:18 +08:00
|
|
|
RFC. The reader can assume it works much like `macro_rules!`, but with the new
|
|
|
|
naming scheme).
|
|
|
|
|
2016-02-11 09:28:06 +08:00
|
|
|
Macro expansion order is also not defined by source order. E.g., in `foo!(); bar!();`,
|
|
|
|
`bar` may be expanded before `foo`. Ordering is only guaranteed as far as it is
|
|
|
|
necessary. E.g., if `bar` is only defined by expanding `foo`, then `foo` must be
|
|
|
|
expanded before `bar`.
|
|
|
|
|
|
|
|
## Function-like macro uses
|
|
|
|
|
|
|
|
A function-like macro use (c.f., attribute-like macro use) is a macro use which
|
|
|
|
uses `foo!(...)` or `foo! ident (...)` syntax (where `()` may also be `[]` or `{}`).
|
|
|
|
|
|
|
|
Macros may be named by using a `::`-separated path. Naming follows the same
|
|
|
|
rules as other items in Rust.
|
|
|
|
|
|
|
|
If a macro `baz` (by example or procedural) is defined in a module `bar` which
|
|
|
|
is nested in `foo`, then it may be used anywhere in the crate using an
|
|
|
|
absolute path: `::foo::bar::baz!(...)`. It can be used via relative paths in the
|
|
|
|
usual way, e.g., inside `foo` as `bar::baz!()`.
|
|
|
|
|
|
|
|
Macros declared inside a function body can only be used inside that function
|
|
|
|
body.
|
|
|
|
|
|
|
|
For procedural macros, the path must point to the function defining the macro.
|
|
|
|
|
|
|
|
The grammar for macros is changed, anywhere we currently parser `name "!"`, we
|
|
|
|
now parse `path "!"`. I don't think this introduces any issues.
|
|
|
|
|
|
|
|
Name lookup follows the same name resolution rules as other items. See [RFC
|
|
|
|
1560](https://github.com/rust-lang/rfcs/pull/1560) for details on how name
|
|
|
|
resolution could be adapted to support this.
|
|
|
|
|
|
|
|
## Attribute-like macro uses
|
|
|
|
|
|
|
|
Attribute macros may also be named using a `::`-separated path. Other than
|
|
|
|
appearing in an attribute, these also follow the usual Rust naming rules.
|
|
|
|
|
|
|
|
E.g., `#[::foo::bar::baz(...)]` and `#[bar::baz(...)]` are uses of absolute and
|
|
|
|
relative paths, respectively.
|
|
|
|
|
|
|
|
|
|
|
|
## Importing macros
|
|
|
|
|
|
|
|
Importing macros is done using `use` in the same way as other items. An `!` is
|
|
|
|
not necessary in an import item. Macros are imported into their own namespace
|
|
|
|
and do not shadow or overlap items with the same name in the type or value
|
|
|
|
namespaces.
|
|
|
|
|
|
|
|
E.g., `use foo::bar::baz;` imports the macro `baz` from the module `::foo::bar`.
|
|
|
|
Macro imports may be used in import lists (with other macro imports and with
|
|
|
|
non-macro imports).
|
|
|
|
|
|
|
|
Where a glob import (`use ...::*;`) imports names from a module including macro
|
|
|
|
definitions, the names of those macros are also imported. E.g., `use
|
|
|
|
foo::bar::*;` would import `baz` along with any other items in `foo::bar`.
|
|
|
|
|
|
|
|
Where macros are defined in a separate crate, these are imported in the same way
|
|
|
|
as other items by an `extern crate` item.
|
|
|
|
|
|
|
|
No `#[macro_use]` or `#[macro_export]` annotations are required.
|
|
|
|
|
|
|
|
|
2016-08-15 12:48:26 +08:00
|
|
|
## Shadowing
|
|
|
|
|
|
|
|
Macro names follow the same shadowing rules as other names. For example, an
|
|
|
|
explicitly declared macro would shadow a glob-imported macro with the same name.
|
|
|
|
Note that since macros are in a different namespace from types and values, a
|
|
|
|
macro cannot shadow a type or value or vice versa.
|
|
|
|
|
|
|
|
|
2016-02-11 09:28:06 +08:00
|
|
|
# Drawbacks
|
|
|
|
[drawbacks]: #drawbacks
|
|
|
|
|
|
|
|
If the new macro system is not well adopted by users, we could be left with two
|
|
|
|
very different schemes for naming macros depending on whether a macro is defined
|
|
|
|
by example or procedurally. That would be inconsistent and annoying. However, I
|
|
|
|
hope we can make the new macro system appealing enough and close enough to the
|
|
|
|
existing system that migration is both desirable and easy.
|
|
|
|
|
|
|
|
|
|
|
|
# Alternatives
|
|
|
|
[alternatives]: #alternatives
|
|
|
|
|
|
|
|
We could adopt the proposed scheme for procedural macros only and keep the
|
|
|
|
existing scheme for macros by example.
|
|
|
|
|
|
|
|
We could adapt the current macros by example scheme to procedural macros.
|
|
|
|
|
|
|
|
We could require the `!` in macro imports to distinguish them from other names.
|
|
|
|
I don't think this is necessary or helpful.
|
|
|
|
|
|
|
|
We could continue to require `macro_export` annotations on top of this scheme.
|
|
|
|
However, I prefer moving to a scheme using the same privacy system as the rest
|
|
|
|
of Rust, see below.
|
|
|
|
|
|
|
|
|
|
|
|
# Unresolved questions
|
|
|
|
[unresolved]: #unresolved-questions
|
|
|
|
|
|
|
|
## Privacy for macros
|
|
|
|
|
|
|
|
I would like that macros follow the same rules for privacy as other Rust items,
|
|
|
|
i.e., they are private by default and may be marked as `pub` to make them
|
|
|
|
public. This is not as straightforward as it sounds as it requires parsing `pub
|
2016-04-05 10:08:18 +08:00
|
|
|
macro! foo` as a macro definition, etc. I leave this for a separate RFC.
|
2016-02-11 09:28:06 +08:00
|
|
|
|
|
|
|
## Scoped attributes
|
|
|
|
|
|
|
|
It would be nice for tools to use scoped attributes as well as procedural
|
|
|
|
macros, e.g., `#[rustfmt::skip]` or `#[rust::new_attribute]`. I believe this
|
|
|
|
should be straightforward syntactically, but there are open questions around
|
|
|
|
when attributes are ignored or seen by tools and the compiler. Again, I leave it
|
|
|
|
for a future RFC.
|
|
|
|
|
|
|
|
## Inline procedural macros
|
|
|
|
|
|
|
|
Some day, I hope that procedural macros may be defined in the same crate in
|
|
|
|
which they are used. I leave the details of this for later, however, I don't
|
|
|
|
think this affects the design of naming - it should all Just Work.
|
2016-08-15 12:48:26 +08:00
|
|
|
|
|
|
|
## Applying to existing macros
|
|
|
|
|
|
|
|
This RFC is framed in terms of a new macro system. There are various ways that
|
|
|
|
some parts of it could be applied to existing macros (`macro_rules!`) to
|
|
|
|
backwards compatibly make existing macros usable under the new naming system.
|
|
|
|
|
|
|
|
I want to leave this question unanswered for now. Until we get some experience
|
|
|
|
implementing this feature it is unclear how much this is possible. Once we know
|
|
|
|
that we can try to decide how much of that is also desirable.
|