From fa52328c7f1f9dd9ddef911de085b5c332f293a5 Mon Sep 17 00:00:00 2001 From: Jane Losare-Lusby Date: Mon, 13 Oct 2025 13:57:28 -0700 Subject: [PATCH 1/5] Add section on expansion-time (early) name resolution Co-authored-by: Vadim Petrochenkov Co-authored-by: Eric Huss Co-authored-by: Tshepang Mbambo --- src/items/use-declarations.md | 67 +----- src/macros-by-example.md | 82 ++++++- src/macros.md | 14 +- src/names/name-resolution.md | 387 +++++++++++++++++++++++++++++++++- src/names/namespaces.md | 54 ++--- src/procedural-macros.md | 5 + 6 files changed, 519 insertions(+), 90 deletions(-) diff --git a/src/items/use-declarations.md b/src/items/use-declarations.md index 94638b6a12..71661d6cc0 100644 --- a/src/items/use-declarations.md +++ b/src/items/use-declarations.md @@ -116,6 +116,7 @@ They may create bindings for: * [Built-in types] * [Attributes] * [Derive macros] +* [`macro_rules`] r[items.use.path.disallowed] They cannot import [associated items], [generic parameters], [local variables], paths with [`Self`], or [tool attributes]. More restrictions are described below. @@ -302,6 +303,10 @@ mod clashing { } ``` +> [!NOTE] +> +> For areas where shadowing is not allowed, see [name resolution ambiguities]. + r[items.use.glob.last-segment-only] `*` cannot be used as the first or intermediate segments. @@ -389,71 +394,19 @@ r[items.use.restrictions.variant] use TypeAlias::MyVariant; //~ ERROR ``` -r[items.use.ambiguities] -## Ambiguities - -> [!NOTE] -> This section is incomplete. - -r[items.use.ambiguities.intro] -Some situations are an error when there is an ambiguity as to which name a `use` declaration refers. This happens when there are two name candidates that do not resolve to the same entity. - -r[items.use.ambiguities.glob] -Glob imports are allowed to import conflicting names in the same namespace as long as the name is not used. -For example: - -```rust -mod foo { - pub struct Qux; -} - -mod bar { - pub struct Qux; -} - -use foo::*; -use bar::*; //~ OK, no name conflict. - -fn main() { - // This would be an error, due to the ambiguity. - //let x = Qux; -} -``` - -Multiple glob imports are allowed to import the same name, and that name is allowed to be used, if the imports are of the same item (following re-exports). The visibility of the name is the maximum visibility of the imports. For example: - -```rust -mod foo { - pub struct Qux; -} - -mod bar { - pub use super::foo::Qux; -} - -// These both import the same `Qux`. The visibility of `Qux` -// is `pub` because that is the maximum visibility between -// these two `use` declarations. -pub use bar::*; -use foo::*; - -fn main() { - let _: Qux = Qux; -} -``` - -[`extern crate`]: extern-crates.md -[`macro_rules`]: ../macros-by-example.md -[`self`]: ../paths.md#self -[associated items]: associated-items.md [Attributes]: ../attributes.md [Built-in types]: ../types.md [Derive macros]: macro.proc.derive [Enum variants]: enumerations.md +[`extern crate`]: extern-crates.md +[`macro_rules`]: ../macros-by-example.md +[`self`]: ../paths.md#self +[associated items]: associated-items.md [extern prelude]: ../names/preludes.md#extern-prelude [generic parameters]: generics.md [items]: ../items.md [local variables]: ../variables.md +[name resolution ambiguities]: names.resolution.expansion.imports.ambiguity [namespace]: ../names/namespaces.md [namespaces]: ../names/namespaces.md [paths]: ../paths.md diff --git a/src/macros-by-example.md b/src/macros-by-example.md index 2fa104ed4d..64a89286b7 100644 --- a/src/macros-by-example.md +++ b/src/macros-by-example.md @@ -326,6 +326,77 @@ fn foo() { // m!(); // Error: m is not in scope. ``` +r[macro.decl.scope.textual.shadow.path-based] +Textual scope name bindings for macros shadow path-based scope bindings to macros. + +```rust +#[macro_export] +macro_rules! m2 { + () => { + println!("m2"); + }; +} + +m!(); // prints "m2\n" + +macro_rules! m { + () => { + println!("m"); + }; +} + +use crate::m2 as m; + +m!(); // prints "m\n" +``` + +> [!NOTE] +> +> For areas where shadowing is not allowed, see [name resolution ambiguities]. + +r[macro.decl.scope.path-based] +### Path-based scope + +r[macro.decl.scope.path-based.intro] +By default, a macro has no path-based scope. Macros can gain path-based scope in two ways: + +* [Use declaration re-export] +* [`macro_export`] + +r[macro.decl.scope.path.reexport] +Macros can be re-exported to give them path-based scope from a module other than the crate root. + +```rust +mac::m!(); // OK: Path-based lookup finds m in the mac module. + +mod mac { + macro_rules! m { + () => {}; + } + pub(crate) use m; +} +``` + +r[macro.decl.scope.path-based.visibility] +Macros have an implicit visibility of `pub(crate)`. `#[macro_export]` changes the implicit visibility to `pub`. + +```rust,compile_fail,E0364 +macro_rules! private_m { + () => {}; +} + +#[macro_export] +macro_rules! pub_m { + () => {}; +} + +pub(crate) use private_m as private_macro; // OK +pub use pub_m as pub_macro; // OK + +pub use private_m; // ERROR: `private_m` is only public within + // the crate and cannot be re-exported outside +``` + r[macro.decl.scope.macro_use] ### The `macro_use` attribute @@ -713,14 +784,17 @@ expansions, taking separators into account. This means: For more detail, see the [formal specification]. +[Hygiene]: #hygiene +[Metavariables]: #metavariables +[Repetitions]: #repetitions +[Use declaration re-export]: items/use-declarations.md#use-visibility +[`macro_export`]: #the-macro_export-attribute +[`$crate`]: macro.decl.hygiene.crate [`extern crate self`]: items.extern-crate.self [`macro_use` prelude]: names/preludes.md#macro_use-prelude [block labels]: expr.loop.block-labels [delimiters]: tokens.md#delimiters [formal specification]: macro-ambiguity.md -[Hygiene]: #hygiene [loop labels]: expressions/loop-expr.md#loop-labels -[Metavariables]: #metavariables -[Repetitions]: #repetitions +[name resolution ambiguities]: names/name-resolution.md#r-names.resolution.expansion.imports.ambiguity [token]: tokens.md -[`$crate`]: macro.decl.hygiene.crate diff --git a/src/macros.md b/src/macros.md index 36287e0d4a..1cd902034a 100644 --- a/src/macros.md +++ b/src/macros.md @@ -106,15 +106,25 @@ macro_rules! example { example!(); ``` +r[macro.invocation.name-resolution] + +Macros invocations can be resolved via two kinds of scopes: + +* Textual Scope + * [Textual scope `macro_rules`](macros-by-example.md#r-macro.decl.scope.textual) +* Path-based scope + * [Path-based scope `macro_rules`](macros-by-example.md#r-macro.decl.scope.path-based) + * [Procedural macros] + +[External blocks]: items/external-blocks.md [Macros by Example]: macros-by-example.md [Procedural Macros]: procedural-macros.md +[`macro_rules`]: macros-by-example.md [associated items]: items/associated-items.md [delimiters]: tokens.md#delimiters [expressions]: expressions.md [items]: items.md -[`macro_rules`]: macros-by-example.md [patterns]: patterns.md [statements]: statements.md [types]: types.md [visibility qualifiers]: visibility-and-privacy.md -[External blocks]: items/external-blocks.md diff --git a/src/names/name-resolution.md b/src/names/name-resolution.md index da60d7eb32..553e475d0e 100644 --- a/src/names/name-resolution.md +++ b/src/names/name-resolution.md @@ -1,4 +1,389 @@ +r[names.resolution] # Name resolution +r[names.resolution.intro] +_Name resolution_ is the process of tying paths and other identifiers to the declarations of those entities. Names are segregated into different [namespaces], allowing entities in different namespaces to share the same name without conflict. Each name is valid within a [scope], or a region of source text where that name may be referenced. Access to certain names may be restricted based on their [visibility]. + +Name resolution is split into three stages throughout the compilation process. The first stage, *expansion-time resolution*, resolves all [`use` declarations] and [macro invocations]. The second stage, *primary resolution*, resolves all names that have not yet been resolved that do not depend on type information to resolve. The last stage, *type-relative resolution*, resolves the remaining names once type information is available. + +> [!NOTE] +> +> * Expansion-time resolution is also known as "early resolution". +> * Primary resolution is also known as "late resolution". + +r[names.resolution.general] +## General + +r[names.resolution.general.intro] +The following rules apply to all stages of name resolution. + +r[names.resolution.general.scopes] +### Scopes + +r[names.resolution.general.scopes.intro] +> [!NOTE] +> This is a placeholder for future expansion about resolution of names through various scopes. + +r[names.resolution.expansion] +## Expansion-time name resolution + +r[names.resolution.expansion.intro] +Expansion-time name resolution is the stage of name resolution necessary to complete macro expansion and fully generate a crate's AST. This stage requires the resolution of macro invocations and `use` declarations. Resolving `use` declarations is required to resolve [path-based scope] macro invocations. Resolving macro invocations is required in order to expand them. + +r[names.resolution.expansion.unresolved-invocations] +After expansion-time name resolution, the AST must not contain any unexpanded macro invocations. Every macro invocation resolves to a valid definition that exists in the final AST or an external crate. + +```rust,compile_fail +fn main() { + foo!(); // ERROR: cannot find macro `foo` in this scope +} +``` + +r[names.resolution.expansion.expansion-order-stability] +The resolution of names must be *stable*. After expansion, names in the fully expanded AST must resolve to the same definition, regardless of the order in which macros are expanded. + +r[names.resolution.expansion.speculation] +All name resolution candidates selected during macro expansion are considering speculative. Once the crate has been fully expanded all speculative import resolutions are validated to ensure that no new ambiguities were introduced by macro expansion. + +> [!NOTE] +> +> Due to the iterative nature of macro expansion, this causes so called time traveling ambiguities, such as when a macro or glob import introduces an item that is ambiguous with its own base path. +> +> ```rust,compile_fail,E0659 +> macro_rules! m { +> () => { mod bar {} } +> } +> +> mod bar { +> pub(crate) use m; +> } +> +> fn f() { +> // * Initially speculatively resolve `bar` to the module in the crate root. +> // * Expansion of `m` introduces a second bar module inside the body of `f`. +> // * Expansion-time resolution finalizes resolutions by re-resolving all +> // imports and macro invocations, sees the introduced ambiguity +> // and reports it as an error. +> bar::m!(); // ERROR: `bar` is ambiguous +> } +> ``` + +r[names.resolution.expansion.imports] +### Imports +r[names.resolution.expansion.imports.intro] +All `use` declarations are fully resolved during this stage of resolution. Type-relative paths cannot be resolved at this stage of compilation and will produce an error. + +```rust +mod my_mod { + pub const CONST: () = (); + + pub enum MyEnum { + MyVariant + } + + impl MyEnum { + pub const CONST: () = (); + } + + pub type TypeAlias = MyEnum; +} + +// valid imports resolved at expansion-time +use my_mod::MyEnum; // OK +use my_mod::MyEnum::MyVariant; // OK +use my_mod::TypeAlias; // OK +use my_mod::CONST; // OK + +// valid expressions resolved during type-relative resolution +let _ = my_mod::TypeAlias::MyVariant; // OK +let _ = my_mod::MyEnum::CONST; // OK +``` + +```rust,compile_fail,E0432 +# mod my_mod { +# pub const CONST: () = (); +# +# pub enum MyEnum { +# MyVariant +# } +# +# impl MyEnum { +# pub const CONST: () = (); +# } +# +# pub type TypeAlias = MyEnum; +# } +// invalid type-relative imports that can't resolve at expansion-time +use my_mod::TypeAlias::MyVariant; // Doesn't work +use my_mod::MyEnum::CONST; // Doesn't work +``` + +r[names.resolution.expansion.imports.shadowing] +The following is a list of situations where shadowing of `use` declarations is permitted: + +* [`use` glob shadowing] +* [Macro textual scope shadowing] + +r[names.resolution.expansion.imports.ambiguity] +#### Ambiguities + +r[names.resolution.expansion.imports.ambiguity.intro] +Some situations are an error when there is an ambiguity as to which macro definition, `use` declaration, or module an import or macro invocation's name refers to. This happens when there are two name candidates that do not resolve to the same entity where neither candidate is [permitted] to shadow the other. + +r[names.resolution.expansion.imports.ambiguity.globvsglob] +Names may not be resolved through ambiguous glob imports. Glob imports are allowed to import conflicting names in the same namespace as long as the name is not used. Names with conflicting candidates from ambiguous glob imports may still be shadowed by non glob imports and used without producing an error. The errors occur at time of use, not time of import. + +For example: + +```rust +mod foo { + pub struct Qux; +} + +mod bar { + pub struct Qux; +} + +use foo::*; +use bar::*; //~ OK, no name conflict. + +fn ambiguous_use() { + // This would be an error, due to the ambiguity. + //let x = Qux; +} + +fn ambiguous_shadow() { + // This is permitted, since resolution is not through the ambiguous globs + struct Qux; + let x = Qux; +} +``` + +Multiple glob imports are allowed to import the same name, and that name is allowed to be used, if the imports are of the same item (following re-exports). The visibility of the name is the maximum visibility of the imports. For example: + +```rust +mod foo { + pub struct Qux; +} + +mod bar { + pub use super::foo::Qux; +} + +// These both import the same `Qux`. The visibility of `Qux` +// is `pub` because that is the maximum visibility between +// these two `use` declarations. +pub use bar::*; +use foo::*; + +fn main() { + let _: Qux = Qux; +} +``` + +r[names.resolution.expansion.imports.ambiguity.globvsouter] +Names may not be resolved through glob imports when there is another candidate available in an [outer scope]. + +```rust,compile_fail,E0659 +mod bar { + pub mod foo { +// ^-- glob `foo` candidate + pub struct Name; + } +} + +pub mod foo { +// ^-- outer `foo` candidate + pub struct Name; +} + +pub fn qux() { + use bar::*; + use foo::Name; // ERROR: `foo` is ambiguous +} +``` + +```rust,compile_fail,E0659 +pub mod bar { + #[macro_export] + macro_rules! m { + () => {}; + } + + macro_rules! m2 { + () => {}; + } + pub(crate) use m2 as m; +} + +pub fn qux() { + use bar::*; + m!(); // ERROR: `m` is ambiguous +} +``` + > [!NOTE] -> This is a placeholder for future expansion. +> These ambiguity errors are specific to imports, even though they are only observed when those imports are used, having multiple candidates available for a given name during later stages of resolution is not considered an error, so long as none of the imports themselves are ambiguous, there will always be a single unambiguous closest resolution during later stages. +> +> ```rust +> mod bar { +> pub const NAME: bool = true; +> } +> +> mod baz { +> pub const NAME: bool = false; +> } +> +> use baz::NAME; +> +> pub fn foo() { +> use bar::*; +> assert!(NAME); +> // ^--- this NAME is resolved during primary resolution +> } +> ``` + +r[names.resolution.expansion.imports.ambiguity.moreexpandedvsouter] +Name bindings from macro expansions to may not shadow name bindings from outside of those expansions. + +```rust,compile_fail,E0659 +macro_rules! name { + () => {} +} + +macro_rules! define_name { + () => { + macro_rules! name { + () => {} + } + } +} + +fn foo() { + define_name!(); + name!(); // ERROR: `name` is ambiguous +} +``` + +r[names.resolution.expansion.imports.ambiguity.pathvstextualmacro] +Path-based scope bindings for macros may not shadow textual scope bindings to macros. For bindings from [`use` declarations], this applies regardless of their [sub-namespace]. + +```rust,compile_fail,E0659 +#[macro_export] +macro_rules! m2 { + () => {} +} +macro_rules! m { + () => {} +} +pub fn foo() { + m!(); // ERROR: `m` is ambiguous + use crate::m2 as m; // in scope for entire function body +} +``` + +r[names.resolution.expansion.imports.ambiguity.builtin-attr] +It is an error to use a user defined attribute or derive macro with the same name as a builtin attribute (e.g. inline). + + +```rust,ignore +// myinline/src/lib.rs +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn inline(_attr: TokenStream, item: TokenStream) -> TokenStream { + item +} +``` + + +```rust,ignore +// src/lib.rs +use myinline::inline; +use myinline::inline as myinline; + +#[myinline::inline] +pub fn foo() {} + +#[crate::inline] +pub fn bar() {} + +#[myinline] +pub fn baz() {} + +#[inline] // ERROR: `inline` is ambiguous +pub fn qux() {} +``` + +r[names.resolution.expansion.imports.ambiguity.derivehelper] +Helper attributes may not be used before the macro that introduces them. + +> [!NOTE] +> rustc currently allows derive helpers to be used before their attribute macro introduces them into scope so long as they do not shadow any other attributes or derive helpers that are otherwise correctly in scope. This behavior is deprecated and slated for removal. +> +> TODO this is wrong +> +> +> ```rust,ignore +> #[helper] // deprecated, hard error in the future +> #[derive(WithHelperAttr)] +> struct Struct { +> field: (), +> } +> ``` +> +> For more details, see [Rust issue #79202](https://github.com/rust-lang/rust/issues/79202). + +r[names.resolution.expansion.macros] +### Macros + +r[names.resolution.expansion.macros.intro] +Macros are resolved by iterating through the available scopes to find the available candidates. Macros are split into two sub-namespaces, one for bang macros, and the other for attributes and derives. Resolution candidates from the incorrect sub-namespace are ignored. + +r[names.resolution.expansion.macros.visitation-order] +The available scopes are visited in the following order. + +* derive helpers +* derive helpers compat TODO admonitionify +* textual scope macros +* path-based scope macros +* macrouseprelude +* stdlibprelude +* builtinattrs + +> [!EDITION-2018] +> +> Starting in edition 2018 the `#[macro_use]` prelude is not visited when `#[no_implicit_prelude]` is present. + +TODO linkify + +r[names.resolution.expansion.macros.derivehelpers] +not visited when resolving derive macros in the parent scope (starting scope) + +r[names.resolution.expansion.macros.reserved-names] +The names `cfg` and `cfg_attr` are reserved in the macro attribute [sub-namespace]. + +r[names.resolution.primary] +## Primary name resolution +> [!NOTE] +> This is a placeholder for future expansion about primary name resolution. + +r[names.resolution.type-dependent] +# Type-dependent resolution +> [!NOTE] +> This is a placeholder for future expansion about type-dependent resolution. + +[Macros]: ../macros.md +[`let` bindings]: ../statements.md#let-statements +[`use` declarations]: ../items/use-declarations.md +[`use` glob shadowing]: ../items/use-declarations.md#r-items.use.glob.shadowing +[item definitions]: ../items.md +[macro invocations]: ../macros.md#macro-invocation +[macro textual scope shadowing]: ../macros-by-example.md#r-macro.decl.scope.textual.shadow +[namespaces]: ../names/namespaces.md +[outer scope]: #names.resolution.general.scopes +[path-based scope]: ../macros.md#r-macro.invocation.name-resolution +[permitted]: name-resolution.md#r-names.resolution.expansion.imports.shadowing +[scope]: ../names/scopes.md +[sub-namespace]: ../names/namespaces.md#r-names.namespaces.sub-namespaces +[visibility]: ../visibility-and-privacy.md diff --git a/src/names/namespaces.md b/src/names/namespaces.md index b3560d2c19..c5afbab79c 100644 --- a/src/names/namespaces.md +++ b/src/names/namespaces.md @@ -117,58 +117,60 @@ This prevents one style from shadowing another. For example, the [`cfg` attribute] and the [`cfg` macro] are two different entities with the same name in the macro namespace, but they can still be used in their respective context. -r[names.namespaces.sub-namespaces.use-shadow] -It is still an error for a [`use` import] to shadow another macro, regardless of their sub-namespaces. +> [!NOTE] +> For restrictions on shadowing macro sub-namespaces with [use declaration]s, see [name resolution ambiguity errors]. -[`cfg` attribute]: ../conditional-compilation.md#the-cfg-attribute -[`cfg` macro]: ../conditional-compilation.md#the-cfg-macro -[`for`]: ../expressions/loop-expr.md#iterator-loops -[`if let`]: ../expressions/if-expr.md#if-let-patterns -[`let`]: ../statements.md#let-statements -[`macro_rules` declarations]: ../macros-by-example.md -[`match`]: ../expressions/match-expr.md -[`Self` constructors]: ../paths.md#self-1 -[`Self` type]: ../paths.md#self-1 -[`use` import]: ../items/use-declarations.md -[`while let`]: ../expressions/loop-expr.md#while-let-patterns [Associated const declarations]: ../items/associated-items.md#associated-constants [Associated function declarations]: ../items/associated-items.md#associated-functions-and-methods [Associated type declarations]: ../items/associated-items.md#associated-types [Attribute macros]: ../procedural-macros.md#the-proc_macro_attribute-attribute -[attributes]: ../attributes.md -[bang-style macros]: ../macros.md [Block labels]: expr.loop.block-labels -[boolean]: ../types/boolean.md [Built-in attributes]: ../attributes.md#built-in-attributes-index -[closure parameters]: ../expressions/closure-expr.md -[closure]: ../expressions/closure-expr.md [Constant item declarations]: ../items/constant-items.md [Derive macro helpers]: ../procedural-macros.md#derive-macro-helper-attributes [Derive macros]: macro.proc.derive -[entity]: ../glossary.md#entity [Enum variant constructors]: ../items/enumerations.md -[enum]: ../items/enumerations.md [External crate declarations]: ../items/extern-crates.md [External crate prelude]: preludes.md#extern-prelude -[field expression]: ../expressions/field-expr.md [Function declarations]: ../items/functions.md -[function parameters]: ../items/functions.md#function-parameters [Function-like procedural macros]: ../procedural-macros.md#the-proc_macro-attribute [Generic const parameters]: ../items/generics.md#const-generics [Generic lifetime parameters]: ../items/generics.md [Generic type parameters]: ../items/generics.md [Loop labels]: ../expressions/loop-expr.md#loop-labels [Module declarations]: ../items/modules.md -[name resolution]: name-resolution.md -[names]: ../names.md -[numeric]: ../types/numeric.md [Static item declarations]: ../items/static-items.md [Struct constructors]: ../items/structs.md [Struct]: ../items/structs.md -[textual]: ../types/textual.md [Tool attribute modules]: ../attributes.md#tool-attributes [Tool attributes]: ../attributes.md#tool-attributes [Trait item declarations]: ../items/traits.md [Type aliases]: ../items/type-aliases.md +[`Self` constructors]: ../paths.md#self-1 +[`Self` type]: ../paths.md#self-1 +[`cfg` attribute]: ../conditional-compilation.md#the-cfg-attribute +[`cfg` macro]: ../conditional-compilation.md#the-cfg-macro +[`for`]: ../expressions/loop-expr.md#iterator-loops +[`if let`]: ../expressions/if-expr.md#if-let-patterns +[`let`]: ../statements.md#let-statements +[`macro_rules` declarations]: ../macros-by-example.md +[`match`]: ../expressions/match-expr.md +[`use` import]: ../items/use-declarations.md +[`while let`]: ../expressions/loop-expr.md#while-let-patterns +[attributes]: ../attributes.md +[bang-style macros]: ../macros.md +[boolean]: ../types/boolean.md +[closure parameters]: ../expressions/closure-expr.md +[closure]: ../expressions/closure-expr.md +[entity]: ../glossary.md#entity +[enum]: ../items/enumerations.md +[field expression]: ../expressions/field-expr.md +[function parameters]: ../items/functions.md#function-parameters +[name resolution ambiguity errors]: name-resolution.md#r-names.resolution.expansion.imports.ambiguity.pathvstextualmacro +[name resolution]: name-resolution.md +[names]: ../names.md +[numeric]: ../types/numeric.md +[textual]: ../types/textual.md [union]: ../items/unions.md [use declaration]: ../items/use-declarations.md + diff --git a/src/procedural-macros.md b/src/procedural-macros.md index 4395e3db95..11db99e58e 100644 --- a/src/procedural-macros.md +++ b/src/procedural-macros.md @@ -240,6 +240,10 @@ A helper attribute for a derive macro is declared by adding its identifier to th > } > ``` +> [!NOTE] +> +> For helper attribute ambiguity errors, see [name resolution ambiguities]. + r[macro.proc.attribute] ## The `proc_macro_attribute` attribute @@ -432,6 +436,7 @@ their equivalent `#[doc = r"str"]` attributes when passed to macros. [items]: items.md [macro namespace]: names/namespaces.md [module]: items/modules.md +[name resolution ambiguities]: names/name-resolution.md#r-names.resolution.expansion.imports.ambiguity.derivehelper [patterns]: patterns.md [public]: visibility-and-privacy.md [statements]: statements.md From c9aead38b56b6b0c59508f6b976cba0b1f814f99 Mon Sep 17 00:00:00 2001 From: Jane Losare-Lusby Date: Tue, 2 Dec 2025 11:23:09 -0800 Subject: [PATCH 2/5] resolving todos and review comments --- src/names/name-resolution.md | 71 +++++++++++++++++------------------- src/procedural-macros.md | 18 ++++++++- 2 files changed, 50 insertions(+), 39 deletions(-) diff --git a/src/names/name-resolution.md b/src/names/name-resolution.md index 553e475d0e..0005956c92 100644 --- a/src/names/name-resolution.md +++ b/src/names/name-resolution.md @@ -88,13 +88,13 @@ mod my_mod { pub type TypeAlias = MyEnum; } -// valid imports resolved at expansion-time +// Valid imports resolved at expansion-time: use my_mod::MyEnum; // OK use my_mod::MyEnum::MyVariant; // OK use my_mod::TypeAlias; // OK use my_mod::CONST; // OK -// valid expressions resolved during type-relative resolution +// Valid expressions resolved during type-relative resolution: let _ = my_mod::TypeAlias::MyVariant; // OK let _ = my_mod::MyEnum::CONST; // OK ``` @@ -113,9 +113,9 @@ let _ = my_mod::MyEnum::CONST; // OK # # pub type TypeAlias = MyEnum; # } -// invalid type-relative imports that can't resolve at expansion-time -use my_mod::TypeAlias::MyVariant; // Doesn't work -use my_mod::MyEnum::CONST; // Doesn't work +// Invalid type-relative imports that can't resolve at expansion-time: +use my_mod::TypeAlias::MyVariant; // ERROR: unresolved import `my_mod::TypeAlias` +use my_mod::MyEnum::CONST; // ERROR: unresolved import `my_mod::MyEnum::CONST` ``` r[names.resolution.expansion.imports.shadowing] @@ -145,7 +145,7 @@ mod bar { } use foo::*; -use bar::*; //~ OK, no name conflict. +use bar::*; // OK, no name conflict. fn ambiguous_use() { // This would be an error, due to the ambiguity. @@ -153,7 +153,7 @@ fn ambiguous_use() { } fn ambiguous_shadow() { - // This is permitted, since resolution is not through the ambiguous globs + // This is permitted, since resolution is not through the ambiguous globs. struct Qux; let x = Qux; } @@ -239,7 +239,7 @@ pub fn qux() { > pub fn foo() { > use bar::*; > assert!(NAME); -> // ^--- this NAME is resolved during primary resolution +> // ^--- This `NAME` is resolved during primary resolution. > } > ``` @@ -278,7 +278,7 @@ macro_rules! m { } pub fn foo() { m!(); // ERROR: `m` is ambiguous - use crate::m2 as m; // in scope for entire function body + use crate::m2 as m; // In scope for entire function body. } ``` @@ -315,25 +315,6 @@ pub fn baz() {} pub fn qux() {} ``` -r[names.resolution.expansion.imports.ambiguity.derivehelper] -Helper attributes may not be used before the macro that introduces them. - -> [!NOTE] -> rustc currently allows derive helpers to be used before their attribute macro introduces them into scope so long as they do not shadow any other attributes or derive helpers that are otherwise correctly in scope. This behavior is deprecated and slated for removal. -> -> TODO this is wrong -> -> -> ```rust,ignore -> #[helper] // deprecated, hard error in the future -> #[derive(WithHelperAttr)] -> struct Struct { -> field: (), -> } -> ``` -> -> For more details, see [Rust issue #79202](https://github.com/rust-lang/rust/issues/79202). - r[names.resolution.expansion.macros] ### Macros @@ -343,20 +324,26 @@ Macros are resolved by iterating through the available scopes to find the availa r[names.resolution.expansion.macros.visitation-order] The available scopes are visited in the following order. -* derive helpers -* derive helpers compat TODO admonitionify -* textual scope macros -* path-based scope macros -* macrouseprelude -* stdlibprelude -* builtinattrs +* [derive helpers] +* [textual scope macros] +* [path-based scope macros] +* [`macro_use` prelude] +* [Standard library prelude] +* [Builtin attributes] + +> [!NOTE] +> +> The compiler will attempt to resolve derive helpers that are used before +> their associated macro introduces them into scope after resolving derive +> helper candidates that are correctly in scope. This behavior is slated for +> removal. +> +> For more info see [derive helper scope]. > [!EDITION-2018] > > Starting in edition 2018 the `#[macro_use]` prelude is not visited when `#[no_implicit_prelude]` is present. -TODO linkify - r[names.resolution.expansion.macros.derivehelpers] not visited when resolving derive macros in the parent scope (starting scope) @@ -373,17 +360,25 @@ r[names.resolution.type-dependent] > [!NOTE] > This is a placeholder for future expansion about type-dependent resolution. +[Builtin attributes]: ./preludes.md#r-names.preludes.lang [Macros]: ../macros.md +[Standard library prelude]: ./preludes.md#r-names.preludes.std [`let` bindings]: ../statements.md#let-statements +[`macro_use` prelude]: ./preludes.md#r-names.preludes.macro_use [`use` declarations]: ../items/use-declarations.md [`use` glob shadowing]: ../items/use-declarations.md#r-items.use.glob.shadowing +[derive helper scope]: ../procedural-macros.md#r-macro.proc.derive.attributes.scope +[derive helpers]: ../procedural-macros.md#r-macro.proc.derive.attributes [item definitions]: ../items.md [macro invocations]: ../macros.md#macro-invocation [macro textual scope shadowing]: ../macros-by-example.md#r-macro.decl.scope.textual.shadow [namespaces]: ../names/namespaces.md -[outer scope]: #names.resolution.general.scopes +[outer scope]: #r-names.resolution.general.scopes +[path-based scope macros]: ../macros.md#r-macro.invocation.name-resolution [path-based scope]: ../macros.md#r-macro.invocation.name-resolution [permitted]: name-resolution.md#r-names.resolution.expansion.imports.shadowing [scope]: ../names/scopes.md [sub-namespace]: ../names/namespaces.md#r-names.namespaces.sub-namespaces +[textual scope macros]: ../macros-by-example.md#r-macro.decl.scope.textual [visibility]: ../visibility-and-privacy.md + diff --git a/src/procedural-macros.md b/src/procedural-macros.md index 11db99e58e..94f5157718 100644 --- a/src/procedural-macros.md +++ b/src/procedural-macros.md @@ -240,9 +240,25 @@ A helper attribute for a derive macro is declared by adding its identifier to th > } > ``` +r[macro.proc.derive.attributes.scope] +Helper attributes are in scope after the macro that introduces them. + > [!NOTE] +> rustc currently allows derive helpers to be used before the macro that +> introduces them. Such derive helpers used out of order may not shadow other +> attribute macros. This behavior is deprecated and slated for removal. > -> For helper attribute ambiguity errors, see [name resolution ambiguities]. +> +> ```rust,ignore +> #[helper] // Deprecated, hard error in the future. +> #[derive(WithHelperAttr)] +> struct Struct { +> field: (), +> } +> ``` +> +> For more details, see [Rust issue #79202](https://github.com/rust-lang/rust/issues/79202). + r[macro.proc.attribute] From 3b2707673630245740f99e4822c050eb9d7cdf1a Mon Sep 17 00:00:00 2001 From: Jane Losare-Lusby Date: Tue, 2 Dec 2025 15:54:09 -0800 Subject: [PATCH 3/5] Apply suggestions from code review Co-authored-by: Eric Huss Co-authored-by: TC --- src/names/name-resolution.md | 13 +++++-------- src/procedural-macros.md | 6 ++---- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/names/name-resolution.md b/src/names/name-resolution.md index 0005956c92..f5dfd7345d 100644 --- a/src/names/name-resolution.md +++ b/src/names/name-resolution.md @@ -43,7 +43,7 @@ r[names.resolution.expansion.expansion-order-stability] The resolution of names must be *stable*. After expansion, names in the fully expanded AST must resolve to the same definition, regardless of the order in which macros are expanded. r[names.resolution.expansion.speculation] -All name resolution candidates selected during macro expansion are considering speculative. Once the crate has been fully expanded all speculative import resolutions are validated to ensure that no new ambiguities were introduced by macro expansion. +All name resolution candidates selected during macro expansion are considered speculative. Once the crate has been fully expanded, all speculative import resolutions are validated to ensure that macro expansion did not introduce any new ambiguities. > [!NOTE] > @@ -130,7 +130,7 @@ r[names.resolution.expansion.imports.ambiguity] r[names.resolution.expansion.imports.ambiguity.intro] Some situations are an error when there is an ambiguity as to which macro definition, `use` declaration, or module an import or macro invocation's name refers to. This happens when there are two name candidates that do not resolve to the same entity where neither candidate is [permitted] to shadow the other. -r[names.resolution.expansion.imports.ambiguity.globvsglob] +r[names.resolution.expansion.imports.ambiguity.glob-vs-glob] Names may not be resolved through ambiguous glob imports. Glob imports are allowed to import conflicting names in the same namespace as long as the name is not used. Names with conflicting candidates from ambiguous glob imports may still be shadowed by non glob imports and used without producing an error. The errors occur at time of use, not time of import. For example: @@ -223,7 +223,7 @@ pub fn qux() { ``` > [!NOTE] -> These ambiguity errors are specific to imports, even though they are only observed when those imports are used, having multiple candidates available for a given name during later stages of resolution is not considered an error, so long as none of the imports themselves are ambiguous, there will always be a single unambiguous closest resolution during later stages. +> These ambiguity errors are specific to imports, even though they are only observed when those imports are used. Having multiple candidates available for a given name during later stages of resolution is not considered an error, so long as none of the imports themselves are ambiguous, there will always be a single unambiguous closest resolution. > > ```rust > mod bar { @@ -333,10 +333,7 @@ The available scopes are visited in the following order. > [!NOTE] > -> The compiler will attempt to resolve derive helpers that are used before -> their associated macro introduces them into scope after resolving derive -> helper candidates that are correctly in scope. This behavior is slated for -> removal. +> The compiler will attempt to resolve derive helpers that are used before their associated macro introduces them into scope after resolving derive helper candidates that are correctly in scope. This behavior is slated for removal. > > For more info see [derive helper scope]. @@ -345,7 +342,7 @@ The available scopes are visited in the following order. > Starting in edition 2018 the `#[macro_use]` prelude is not visited when `#[no_implicit_prelude]` is present. r[names.resolution.expansion.macros.derivehelpers] -not visited when resolving derive macros in the parent scope (starting scope) +Derive helper scopes are not visited when resolving derive macros in the parent scope (starting scope). r[names.resolution.expansion.macros.reserved-names] The names `cfg` and `cfg_attr` are reserved in the macro attribute [sub-namespace]. diff --git a/src/procedural-macros.md b/src/procedural-macros.md index 94f5157718..721991f1eb 100644 --- a/src/procedural-macros.md +++ b/src/procedural-macros.md @@ -241,12 +241,10 @@ A helper attribute for a derive macro is declared by adding its identifier to th > ``` r[macro.proc.derive.attributes.scope] -Helper attributes are in scope after the macro that introduces them. +When a derive macro invocation is applied to an item, the helper attributes introduced by that derive macro become in scope 1) for attributes that are applied to that item and are applied lexically after the derive macro invocation and 2) for attributes that are applied to fields and variants inside of the item. > [!NOTE] -> rustc currently allows derive helpers to be used before the macro that -> introduces them. Such derive helpers used out of order may not shadow other -> attribute macros. This behavior is deprecated and slated for removal. +> rustc currently allows derive helpers to be used before the macro that introduces them. Such derive helpers used out of order may not shadow other attribute macros. This behavior is deprecated and slated for removal. > > > ```rust,ignore From 04a4cfda182a026ac51bdee154ff0ec4796781e2 Mon Sep 17 00:00:00 2001 From: Jane Losare-Lusby Date: Tue, 2 Dec 2025 16:34:27 -0800 Subject: [PATCH 4/5] use sentence case for bullet points --- src/names/name-resolution.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/names/name-resolution.md b/src/names/name-resolution.md index f5dfd7345d..67d1a01ade 100644 --- a/src/names/name-resolution.md +++ b/src/names/name-resolution.md @@ -324,9 +324,9 @@ Macros are resolved by iterating through the available scopes to find the availa r[names.resolution.expansion.macros.visitation-order] The available scopes are visited in the following order. -* [derive helpers] -* [textual scope macros] -* [path-based scope macros] +* [Derive helpers] +* [Textual scope macros] +* [Path-based scope macros] * [`macro_use` prelude] * [Standard library prelude] * [Builtin attributes] @@ -358,24 +358,24 @@ r[names.resolution.type-dependent] > This is a placeholder for future expansion about type-dependent resolution. [Builtin attributes]: ./preludes.md#r-names.preludes.lang +[Derive helpers]: ../procedural-macros.md#r-macro.proc.derive.attributes [Macros]: ../macros.md +[Path-based scope macros]: ../macros.md#r-macro.invocation.name-resolution [Standard library prelude]: ./preludes.md#r-names.preludes.std +[Textual scope macros]: ../macros-by-example.md#r-macro.decl.scope.textual [`let` bindings]: ../statements.md#let-statements [`macro_use` prelude]: ./preludes.md#r-names.preludes.macro_use [`use` declarations]: ../items/use-declarations.md [`use` glob shadowing]: ../items/use-declarations.md#r-items.use.glob.shadowing [derive helper scope]: ../procedural-macros.md#r-macro.proc.derive.attributes.scope -[derive helpers]: ../procedural-macros.md#r-macro.proc.derive.attributes [item definitions]: ../items.md [macro invocations]: ../macros.md#macro-invocation [macro textual scope shadowing]: ../macros-by-example.md#r-macro.decl.scope.textual.shadow [namespaces]: ../names/namespaces.md [outer scope]: #r-names.resolution.general.scopes -[path-based scope macros]: ../macros.md#r-macro.invocation.name-resolution [path-based scope]: ../macros.md#r-macro.invocation.name-resolution [permitted]: name-resolution.md#r-names.resolution.expansion.imports.shadowing [scope]: ../names/scopes.md [sub-namespace]: ../names/namespaces.md#r-names.namespaces.sub-namespaces -[textual scope macros]: ../macros-by-example.md#r-macro.decl.scope.textual [visibility]: ../visibility-and-privacy.md From b6acfd7c48900eeb7ce1479e8b3d6b3d33995d7e Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Wed, 3 Dec 2025 01:58:25 +0000 Subject: [PATCH 5/5] WIP: Editorial revisions --- src/glossary.md | 1 + src/names/name-resolution.md | 202 +++++++++++++++++++---------------- 2 files changed, 111 insertions(+), 92 deletions(-) diff --git a/src/glossary.md b/src/glossary.md index fd865dcc4d..c6c1656b88 100644 --- a/src/glossary.md +++ b/src/glossary.md @@ -1,5 +1,6 @@ # Glossary +r[glossary.ast] ### Abstract syntax tree An ‘abstract syntax tree’, or ‘AST’, is an intermediate representation of diff --git a/src/names/name-resolution.md b/src/names/name-resolution.md index 67d1a01ade..4251a39793 100644 --- a/src/names/name-resolution.md +++ b/src/names/name-resolution.md @@ -2,127 +2,141 @@ r[names.resolution] # Name resolution r[names.resolution.intro] -_Name resolution_ is the process of tying paths and other identifiers to the declarations of those entities. Names are segregated into different [namespaces], allowing entities in different namespaces to share the same name without conflict. Each name is valid within a [scope], or a region of source text where that name may be referenced. Access to certain names may be restricted based on their [visibility]. +_Name resolution_ is the process of tying paths and other identifiers to the declarations of those entities. Names are segregated into different [namespaces], allowing entities in different namespaces to share the same name without conflict. Each name is valid within a [scope], or a region of source text where that name may be referenced. Access to a name may be restricted based on its [visibility]. -Name resolution is split into three stages throughout the compilation process. The first stage, *expansion-time resolution*, resolves all [`use` declarations] and [macro invocations]. The second stage, *primary resolution*, resolves all names that have not yet been resolved that do not depend on type information to resolve. The last stage, *type-relative resolution*, resolves the remaining names once type information is available. +Name resolution is split into three stages throughout the compilation process. The first stage, *expansion-time resolution*, resolves all [`use` declarations] and [macro invocations]. The second stage, *primary resolution*, resolves all names that have not yet been resolved and that do not depend on type information to resolve. The last stage, *type-relative resolution*, resolves the remaining names once type information is available. > [!NOTE] -> -> * Expansion-time resolution is also known as "early resolution". -> * Primary resolution is also known as "late resolution". +> Expansion-time resolution is also known as *early resolution*. Primary resolution is also known as *late resolution*. r[names.resolution.general] ## General r[names.resolution.general.intro] -The following rules apply to all stages of name resolution. +The rules within this section apply to all stages of name resolution. r[names.resolution.general.scopes] ### Scopes r[names.resolution.general.scopes.intro] > [!NOTE] -> This is a placeholder for future expansion about resolution of names through various scopes. +> This is a placeholder for future expansion about resolution of names within various scopes. r[names.resolution.expansion] ## Expansion-time name resolution r[names.resolution.expansion.intro] -Expansion-time name resolution is the stage of name resolution necessary to complete macro expansion and fully generate a crate's AST. This stage requires the resolution of macro invocations and `use` declarations. Resolving `use` declarations is required to resolve [path-based scope] macro invocations. Resolving macro invocations is required in order to expand them. +Expansion-time name resolution is the stage of name resolution necessary to complete macro expansion and fully generate a crate's [AST]. This stage requires the resolution of macro invocations and `use` declarations. Resolving `use` declarations is required for macro invocations that resolve via [path-based scope]. Resolving macro invocations is required in order to expand them. r[names.resolution.expansion.unresolved-invocations] -After expansion-time name resolution, the AST must not contain any unexpanded macro invocations. Every macro invocation resolves to a valid definition that exists in the final AST or an external crate. +After expansion-time name resolution, the AST must not contain any unexpanded macro invocations. Every macro invocation resolves to a valid definition that exists in the final AST or in an external crate. ```rust,compile_fail -fn main() { - foo!(); // ERROR: cannot find macro `foo` in this scope -} +m!(); // ERROR: Cannot find macro `m` in this scope. ``` r[names.resolution.expansion.expansion-order-stability] -The resolution of names must be *stable*. After expansion, names in the fully expanded AST must resolve to the same definition, regardless of the order in which macros are expanded. +The resolution of names must be stable. After expansion, names in the fully expanded AST must resolve to the same definition regardless of the order in which macros are expanded and imports are resolved. r[names.resolution.expansion.speculation] All name resolution candidates selected during macro expansion are considered speculative. Once the crate has been fully expanded, all speculative import resolutions are validated to ensure that macro expansion did not introduce any new ambiguities. > [!NOTE] -> -> Due to the iterative nature of macro expansion, this causes so called time traveling ambiguities, such as when a macro or glob import introduces an item that is ambiguous with its own base path. +> Due to the iterative nature of macro expansion, this causes so-called time traveling ambiguities, such as when a macro or glob import introduces an item that is ambiguous with its own base path. > > ```rust,compile_fail,E0659 -> macro_rules! m { -> () => { mod bar {} } +> # fn main() {} +> macro_rules! f { +> () => { +> mod m { +> pub(crate) use f; +> } +> } > } +> f!(); > -> mod bar { -> pub(crate) use m; -> } -> -> fn f() { -> // * Initially speculatively resolve `bar` to the module in the crate root. -> // * Expansion of `m` introduces a second bar module inside the body of `f`. -> // * Expansion-time resolution finalizes resolutions by re-resolving all -> // imports and macro invocations, sees the introduced ambiguity -> // and reports it as an error. -> bar::m!(); // ERROR: `bar` is ambiguous -> } +> const _: () = { +> // Initially, we speculatively resolve `m` to the module in +> // the crate root. +> // +> // Expansion of `f` introduces a second `m` module inside this +> // body. +> // +> // Expansion-time resolution finalizes resolutions by re- +> // resolving all imports and macro invocations, sees the +> // introduced ambiguity and reports it as an error. +> m::f!(); // ERROR: `bar` is ambiguous. +> }; > ``` r[names.resolution.expansion.imports] ### Imports r[names.resolution.expansion.imports.intro] -All `use` declarations are fully resolved during this stage of resolution. Type-relative paths cannot be resolved at this stage of compilation and will produce an error. +All `use` declarations are fully resolved during this stage of resolution. [Type-relative paths] cannot be resolved at this stage and will produce an error. ```rust -mod my_mod { - pub const CONST: () = (); - - pub enum MyEnum { - MyVariant +mod m { + pub const C: () = (); + pub enum E { V } + pub type A = E; + impl E { + pub const C: () = (); } - - impl MyEnum { - pub const CONST: () = (); - } - - pub type TypeAlias = MyEnum; } // Valid imports resolved at expansion-time: -use my_mod::MyEnum; // OK -use my_mod::MyEnum::MyVariant; // OK -use my_mod::TypeAlias; // OK -use my_mod::CONST; // OK +use m::C; // OK. +use m::E; // OK. +use m::A; // OK. +use m::E::V; // OK. // Valid expressions resolved during type-relative resolution: -let _ = my_mod::TypeAlias::MyVariant; // OK -let _ = my_mod::MyEnum::CONST; // OK +let _ = m::A::V; // OK. +let _ = m::E::C; // OK. ``` ```rust,compile_fail,E0432 -# mod my_mod { -# pub const CONST: () = (); -# -# pub enum MyEnum { -# MyVariant +# mod m { +# pub const C: () = (); +# pub enum E { V } +# pub type A = E; +# impl E { +# pub const C: () = (); # } -# -# impl MyEnum { -# pub const CONST: () = (); -# } -# -# pub type TypeAlias = MyEnum; # } // Invalid type-relative imports that can't resolve at expansion-time: -use my_mod::TypeAlias::MyVariant; // ERROR: unresolved import `my_mod::TypeAlias` -use my_mod::MyEnum::CONST; // ERROR: unresolved import `my_mod::MyEnum::CONST` +use m::E::C; // ERROR: Unresolved import `m::E::C`. +use m::A::V; // ERROR: Unresolved import `m::A::V`. ``` r[names.resolution.expansion.imports.shadowing] -The following is a list of situations where shadowing of `use` declarations is permitted: +Shadowing of names with a `use` declaration is permitted only with: + +- [`use` glob shadowing] +- [Macro textual scope shadowing] +- TODO: Also `use` declarations in anonymous scopes. + +Example for the TODO: + +```rust +pub mod foo { + pub mod baz { + pub struct Name; + } +} -* [`use` glob shadowing] -* [Macro textual scope shadowing] +pub mod bar { + pub mod baz { + pub struct Name; + } +} + +use foo::baz::Name; +fn f() { + use bar::baz::Name; + Name; +} +``` r[names.resolution.expansion.imports.ambiguity] #### Ambiguities @@ -159,7 +173,7 @@ fn ambiguous_shadow() { } ``` -Multiple glob imports are allowed to import the same name, and that name is allowed to be used, if the imports are of the same item (following re-exports). The visibility of the name is the maximum visibility of the imports. For example: +Multiple glob imports are allowed to import the same name, and that name is allowed to be used if the imports are of the same item (following re-exports). The visibility of the name is the maximum visibility of the imports. For example: ```rust mod foo { @@ -181,7 +195,7 @@ fn main() { } ``` -r[names.resolution.expansion.imports.ambiguity.globvsouter] +r[names.resolution.expansion.imports.ambiguity.glob-vs-outer] Names may not be resolved through glob imports when there is another candidate available in an [outer scope]. ```rust,compile_fail,E0659 @@ -223,7 +237,7 @@ pub fn qux() { ``` > [!NOTE] -> These ambiguity errors are specific to imports, even though they are only observed when those imports are used. Having multiple candidates available for a given name during later stages of resolution is not considered an error, so long as none of the imports themselves are ambiguous, there will always be a single unambiguous closest resolution. +> These ambiguity errors are specific to imports, even though they are only observed when those imports are used. Having multiple candidates available for a given name during later stages of resolution is not considered an error. So long as none of the imports themselves are ambiguous, there will always be a single unambiguous closest resolution. > > ```rust > mod bar { @@ -243,29 +257,7 @@ pub fn qux() { > } > ``` -r[names.resolution.expansion.imports.ambiguity.moreexpandedvsouter] -Name bindings from macro expansions to may not shadow name bindings from outside of those expansions. - -```rust,compile_fail,E0659 -macro_rules! name { - () => {} -} - -macro_rules! define_name { - () => { - macro_rules! name { - () => {} - } - } -} - -fn foo() { - define_name!(); - name!(); // ERROR: `name` is ambiguous -} -``` - -r[names.resolution.expansion.imports.ambiguity.pathvstextualmacro] +r[names.resolution.expansion.imports.ambiguity.path-vs-textual-macro] Path-based scope bindings for macros may not shadow textual scope bindings to macros. For bindings from [`use` declarations], this applies regardless of their [sub-namespace]. ```rust,compile_fail,E0659 @@ -347,16 +339,42 @@ Derive helper scopes are not visited when resolving derive macros in the parent r[names.resolution.expansion.macros.reserved-names] The names `cfg` and `cfg_attr` are reserved in the macro attribute [sub-namespace]. +r[names.resolution.expansion.macros.ambiguity] +#### Ambiguities + +r[names.resolution.expansion.macros.ambiguity.more-expanded-vs-outer] +Name bindings from macro expansions may not shadow name bindings from outside of those expansions. + +```rust,compile_fail,E0659 +macro_rules! name { + () => {} +} + +macro_rules! define_name { + () => { + macro_rules! name { + () => {} + } + } +} + +fn foo() { + define_name!(); + name!(); // ERROR: `name` is ambiguous +} +``` + r[names.resolution.primary] ## Primary name resolution > [!NOTE] > This is a placeholder for future expansion about primary name resolution. -r[names.resolution.type-dependent] -# Type-dependent resolution +r[names.resolution.type-relative] +# Type-relative resolution > [!NOTE] > This is a placeholder for future expansion about type-dependent resolution. +[AST]: glossary.ast [Builtin attributes]: ./preludes.md#r-names.preludes.lang [Derive helpers]: ../procedural-macros.md#r-macro.proc.derive.attributes [Macros]: ../macros.md @@ -377,5 +395,5 @@ r[names.resolution.type-dependent] [permitted]: name-resolution.md#r-names.resolution.expansion.imports.shadowing [scope]: ../names/scopes.md [sub-namespace]: ../names/namespaces.md#r-names.namespaces.sub-namespaces +[type-relative paths]: names.resolution.type-relative [visibility]: ../visibility-and-privacy.md -