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/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..e03ca9bf07 100644 --- a/src/macros-by-example.md +++ b/src/macros-by-example.md @@ -326,6 +326,108 @@ 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_rules! m2 { + () => { + println!("m2"); + }; +} + +// Resolves to path-based candidate from use declaration below. +m!(); // prints "m2\n" + +// Introduce second candidate for `m` with textual scope. +// +// This shadows path-based candidate from below for the rest of this +// example. +macro_rules! m { + () => { + println!("m"); + }; +} + +// Introduce m2 macro as path-based candidate. +// +// This item is in scope for this entire example, not just below the +// use declaration. +use m2 as m; + +// Resolves to the textual macro candidate from above the use +// declaration. +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 { + // Introduce macro m with textual scope. + macro_rules! m { + () => {}; + } + + // Re-export with path-based scope from within m's textual scope. + 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 +// Implicit visibility is `pub(crate)`. +macro_rules! private_m { + () => {}; +} + +// Implicit visibility is `pub`. +#[macro_export] +macro_rules! pub_m { + () => {}; +} + +pub(crate) use private_m as private_macro; // OK. +pub use pub_m as pub_macro; // OK. +``` + +```rust,compile_fail,E0364 +# // Implicit visibility is `pub(crate)`. +# macro_rules! private_m { +# () => {}; +# } +# +# // Implicit visibility is `pub`. +# #[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 +815,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..49e443fd9a 100644 --- a/src/names/name-resolution.md +++ b/src/names/name-resolution.md @@ -1,4 +1,553 @@ +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 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 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*. + +r[names.resolution.general] +## General + +r[names.resolution.general.intro] +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 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 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 in an external crate. + +```rust,compile_fail +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 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. +> +> ```rust,compile_fail,E0659 +> # fn main() {} +> macro_rules! f { +> () => { +> mod m { +> pub(crate) use f; +> } +> } +> } +> f!(); +> +> 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: `m` 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 and will produce an error. + +```rust +mod m { + pub const C: () = (); + pub enum E { V } + pub type A = E; + impl E { + pub const C: () = (); + } +} + +// Valid imports resolved at expansion-time: +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 _ = m::A::V; // OK. +let _ = m::E::C; // OK. +``` + +```rust,compile_fail,E0432 +# mod m { +# pub const C: () = (); +# pub enum E { V } +# pub type A = E; +# impl E { +# pub const C: () = (); +# } +# } +// Invalid type-relative imports that can't resolve at expansion-time: +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] +Names introduced via `use` declarations in an [outer scope] are shadowed by candidates in the same namespace with the same name from an inner scope except where otherwise restricted by [name resolution ambiguities]. + +```rust,no_run +pub mod m1 { + pub mod ambig { + pub const C: u8 = 1; + } +} + +pub mod m2 { + pub mod ambig { + pub const C: u8 = 2; + } +} + +// This introduces the name `ambig` in the outer scope. +use m1::ambig; +fn f() { + // This shadows `ambig` in the inner scope. + use m2::ambig; + // The inner candidate is selected here + // as the resolution of `ambig`. + use ambig::C; + const { assert!(C == 2) }; +} +``` + +r[names.resolution.expansion.imports.shadowing.shared-scope] +Shadowing of names introduced via `use` declarations within a single scope is permitted in the following situations: + +- [`use` glob shadowing] +- [Macro textual scope shadowing] + +r[names.resolution.expansion.imports.ambiguity] +#### Ambiguities + +r[names.resolution.expansion.imports.ambiguity.intro] +There are certain situations during expansion-time resolution where there are multiple macro definitions, `use` declarations, or modules an import or macro invocation's name could refer to where the compiler cannot consistently determine which candidate should shadow the other. Shadowing cannot be permitted in these situations and the compiler instead emits ambiguity errors. + +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: + +```rust,compile_fail,E0659 +mod m1 { + pub struct Ambig; +} + +mod m2 { + pub struct Ambig; +} + +// OK: This brings conficting names into scope and namespace +// but they have not been used yet. +use m1::*; +use m2::*; + +fn ambiguous_use() { + let x = Ambig; // ERROR: `Ambig` is ambiguous. +} +``` + +```rust +# mod m1 { +# pub struct Ambig; +# } +# +# mod m2 { +# pub struct Ambig; +# } +# +# use m1::*; +# use m2::*; // OK: No name conflict. +fn ambiguous_shadow() { + // This is permitted, since resolution is not through the ambiguous globs. + struct Ambig; + let x = Ambig; +} +``` + +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. + +```rust +mod m1 { + pub struct Ambig; +} + +mod m2 { + // This re-exports the same `Ambig` item through a second module. + pub use super::m1::Ambig; +} + +// These both import the same `Ambig`. +// +// The visibility of `Ambig` is `pub` because that is the +// maximum visibility between these two `use` declarations. +mod m3 { + pub use super::m1::*; + use super::m2::*; +} + +fn main() { + // `Ambig` can be used through the m3 + // globs and still has `pub` visibility. + let _ = m3::Ambig; +} +``` + +r[names.resolution.expansion.imports.ambiguity.glob-vs-outer] +Names in imports and macro invocations may not be resolved through glob imports when there is another candidate available in an [outer scope]. + +```rust,compile_fail,E0659 +mod glob { + pub mod ambig { + pub struct Name; + } +} + +// Outer `ambig` candidate. +pub mod ambig { + pub struct Name; +} + +const _: () = { + // Cannot resolve `ambig` through this glob + // because of the outer `ambig` candidate above. + use glob::*; + use ambig::Name; // ERROR: `ambig` is ambiguous. +}; +``` + +```rust,compile_fail,E0659 +use m::f as ambig; +pub mod m { + macro_rules! f { + () => {}; + } + pub(crate) use f; +} +pub mod glob { + macro_rules! f { + () => {}; + } + pub(crate) use f as ambig; +} + +const _: () = { + use glob::*; + ambig!(); // ERROR: `ambig` is ambiguous. +}; +``` + +> [!NOTE] +> These ambiguity errors are specific to expansion-time resolution. 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 glob { +> pub const AMBIG: bool = true; +> } +> +> mod outer { +> pub const AMBIG: bool = false; +> } +> +> use outer::AMBIG; +> +> pub fn f() { +> use glob::*; +> assert!(AMBIG); +> // ^--- This `AMBIG` is resolved during primary resolution. +> } +> ``` + +r[names.resolution.expansion.imports.ambiguity.path-vs-textual-macro] +Names may not be resolved through ambiguous macro re-exports. Macro re-exports are ambiguous when they would shadow a textual macro candidate for the same name in an [outer scope]. + +```rust,compile_fail,E0659 +// Textual macro candidate. +macro_rules! ambig { + () => {} +} + +// Path-based macro candidate. +macro_rules! path_based { + () => {} +} + +pub fn f() { + // This re-export of the `path_based` macro definition + // as `ambig` may not shadow the `ambig` macro definition + // which is resolved via textual macro scope. + use path_based as ambig; + ambig!(); // ERROR: `ambig` is ambiguous. +} +``` + +> [!NOTE] +> This restriction is needed due to implementation details in the compiler, +> specifically the current scope visitation logic and the complexity of supporting +> this behavior. This ambiguity error may be removed in the future. + +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 function-like 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 scope kinds are visited in the following order. Each of these scope kinds represent one or more scopes. + +* [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. This scope is visited after the scope for resolving derive helper candidates that are correctly in scope. This behavior is slated for removal. +> +> For more info see [derive helper scope]. + > [!NOTE] -> This is a placeholder for future expansion. +> +> This visitation order may change in the future, such as interleaving the +> visitation of textual and path-based scope candidates based on their lexical +> scopes. + +> [!EDITION-2018] +> +> Starting in edition 2018 the `#[macro_use]` prelude is not visited when `#[no_implicit_prelude]` is present. + +r[names.resolution.expansion.macros.derivehelpers] +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]. + +r[names.resolution.expansion.macros.ambiguity] +#### Ambiguities + +r[names.resolution.expansion.macros.ambiguity.more-expanded-vs-outer] +Names may not be resolved through ambiguous candidates inside of macro expansions. Candidates inside of macro expansions are ambiguous when they would shadow a candidate for the same name from outside of the first candidate's macro expansion and the invocation of the name being resolved is also from outside of the first candidate's macro expansion. + +```rust,compile_fail,E0659 +macro_rules! define_ambig { + () => { + macro_rules! ambig { + () => {} + } + } +} + +// Introduce outer candidate definition for `ambig` macro invocation. +macro_rules! ambig { + () => {} +} + +// Introduce a second candidate definition for `ambig` inside of a macro +// expansion. +define_ambig!(); + +// The definition of `ambig` from the second invocation +// of `define_ambig` is the innermost canadidate. +// +// The definition of `ambig` from the first invocation of `define_ambig` +// is the second candidate. +// +// The compiler checks that the first candidate is inside of a macro +// expansion, that the second candidate is not from within the same +// macro expansion, and that the name being resolved is not from +// within the same macro expansion. +ambig!(); // ERROR: `ambig` is ambiguous. +``` + +The reverse is not considered ambiguous. + +```rust +# macro_rules! define_ambig { +# () => { +# macro_rules! ambig { +# () => {} +# } +# } +# } +// Swap order of definitions. +define_ambig!(); +macro_rules! ambig { + () => {} +} +// The innermost candidate is now less expanded so it may shadow more +// the macro expanded definition above it. +ambig!(); +``` + +Nor is it ambiguous if the invocation being resolved is within the innermost candidate's expansion. + +```rust +macro_rules! ambig { + () => {} +} + +macro_rules! define_and_invoke_ambig { + () => { + // Define innermost candidate. + macro_rules! ambig { + () => {} + } + + // Invocation of `ambig` is in the same expansion as the + // innermost candidate. + ambig!(); // OK + } +} + +define_and_invoke_ambig!(); +``` + +It doesn't matter if both definitions come from invocations of the same macro, the outermost candidate is still considered "less expanded" because it is not within the expansion containing the innermost candidate's definition. + +```rust,compile_fail,E0659 +# macro_rules! define_ambig { +# () => { +# macro_rules! ambig { +# () => {} +# } +# } +# } +define_ambig!(); +define_ambig!(); +ambig!(); // ERROR: `ambig` is ambiguous. +``` + +This also applies to imports, so long as the innermost candidate for the invocation of name is from within a macro expansion. + +```rust,compile_fail,E0659 +macro_rules! define_ambig { + () => { + mod ambig { + pub struct Name; + } + } +} + +mod ambig { + pub struct Name; +} + +const _: () = { + // Introduce innermost candidate for + // `ambig` mod in this macro expansion. + define_ambig!(); + use ambig::Name; // ERROR: `ambig` is ambiguous. +}; +``` + +r[names.resolution.expansion.macros.ambiguity.builtin-attr] +User defined attributes or derive macros may not shadow builtin non-macro attributes (e.g. inline). + + +```rust,ignore +// with-helper/src/lib.rs +# use proc_macro::TokenStream; +#[proc_macro_derive(WithHelperAttr, attributes(non_exhaustive))] +// ^------------- user attr candidate +... +# pub fn derive_with_helper_attr(_item: TokenStream) -> TokenStream { +# TokenStream::new() +# } +``` + + +```rust,ignore +// src/lib.rs +#[derive(with_helper::WithHelperAttr)] +#[non_exhaustive] // ERROR: `non_exhaustive` is ambiguous. +struct S; +``` + +> [!NOTE] +> This applies regardless of the name the builtin attribute is a candidate for: +> +> +> ```rust,ignore +> // with-helper/src/lib.rs +> # use proc_macro::TokenStream; +> # +> #[proc_macro_derive(WithHelperAttr, attributes(helper))] +> // ^----- user attr candidate +> ... +> # pub fn derive_with_helper_attr(_item: TokenStream) -> TokenStream { +> # TokenStream::new() +> # } +> ``` +> +> +> ```rust,ignore +> // src/lib.rs +> use inline as helper; +> // ^----- builtin attr candidate via re-export +> +> #[derive(with_helper::WithHelperAttr)] +> #[helper] // ERROR: `helper` is ambiguous. +> struct S; +> ``` + +r[names.resolution.primary] +## Primary name resolution +> [!NOTE] +> This is a placeholder for future expansion about primary name 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 +[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 +[item definitions]: ../items.md +[macro invocations]: ../macros.md#macro-invocation +[macro textual scope shadowing]: ../macros-by-example.md#r-macro.decl.scope.textual.shadow +[name resolution ambiguities]: #r-names.resolution.expansion.imports.ambiguity +[namespaces]: ../names/namespaces.md +[outer scope]: #r-names.resolution.general.scopes +[path-based scope]: ../macros.md#r-macro.invocation.name-resolution +[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 diff --git a/src/names/namespaces.md b/src/names/namespaces.md index b3560d2c19..d8494350fd 100644 --- a/src/names/namespaces.md +++ b/src/names/namespaces.md @@ -117,58 +117,70 @@ 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] +> `use` imports still cannot create duplicate bindings of the same name in a module or block, regardless of sub-namespace. +> +> ```rust,ignore +> #[macro_export] +> macro_rules! mymac { +> () => {}; +> } +> +> use myattr::mymac; // error[E0252]: the name `mymac` is defined multiple times. +> ``` -[`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..721991f1eb 100644 --- a/src/procedural-macros.md +++ b/src/procedural-macros.md @@ -240,6 +240,24 @@ A helper attribute for a derive macro is declared by adding its identifier to th > } > ``` +r[macro.proc.derive.attributes.scope] +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. +> +> +> ```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] ## The `proc_macro_attribute` attribute @@ -432,6 +450,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