Skip to content

Commit d062154

Browse files
GoldsteinEtraviscross
authored andcommitted
Document mixed-site hygiene.
1 parent 458882b commit d062154

File tree

1 file changed

+44
-5
lines changed

1 file changed

+44
-5
lines changed

src/macros-by-example.md

+44-5
Original file line numberDiff line numberDiff line change
@@ -416,11 +416,48 @@ by other crates, either by path or by `#[macro_use]` as described above.
416416
r[macro.decl.hygiene]
417417

418418
r[macro.decl.hygiene.intro]
419-
By default, all identifiers referred to in a macro are expanded as-is, and are
420-
looked up at the macro's invocation site. This can lead to issues if a macro
421-
refers to an item or macro which isn't in scope at the invocation site. To
422-
alleviate this, the `$crate` metavariable can be used at the start of a path to
423-
force lookup to occur inside the crate defining the macro.
419+
420+
Macros by example have _mixed-site hygiene_. It means that [loop labels], [block labels] and local variables are looked up at the macro definition site, and other symbols are looked up at the macro invocation site. For example:
421+
422+
```rust
423+
let x = 1;
424+
fn func() {
425+
unreachable!("this is never called")
426+
}
427+
428+
macro_rules! check {
429+
() => {
430+
assert_eq!(x, 1); // Uses `x` from the declaration site.
431+
func(); // Uses `func` from the invocation site.
432+
};
433+
}
434+
435+
{
436+
let x = 2;
437+
fn func() { /* does not panic */ }
438+
check!();
439+
}
440+
```
441+
442+
Labels and local variables defined in macro expansion are not shared between invocations, so this code doesn’t compile:
443+
444+
```rust,compile_fail
445+
macro_rules! m {
446+
(define) => {
447+
let x = 1;
448+
};
449+
(refer) => {
450+
dbg!(x);
451+
};
452+
}
453+
454+
m!(define);
455+
m!(refer);
456+
```
457+
458+
r[macro.decl.hygiene.crate]
459+
460+
A special case is the `$crate` metavariable. It refers to the crate defining the macro, and can be used at the start of the path to look up items or macros which are not in scope at the invocation site.
424461

425462
<!-- ignore: requires external crates -->
426463
```rust,ignore
@@ -565,6 +602,7 @@ expansions, taking separators into account. This means:
565602

566603
For more detail, see the [formal specification].
567604

605+
[block labels]: expressions/loop-expr.md#labelled-block-expressions
568606
[const block]: expressions/block-expr.md#const-blocks
569607
[Hygiene]: #hygiene
570608
[IDENTIFIER]: identifiers.md
@@ -580,6 +618,7 @@ For more detail, see the [formal specification].
580618
[_Expression_]: expressions.md
581619
[_Item_]: items.md
582620
[_LiteralExpression_]: expressions/literal-expr.md
621+
[loop labels]: expressions/loop-expr.md#loop-labels
583622
[_MetaListIdents_]: attributes.md#meta-item-attribute-syntax
584623
[_Pattern_]: patterns.md
585624
[_PatternNoTopAlt_]: patterns.md

0 commit comments

Comments
 (0)