From d062154a08c29af79c0e8bb59bd23bdb10025aa3 Mon Sep 17 00:00:00 2001 From: Goldstein Date: Sat, 19 Oct 2024 20:37:34 +0300 Subject: [PATCH 1/2] Document mixed-site hygiene. --- src/macros-by-example.md | 49 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/src/macros-by-example.md b/src/macros-by-example.md index dad88a55a..78660e09c 100644 --- a/src/macros-by-example.md +++ b/src/macros-by-example.md @@ -416,11 +416,48 @@ by other crates, either by path or by `#[macro_use]` as described above. r[macro.decl.hygiene] r[macro.decl.hygiene.intro] -By default, all identifiers referred to in a macro are expanded as-is, and are -looked up at the macro's invocation site. This can lead to issues if a macro -refers to an item or macro which isn't in scope at the invocation site. To -alleviate this, the `$crate` metavariable can be used at the start of a path to -force lookup to occur inside the crate defining the macro. + +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: + +```rust +let x = 1; +fn func() { + unreachable!("this is never called") +} + +macro_rules! check { + () => { + assert_eq!(x, 1); // Uses `x` from the declaration site. + func(); // Uses `func` from the invocation site. + }; +} + +{ + let x = 2; + fn func() { /* does not panic */ } + check!(); +} +``` + +Labels and local variables defined in macro expansion are not shared between invocations, so this code doesn’t compile: + +```rust,compile_fail +macro_rules! m { + (define) => { + let x = 1; + }; + (refer) => { + dbg!(x); + }; +} + +m!(define); +m!(refer); +``` + +r[macro.decl.hygiene.crate] + +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. ```rust,ignore @@ -565,6 +602,7 @@ expansions, taking separators into account. This means: For more detail, see the [formal specification]. +[block labels]: expressions/loop-expr.md#labelled-block-expressions [const block]: expressions/block-expr.md#const-blocks [Hygiene]: #hygiene [IDENTIFIER]: identifiers.md @@ -580,6 +618,7 @@ For more detail, see the [formal specification]. [_Expression_]: expressions.md [_Item_]: items.md [_LiteralExpression_]: expressions/literal-expr.md +[loop labels]: expressions/loop-expr.md#loop-labels [_MetaListIdents_]: attributes.md#meta-item-attribute-syntax [_Pattern_]: patterns.md [_PatternNoTopAlt_]: patterns.md From 11ef50266c0c797184e9ddcbd2e74ffae0d9735f Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Tue, 22 Oct 2024 20:57:31 +0000 Subject: [PATCH 2/2] Prepare PR #1656 to be merged --- src/macros-by-example.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/macros-by-example.md b/src/macros-by-example.md index 78660e09c..6d93dab42 100644 --- a/src/macros-by-example.md +++ b/src/macros-by-example.md @@ -416,8 +416,7 @@ by other crates, either by path or by `#[macro_use]` as described above. r[macro.decl.hygiene] r[macro.decl.hygiene.intro] - -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: +Macros by example have _mixed-site hygiene_. This means that [loop labels], [block labels], and local variables are looked up at the macro definition site while other symbols are looked up at the macro invocation site. For example: ```rust let x = 1; @@ -427,7 +426,7 @@ fn func() { macro_rules! check { () => { - assert_eq!(x, 1); // Uses `x` from the declaration site. + assert_eq!(x, 1); // Uses `x` from the definition site. func(); // Uses `func` from the invocation site. }; } @@ -441,7 +440,7 @@ macro_rules! check { Labels and local variables defined in macro expansion are not shared between invocations, so this code doesn’t compile: -```rust,compile_fail +```rust,compile_fail,E0425 macro_rules! m { (define) => { let x = 1; @@ -456,7 +455,6 @@ m!(refer); ``` r[macro.decl.hygiene.crate] - 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.