I thought "hygiene" would prevent collisions between X
s defined within my macro m!
but that turned out not to be the case. What am I misunderstanding?
macro_rules! m {
($e:expr) => {
const X: i32 = $e;
};
}
m!(0);
m!(1);
fn main() {
m!(2);
m!(3);
}
Playground
Error message:
error[E0428]: the name `X` is defined multiple times
--> src/main.rs:3:9
|
3 | const X: i32 = $e;
| ^^^^^^^^^^^^^^^^^^
| |
| `X` redefined here
| previous definition of the value `X` here
...
7 | m!(0);
| ------ in this macro invocation
|
= note: `X` must be defined only once in the value namespace of this module
From The Rust Programming Language (first edition)'s section on macro hygiene:
This [i.e. renaming] holds for let
bindings and loop labels, but not for items
The Rust reference defines items:
An item is a component of a crate. Items are organized within a crate
by a nested set of modules. Every crate has a single "outermost"
anonymous module; all further items within the crate have paths within
the module tree of the crate.
Items are entirely determined at compile-time, generally remain fixed
during execution, and may reside in read-only memory.
There are several kinds of items:
- modules
extern crate
declarations
use
declarations
- function definitions
- type definitions
- struct definitions
- enumeration definitions
- union definitions
- constant items
- static items
- trait definitions
- implementations
extern
blocks
This makes sense: if you you introduce an item in a macro you presumably want to actually use it from other items/modules/crates (and thus outside the macro), but you can't if you don't know its name, so the compiler can't rename it.