diff --git a/src/items/use-declarations.md b/src/items/use-declarations.md index 94638b6a1..0f95cf881 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,59 +394,6 @@ 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 @@ -460,3 +412,4 @@ fn main() { [tool attributes]: ../attributes.md#tool-attributes [type alias]: type-aliases.md [type namespace]: ../names/namespaces.md +[name resolution ambiguities]: ../names/name-resolution.html#r-names.resolution.expansion.imports.ambiguity diff --git a/src/macros-by-example.md b/src/macros-by-example.md index 2fa104ed4..4912e7f07 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 may 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]`](macros-by-example.html#the-macro_export-attribute) + +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 @@ -724,3 +795,5 @@ For more detail, see the [formal specification]. [Repetitions]: #repetitions [token]: tokens.md [`$crate`]: macro.decl.hygiene.crate +[Use declaration re-export]: items/use-declarations.md#use-visibility +[name resolution ambiguities]: names/name-resolution.md#r-names.resolution.expansion.imports.ambiguity diff --git a/src/macros.md b/src/macros.md index 36287e0d4..4ab14fd89 100644 --- a/src/macros.md +++ b/src/macros.md @@ -106,6 +106,16 @@ 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] + [Macros by Example]: macros-by-example.md [Procedural Macros]: procedural-macros.md [associated items]: items/associated-items.md diff --git a/src/names/name-resolution.md b/src/names/name-resolution.md index da60d7eb3..415ab96ae 100644 --- a/src/names/name-resolution.md +++ b/src/names/name-resolution.md @@ -1,4 +1,356 @@ +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.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. + +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). The resolution of imports must be *stable*. After expansion, imports in the fully expanded AST must resolve to the same definition, regardless of the order in which macros are expanded. 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 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] + +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,compile_fail,E0432 +mod my_mod { + pub const Const: () = (); + + pub enum MyEnum { + MyVariant + } + + impl MyEnum { + pub const Const: () = (); + } + + pub type TypeAlias = MyEnum; +} + +fn foo() { + // imports resolved at expansion-time + use my_mod::MyEnum; // OK + use my_mod::MyEnum::MyVariant; // OK + use my_mod::TypeAlias; // OK + use my_mod::TypeAlias::MyVariant; // Doesn't work + use my_mod::MyEnum::Const; // Doesn't work + use my_mod::Const; // OK + + // expressions resolved during type-relative resolution + let _ = my_mod::TypeAlias::MyVariant; // OK + let _ = my_mod::MyEnum::Const; // OK +} +``` + +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] +it is an error to shadow an outer name binding with a glob import. + +```rust,compile_fail,E0659 +mod bar { + pub mod foo { + pub struct Name; + } +} + +mod baz { + pub mod foo { + pub struct Name; + } +} + +pub mod foo { + 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** 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 struct Name; +> } +> +> mod baz { +> pub struct Name; +> } +> +> use baz::Name; +> +> pub fn foo() { +> use bar::*; +> Name; // resolves to bar::Name +> } +> ``` + +r[names.resolution.expansion.imports.ambiguity.moreexpandedvsouter] +It is an error for name bindings from macro expansions to 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 +> deprecated and slated for removal. +> +> ```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 are resolved by iterating through the available scopes until a candidate +is found. 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. The available scopes are visited in the following order. + +* derive helpers + * not visited when resolving derive macros in the parent scope (starting scope) +* derive helpers compat +* textual scope macros +* path-based scope macros +* macrouseprelude + * not visited in 2018 and later when `#[no_implicit_prelude]` is present +* stdlibprelude +* builtinattrs + +r[names.resolution.expansion.macros.errors.reserved-names + +the names cfg and cfg_attr are reserved in the macro attribute [sub-namespace]. + +r[names.resolution.late] + > [!NOTE] > This is a placeholder for future expansion. + +r[names.resolution.type-dependent] + +> [!NOTE] +> This is a placeholder for future expansion. + +[use glob shadowing]: ../items/use-declarations.md#r-items.use.glob.shadowing +[Macros]: ../macros.md +[use declarations]: ../items/use-declarations.md +[macro textual scope shadowing]: ../macros-by-example.md#r-macro.decl.scope.textual.shadow +[`let` bindings]: ../statements.md#let-statements +[item definitions]: ../items.md +[namespaces]: ../names/namespaces.md +[scope]: ../names/scopes.md +[visibility]: ../visibility-and-privacy.md +[permitted]: name-resolution.md#r-names.resolution.expansion.imports.shadowing +[macro invocations]: ../macros.md#macro-invocation +[path-based scope]: ../macros.md#r-macro.invocation.name-resolution +[sub-namespace]: ../names/namespaces.md#r-names.namespaces.sub-namespaces diff --git a/src/names/namespaces.md b/src/names/namespaces.md index b3560d2c1..8baa57096 100644 --- a/src/names/namespaces.md +++ b/src/names/namespaces.md @@ -117,8 +117,8 @@ 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 @@ -172,3 +172,5 @@ It is still an error for a [`use` import] to shadow another macro, regardless of [Type aliases]: ../items/type-aliases.md [union]: ../items/unions.md [use declaration]: ../items/use-declarations.md +[name resolution ambiguity errors]: name-resolution.md#r-names.resolution.expansion.imports.ambiguity.pathvstextualmacro + diff --git a/src/procedural-macros.md b/src/procedural-macros.md index 4395e3db9..5a526f93c 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 @@ -440,3 +444,4 @@ their equivalent `#[doc = r"str"]` attributes when passed to macros. [type expressions]: types.md#type-expressions [type]: types.md [union]: items/unions.md +[name resolution ambiguities]: names/name-resolution.md#r-names.resolution.expansion.imports.ambiguity.derivehelper