Skip to content

Commit 3e5861d

Browse files
author
Keegan McAllister
committed
New revision
1 parent 45ff6ec commit 3e5861d

File tree

1 file changed

+63
-95
lines changed

1 file changed

+63
-95
lines changed

text/0000-macro-reform.md

Lines changed: 63 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,11 @@ enables macro re-export (see below). It is [implemented and
5353
tested](https://github.com/kmcallister/rust/commits/macro-reexport) but needs a
5454
rebase.
5555

56-
## Crate scope for macros
56+
We can add a lint to warn about cases where an exported macro has paths that
57+
are not absolute-with-crate or `$crate`-relative. This will have some
58+
(hopefully rare) false positives.
59+
60+
## Macro scope
5761

5862
In this document, the "syntax environment" refers to the set of syntax
5963
extensions that can be invoked at a given position in the crate. The names in
@@ -63,55 +67,48 @@ However, the exclamation point is really part of the invocation syntax, not the
6367
name, and some syntax extensions are invoked with no exclamation point, for
6468
example item decorators like `deriving`.
6569

66-
Imported macros will not automatically end up in the syntax environment.
67-
Instead, you can bring an imported macro into the syntax environment by
68-
providing the crate ident and a macro name (or wildcard) in a `use macro` view
69-
item:
70+
We introduce an attribute `use_macros` to specify which macros from an external
71+
crate should be imported to the syntax environment:
7072

7173
```rust
72-
use macro std::vec;
73-
use macro std::panic as fail;
74-
use macro core::*;
75-
```
76-
77-
These paths must have exactly two components: the crate ident, and a macro name
78-
or `*`.
74+
#[use_macros(vec, panic="fail")]
75+
extern crate std;
7976

80-
The syntax environment still consists of unqualified names. There's no way to
81-
invoke a macro through a qualified name. This obviates the need to change the
82-
parsing of expressions, patterns, etc.
83-
84-
`macro` is a new keyword. This is an important part of the proposal, because
85-
it signals that we're deviating from usual name resolution. `use macro` is a
86-
memorable and searchable name for the feature.
77+
#[use_macros(*)]
78+
extern crate core;
79+
```
8780

88-
The `use macro` view item only affects the syntax environment of the block or
89-
module where it appears, and only from the point of appearance onward. Unlike
90-
a normal `use` item, this includes child modules (in the same file or others).
81+
Macros imported this way can be used anywhere in the module after the
82+
`extern crate` item, including in child modules. Since a macro-importing
83+
`extern crate` must appear at the crate root, and view items come before
84+
other items, this effectively means imported macros will be visible for
85+
the entire crate.
9186

92-
Many macros expand using other "private macros" as an implementation detail.
87+
Many macros expand using other "helper macros" as an implementation detail.
9388
For example, librustc's `declare_lint!` uses `lint_initializer!`. The client
9489
should not know about this macro, although it still needs to be exported for
95-
cross-crate use. For this reason we allow `use macro` within a macro
90+
cross-crate use. For this reason we allow `#[use_macros]` on a macro
9691
definition.
9792

9893
```rust
9994
/// Not to be imported directly.
100-
extern macro_rules! lint_initializer { ... }
95+
#[export]
96+
macro_rules! lint_initializer { ... }
10197

10298
/// Declare a lint.
103-
extern macro_rules! declare_lint {
104-
use macro $crate::lint_initializer;
105-
99+
#[export]
100+
#[use_macros(lint_initializer)]
101+
macro_rules! declare_lint {
106102
($name:ident, $level:ident, $desc:expr) => (
107103
static $name: &'static $crate::lint::Lint
108104
= &lint_initializer!($name, $level, $desc);
109105
)
110106
}
111107
```
112108

113-
The macro `lint_initializer!` will be visible only during further expansion of
114-
the result of invoking `declare_lint!`.
109+
The macro `lint_initializer!`, imported from the same crate as `declare_lint!`,
110+
will be visible only during further expansion of the result of invoking
111+
`declare_lint!`.
115112

116113
Procedural macros need their own way to manipulate the syntax environment, but
117114
that's an unstable internal API, so it's outside the scope of this RFC.
@@ -120,43 +117,40 @@ that's an unstable internal API, so it's outside the scope of this RFC.
120117

121118
We also clean up macro syntax in a way that complements the semantic changes above.
122119

123-
## Macro definition syntax
120+
## `#[use_macros(...)] mod`
124121

125-
`macro_rules!` already allows `{ }` for the macro body, but the convention is
126-
`( )` for some reason. In accepting this RFC we would change to a `{ }`
127-
convention for consistency with the rest of the language.
128-
129-
The new macro can be used immediately. There is no way to `use macro` a macro
130-
defined in the same crate, and no need to do so.
131-
132-
A macro with a `pub` qualifier, i.e.
122+
The `use_macros` attribute can be applied to a `mod` item as well. The
123+
specified macros will "escape" the module and become visible throughout the
124+
rest of the enclosing module, including any child modules. A crate might start
125+
with
133126

134127
```rust
135-
pub macro_rules! foo { ... }
128+
#[use_macros(*)]
129+
mod macros;
136130
```
137131

138-
escapes the syntax environment for the enclosing block/module and becomes
139-
available throughout the rest of the crate (according to depth-first search).
140-
This is like putting `#[macro_escape]` on the module and all its ancestors, but
141-
applies *only* to the macro with `pub`.
132+
to define some macros for use by the whole crate, without putting those
133+
definitions in `lib.rs`.
142134

143-
## Macro export and re-export
144-
145-
A macro definition qualified by `extern` becomes available to other crates.
146-
That is, it can be the target of `use macro`. Or put another way,
147-
`extern macro_rules!` works the way `#[macro_export] macro_rules!` does today.
148-
Adding `extern` has no effect on the syntax environment for the current crate.
135+
Note that `#[use_macros(*)]` is equivalent to the current `#[macro_escape]`.
136+
However, the new convention is to use an outer attribute, in the file whose
137+
syntax environment is affected, rather than an inner attribute in the file
138+
defining the macros.
149139

150-
`pub` and `extern` may be used together on the same macro definition, since
151-
their effects are independent.
140+
## Macro export and re-export
152141

153-
We can also re-export macros that were imported from another crate. This is
154-
accomplished with `extern use macro`.
142+
A macro definition qualified by `#[export]` becomes available to other crates.
143+
That is, it can be the target of `#[use_macros]`. Or put another way,
144+
`#[export] macro_rules!` works the way `#[macro_export] macro_rules!` does
145+
today. Adding `#[export]` has no effect on the syntax environment for the
146+
current crate.
155147

156-
For example, libcollections defines a `vec!` macro, which would now look like:
148+
We can also re-export macros that were imported from another crate. For
149+
example, libcollections defines a `vec!` macro, which would now look like:
157150

158151
```rust
159-
extern macro_rules! vec {
152+
#[export]
153+
macro_rules! vec {
160154
($($e:expr),*) => ({
161155
let mut _temp = $crate::vec::Vec::new();
162156
$(_temp.push($e);)*
@@ -169,7 +163,8 @@ Currently, libstd duplicates this macro in its own `macros.rs`. Now it could
169163
do
170164

171165
```rust
172-
extern use macro collections::vec;
166+
#[reexport_macros(vec)]
167+
extern crate collections;
173168
```
174169

175170
as long as the module `std::vec` is interface-compatible with
@@ -184,11 +179,6 @@ works" as soon as `$crate` is available. It's implemented as part of the
184179

185180
## `#[plugin]` attribute
186181

187-
Since macros no longer automatically pollute the syntax environment, we can
188-
load them from every `extern crate`. (Probably we should exclude
189-
`extern crate`s that aren't at the crate root, because there's no way `$crate`
190-
paths will be correct.)
191-
192182
`#[phase(plugin)]` becomes simply `#[plugin]` and is still feature-gated. It
193183
only controls whether to search for and run a plugin registrar function. The
194184
plugin itself will decide whether it's to be linked at runtime, by calling a
@@ -208,39 +198,23 @@ to the plugin through a `Registry` method. This facilitates plugin
208198
configuration. The alternative in many cases is to use interacting side
209199
effects between procedural macros, which are harder to reason about.
210200

211-
# Miscellaneous remarks
212-
213-
In a future where macros are scoped the same way as other items,
214-
215-
```rust
216-
use macro std::vec;
217-
```
218-
219-
would become a deprecated synonym for
201+
## Syntax convention
220202

221-
```rust
222-
use std::vec!;
223-
```
203+
`macro_rules!` already allows `{ }` for the macro body, but the convention is
204+
`( )` for some reason. In accepting this RFC we would change to a `{ }`
205+
convention for consistency with the rest of the language.
224206

225-
Maintaining this synonym does not seem like a large burden.
207+
## Reserve `macro` as a keyword
226208

227-
We can add a lint to warn about cases where an `extern` macro has paths that
228-
are not absolute-with-crate or `$crate`-relative. This will have some
229-
(hopefully rare) false positives, and is not fully fleshed out yet.
209+
A lot of the syntax alternatives discussed for this RFC involved a `macro`
210+
keyword. The consensus is that macros are too unfinished to merit using the
211+
keyword now. However, we should reserve it for a future macro system.
230212

231213
# Implementation and transition
232214

233215
I will coordinate implementation of this RFC, and I expect to write most of the
234216
code myself.
235217

236-
Some of the syntax cleanups could be deferred until after 1.0. However the
237-
semantic changes are enough that many users will re-examine and perhaps edit a
238-
large fraction of their macro definitions. My thinking is that the cleaned-up
239-
syntax should be available when this happens rather than requiring a separate
240-
pass a few months later. Also I would really like the first Rust release to
241-
put its best foot forward with macros, not just in terms of semantics but
242-
with a polished and pleasant user experience.
243-
244218
To ease the transition, we can keep the old syntax as a deprecated synonym, to
245219
be removed before 1.0.
246220

@@ -282,15 +256,9 @@ reform. Two ways this could work out:
282256

283257
# Unresolved questions
284258

285-
Should we forbid `$crate` in non-`extern` macros? It seems useless, however I
286-
think we should allow it anyway, to encourage the habit of writing `$crate::`
287-
for any references to the local crate.
288-
289-
Should we allow `pub use macro`, which would escape the enclosing block/module
290-
the way `pub macro_rules!` does?
291-
292-
Should we require that `extern use macro` can only appear in the crate root?
293-
It doesn't make a lot of sense to put it elsewhere.
259+
Should we forbid `$crate` in non-`#[export]`ed macros? It seems useless,
260+
however I think we should allow it anyway, to encourage the habit of writing
261+
`$crate::` for any references to the local crate.
294262

295263
# Acknowledgements
296264

0 commit comments

Comments
 (0)