From 276954590a30efa972227207aba771157fc862fe Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 20 Aug 2025 16:16:02 +0200 Subject: [PATCH 01/53] specify s390x target features --- src/attributes/codegen.md | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/attributes/codegen.md b/src/attributes/codegen.md index 24e4c2c3..bb446130 100644 --- a/src/attributes/codegen.md +++ b/src/attributes/codegen.md @@ -506,6 +506,30 @@ Feature | Implicitly Enables | Description [tail-call]: https://github.com/webassembly/tail-call [multivalue]: https://github.com/webassembly/multi-value +r[attributes.codegen.target_feature.s390x] +#### `s390x` + +On this platform the usage of `#[target_feature]` functions follows the [above restrictions][attributes.codegen.target_feature.safety-restrictions]. + +Further documentation on these features can be found in the "Additions to z/Architecture" section of Chapter 1 of the [Principles of Operation]. + +Feature | Implicitly Enables | Description +---------------------------------------|---------------------------------------|--------------------- +`vector` | | 128-bit vector instructions +`vector-enhancements-1` | `vector` | vector enhancements 1 +`vector-enhancements-2` | `vector-enhancements-1` | vector enhancements 2 +`vector-enhancements-3` | `vector-enhancements-2` | vector enhancements 3 +`vector-packed-decimal` | `vector` | vector packed-decimal +`vector-packed-decimal-enhancement` | `vector-packed-decimal` | vector packed-decimal enhancement +`vector-packed-decimal-enhancement-2` | `vector-packed-decimal-enhancement-2` | vector packed-decimal enhancement 2 +`vector-packed-decimal-enhancement-3` | `vector-packed-decimal-enhancement-3` | vector packed-decimal enhancement 3 +`nnp-assist` | `vector` | nnp assist +`miscellaneous-extensions-2` | | miscellaneous extensions 2 +`miscellaneous-extensions-3` | | miscellaneous extensions 3 +`miscellaneous-extensions-4` | | miscellaneous extensions 4 + +[Principles of Operation]: https://publibfp.dhe.ibm.com/epubs/pdf/a227832d.pdf + r[attributes.codegen.target_feature.info] ### Additional information @@ -516,8 +540,7 @@ that this option is not affected by the `target_feature` attribute, and is only driven by the features enabled for the entire crate. r[attributes.codegen.target_feature.remark-rt] -See the [`is_x86_feature_detected`] or [`is_aarch64_feature_detected`] macros -in the standard library for runtime feature detection on these platforms. +Whether a feature is enabled can be checked at runtime using a platform-specific macro from the standard library, for instance [`is_x86_feature_detected`] or [`is_aarch64_feature_detected`]. > [!NOTE] > `rustc` has a default set of features enabled for each target and CPU. The CPU may be chosen with the [`-C target-cpu`] flag. Individual features may be enabled or disabled for an entire crate with the [`-C target-feature`] flag. From 4ec04bcd06e9fe235653d0767dcb94130b345eda Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Wed, 20 Aug 2025 18:21:11 +0000 Subject: [PATCH 02/53] Revise `s390x` codegen text --- src/attributes/codegen.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/attributes/codegen.md b/src/attributes/codegen.md index bb446130..e8afe711 100644 --- a/src/attributes/codegen.md +++ b/src/attributes/codegen.md @@ -509,9 +509,9 @@ Feature | Implicitly Enables | Description r[attributes.codegen.target_feature.s390x] #### `s390x` -On this platform the usage of `#[target_feature]` functions follows the [above restrictions][attributes.codegen.target_feature.safety-restrictions]. +On `s390x` targets, use of functions with the `#[target_feature]` attribute follows the [above restrictions][attributes.codegen.target_feature.safety-restrictions]. -Further documentation on these features can be found in the "Additions to z/Architecture" section of Chapter 1 of the [Principles of Operation]. +Further documentation on these features can be found in the "Additions to z/Architecture" section of Chapter 1 of the *[z/Architecture Principles of Operation]*. Feature | Implicitly Enables | Description ---------------------------------------|---------------------------------------|--------------------- @@ -528,7 +528,7 @@ Feature | Implicitly Enables | `miscellaneous-extensions-3` | | miscellaneous extensions 3 `miscellaneous-extensions-4` | | miscellaneous extensions 4 -[Principles of Operation]: https://publibfp.dhe.ibm.com/epubs/pdf/a227832d.pdf +[z/Architecture Principles of Operation]: https://publibfp.dhe.ibm.com/epubs/pdf/a227832d.pdf r[attributes.codegen.target_feature.info] ### Additional information From ea013b5badf78ea16bf23edf58483c30fe1da1ce Mon Sep 17 00:00:00 2001 From: AudaciousAxiom <179637270+AudaciousAxiom@users.noreply.github.com> Date: Sat, 25 Oct 2025 10:49:46 +0200 Subject: [PATCH 03/53] feat: guarantee the binary representation of `isize` explicitly --- src/types/numeric.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/numeric.md b/src/types/numeric.md index 73c61991..5b796e41 100644 --- a/src/types/numeric.md +++ b/src/types/numeric.md @@ -44,7 +44,7 @@ platform's pointer type. It can represent every memory address in the process. > For more information, see the documentation for [type cast expressions], [`std::ptr`], and [provenance][std::ptr#provenance] in particular. r[type.numeric.int.size.isize] -The `isize` type is a signed integer type with the same number of bits as the +The `isize` type is a signed two's complement integer type with the same number of bits as the platform's pointer type. The theoretical upper bound on object and array size is the maximum `isize` value. This ensures that `isize` can be used to calculate differences between pointers into an object or array and can address every byte From d8d11e225413a3d494222ce57b655fd61fd36bb6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Oct 2025 12:00:59 +0100 Subject: [PATCH 04/53] add 'system' to variadic ABIs --- src/items/external-blocks.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/items/external-blocks.md b/src/items/external-blocks.md index c360189b..b3a1d2fe 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -124,7 +124,7 @@ r[items.extern.abi.c] * `unsafe extern "C"` --- The "C" ABI matches the default ABI chosen by the dominant C compiler for the target. r[items.extern.abi.system] -* `unsafe extern "system"` --- This is equivalent to `extern "C"` except on Windows x86_32 where it is equivalent to `"stdcall"`. +* `unsafe extern "system"` --- This is equivalent to `extern "C"` except on Windows x86_32 where it is equivalent to `"stdcall"` for non-variadic functions, and equivalent to `"C"` for variadic functions. > [!NOTE] > As the correct underlying ABI on Windows is target-specific, it's best to use `extern "system"` when attempting to link Windows API functions that don't use an explicitly defined ABI. @@ -257,6 +257,7 @@ Variadic parameters can only be specified within `extern` blocks with the follow - `"C"` - `"cdecl"` - `"efiapi"` +- `"system"` - `"sysv64"` - `"win64"` From 07be87efda16ceeeae3c3bc8e1da767af5dfc780 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 10 Nov 2025 10:24:09 +0200 Subject: [PATCH 05/53] const_eval.md: be more clear where link leads to Having just "Struct" as the link makes it look like the target is about structs and not just struct expressions --- src/const_eval.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/const_eval.md b/src/const_eval.md index 7cb85dc2..04146adf 100644 --- a/src/const_eval.md +++ b/src/const_eval.md @@ -55,7 +55,7 @@ r[const-eval.const-expr.array] * [Array expressions]. r[const-eval.const-expr.constructor] -* [Struct] expressions. +* [Struct expressions]. r[const-eval.const-expr.block] * [Block expressions], including `unsafe` and `const` blocks. @@ -332,7 +332,7 @@ The types of a const function's parameters and return type are restricted to tho [range expressions]: expressions/range-expr.md [slice]: types/slice.md [statics]: items/static-items.md -[struct]: expressions/struct-expr.md +[Struct expressions]: expressions/struct-expr.md [temporary lifetime extension]: destructors.scope.lifetime-extension [tuple enum variant]: items/enumerations.md [tuple expressions]: expressions/tuple-expr.md From 7e7ae6cb0ab1d53818b34b91dafc9851f6f2fca0 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 31 May 2025 13:58:15 -0700 Subject: [PATCH 06/53] Unwrap the no_std attribute --- src/names/preludes.md | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/names/preludes.md b/src/names/preludes.md index 97c1ba77..c94b5bc2 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -80,15 +80,10 @@ r[names.preludes.extern.no_std] ### The `no_std` attribute r[names.preludes.extern.no_std.intro] -By default, the standard library is automatically included in the crate root -module. The [`std`] crate is added to the root, along with an implicit -[`macro_use` attribute] pulling in all macros exported from `std` into the -[`macro_use` prelude]. Both [`core`] and [`std`] are added to the [extern -prelude]. +By default, the standard library is automatically included in the crate root module. The [`std`] crate is added to the root, along with an implicit [`macro_use` attribute] pulling in all macros exported from `std` into the [`macro_use` prelude]. Both [`core`] and [`std`] are added to the [extern prelude]. r[names.preludes.extern.no_std.allowed-positions] -The *`no_std` [attribute]* may be applied at the crate level to prevent the -[`std`] crate from being automatically added into scope. +The *`no_std` [attribute]* may be applied at the crate level to prevent the [`std`] crate from being automatically added into scope. It does three things: @@ -97,8 +92,7 @@ r[names.preludes.extern.no_std.extern] r[names.preludes.extern.no_std.module] * Affects which module is used to make up the [standard library prelude] (as described above). r[names.preludes.extern.no_std.core] -* Injects the [`core`] crate into the crate root instead of [`std`], and pulls - in all macros exported from `core` in the [`macro_use` prelude]. +* Injects the [`core`] crate into the crate root instead of [`std`], and pulls in all macros exported from `core` in the [`macro_use` prelude]. > [!NOTE] > Using the core prelude over the standard prelude is useful when either the crate is targeting a platform that does not support the standard library or is purposefully not using the capabilities of the standard library. Those capabilities are mainly dynamic memory allocation (e.g. `Box` and `Vec`) and file and network capabilities (e.g. `std::fs` and `std::io`). From a5a160db984dc35c63110a74a1917b33d5536927 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 31 May 2025 14:01:40 -0700 Subject: [PATCH 07/53] Add names.preludes.extern.no_std.syntax --- src/names/preludes.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/names/preludes.md b/src/names/preludes.md index c94b5bc2..0d44cdf4 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -82,6 +82,9 @@ r[names.preludes.extern.no_std] r[names.preludes.extern.no_std.intro] By default, the standard library is automatically included in the crate root module. The [`std`] crate is added to the root, along with an implicit [`macro_use` attribute] pulling in all macros exported from `std` into the [`macro_use` prelude]. Both [`core`] and [`std`] are added to the [extern prelude]. +r[names.preludes.extern.no_std.syntax] +The `no_std` attribute uses the [MetaWord] syntax and thus does not take any inputs. + r[names.preludes.extern.no_std.allowed-positions] The *`no_std` [attribute]* may be applied at the crate level to prevent the [`std`] crate from being automatically added into scope. From acb4347d8e95f015949106d534051b0a65400128 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 31 May 2025 15:31:05 -0700 Subject: [PATCH 08/53] Remove duplicate link definition --- src/names/preludes.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/names/preludes.md b/src/names/preludes.md index 0d44cdf4..daa6b30e 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -157,7 +157,6 @@ r[names.preludes.no_implicit_prelude.edition2018] [`macro_use` attribute]: ../macros-by-example.md#the-macro_use-attribute [`macro_use` prelude]: #macro_use-prelude [`no_std` attribute]: #the-no_std-attribute -[`no_std` attribute]: #the-no_std-attribute [attribute]: ../attributes.md [Boolean type]: ../types/boolean.md [Built-in attributes]: ../attributes.md#built-in-attributes-index From dea61cb30e0819012faf51736509582c7a6aceb9 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 31 May 2025 15:32:19 -0700 Subject: [PATCH 09/53] Add example to no_std intro --- src/names/preludes.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/names/preludes.md b/src/names/preludes.md index daa6b30e..87faf24c 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -82,6 +82,12 @@ r[names.preludes.extern.no_std] r[names.preludes.extern.no_std.intro] By default, the standard library is automatically included in the crate root module. The [`std`] crate is added to the root, along with an implicit [`macro_use` attribute] pulling in all macros exported from `std` into the [`macro_use` prelude]. Both [`core`] and [`std`] are added to the [extern prelude]. +> [!EXAMPLE] +> +> ```rust,ignore +> #![no_std] +> ``` + r[names.preludes.extern.no_std.syntax] The `no_std` attribute uses the [MetaWord] syntax and thus does not take any inputs. From 4f50d5234e22c4cca071f246608916dc964be528 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 31 May 2025 15:33:00 -0700 Subject: [PATCH 10/53] Move note and warning to the intro These don't really belong where they are, and are just generally helpful things about the attribute. --- src/names/preludes.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/names/preludes.md b/src/names/preludes.md index 87faf24c..17549f83 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -88,6 +88,12 @@ By default, the standard library is automatically included in the crate root mod > #![no_std] > ``` +> [!NOTE] +> Using `no_std` is useful when either the crate is targeting a platform that does not support the standard library or is purposefully not using the capabilities of the standard library. Those capabilities are mainly dynamic memory allocation (e.g. `Box` and `Vec`) and file and network capabilities (e.g. `std::fs` and `std::io`). + +> [!WARNING] +> Using `no_std` does not prevent the standard library from being linked in. It is still valid to put `extern crate std;` into the crate and dependencies can also link it in. + r[names.preludes.extern.no_std.syntax] The `no_std` attribute uses the [MetaWord] syntax and thus does not take any inputs. @@ -103,11 +109,7 @@ r[names.preludes.extern.no_std.module] r[names.preludes.extern.no_std.core] * Injects the [`core`] crate into the crate root instead of [`std`], and pulls in all macros exported from `core` in the [`macro_use` prelude]. -> [!NOTE] -> Using the core prelude over the standard prelude is useful when either the crate is targeting a platform that does not support the standard library or is purposefully not using the capabilities of the standard library. Those capabilities are mainly dynamic memory allocation (e.g. `Box` and `Vec`) and file and network capabilities (e.g. `std::fs` and `std::io`). -> [!WARNING] -> Using `no_std` does not prevent the standard library from being linked in. It is still valid to put `extern crate std;` into the crate and dependencies can also link it in. r[names.preludes.lang] ## Language prelude From e464933c11bfe9ea02b09ae07791bb52242f774b Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 31 May 2025 15:37:55 -0700 Subject: [PATCH 11/53] Rewrite no_std The current text was a little bit of a mess and had some subtle inaccuracies. This reworks so that the intro follows the template, and just generally introduces the attribute. `allowed-positions` now just specifies the allowed positions. I reworked the behavior changes caused by no_std into proper separate rules. `std` is not injected into the crate root anymore starting with edition 2018. --- src/names/preludes.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/names/preludes.md b/src/names/preludes.md index 17549f83..3c38f7b3 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -80,7 +80,7 @@ r[names.preludes.extern.no_std] ### The `no_std` attribute r[names.preludes.extern.no_std.intro] -By default, the standard library is automatically included in the crate root module. The [`std`] crate is added to the root, along with an implicit [`macro_use` attribute] pulling in all macros exported from `std` into the [`macro_use` prelude]. Both [`core`] and [`std`] are added to the [extern prelude]. +The *`no_std` [attribute][attributes]* is used to prevent the automatic linking of the [`std`] crate, deferring to [`core`] instead. > [!EXAMPLE] > @@ -98,18 +98,16 @@ r[names.preludes.extern.no_std.syntax] The `no_std` attribute uses the [MetaWord] syntax and thus does not take any inputs. r[names.preludes.extern.no_std.allowed-positions] -The *`no_std` [attribute]* may be applied at the crate level to prevent the [`std`] crate from being automatically added into scope. +The `no_std` attribute may only be applied to the crate root. -It does three things: -r[names.preludes.extern.no_std.extern] -* Prevents `std` from being added to the [extern prelude](#extern-prelude). r[names.preludes.extern.no_std.module] -* Affects which module is used to make up the [standard library prelude] (as described above). -r[names.preludes.extern.no_std.core] -* Injects the [`core`] crate into the crate root instead of [`std`], and pulls in all macros exported from `core` in the [`macro_use` prelude]. +The `no_std` attribute changes the [standard library prelude] to use the `core` prelude instead of `std`. +r[names.preludes.extern.no_std.inject] +By default, the [`std`] crate is injected into the [extern prelude], and all macros exported from `std` are added to the [`macro_use` prelude]. +If the `no_std` attribute is specified, then the [`core`] crate is used instead of `std`, and similarly all macros exported from `core` are placed into the [`macro_use` prelude]. r[names.preludes.lang] ## Language prelude From d6e0a9fc9e4db338cfc496c1a8089f11fc3909e8 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 31 May 2025 15:41:28 -0700 Subject: [PATCH 12/53] Add a rule for `std` injection in edition 2018 I do not know how this was missing, I've looked at it a million times. I feel like I was maybe missing something, but I really can't find anything that directly refers to this, nor can I find any open issues. I believe this is now done with this relatively subtle bit: https://github.com/rust-lang/rust/blob/4d08223c054cf5a56d9761ca925fd46ffebe7115/compiler/rustc_builtin_macros/src/standard_library_imports.rs#L42 In the past it used to use a different approach of emulating `extern crate std as _;`: https://github.com/rust-lang/rust/blob/c8cf9f5a025bb475804b5a90f54aca310b952526/src/libsyntax_ext/standard_library_imports.rs#L42-L46 --- src/names/preludes.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/names/preludes.md b/src/names/preludes.md index 3c38f7b3..628e5fb2 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -109,6 +109,10 @@ By default, the [`std`] crate is injected into the [extern prelude], and all mac If the `no_std` attribute is specified, then the [`core`] crate is used instead of `std`, and similarly all macros exported from `core` are placed into the [`macro_use` prelude]. +r[names.preludes.extern.no_std.edition2018] +> [!EDITION-2018] +> Before the 2018 edition, `std` is also injected into the crate root. `core` is injected instead of `std` if `no_std` is specified. Starting with the 2018 edition, these are not injected into the crate root. + r[names.preludes.lang] ## Language prelude From f7d9d8442c8be8c82501ba30e78d4c3a640f62dd Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 31 May 2025 15:41:36 -0700 Subject: [PATCH 13/53] Add names.preludes.extern.no_std.duplicates --- src/names/preludes.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/names/preludes.md b/src/names/preludes.md index 628e5fb2..188a67e3 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -100,6 +100,11 @@ The `no_std` attribute uses the [MetaWord] syntax and thus does not take any inp r[names.preludes.extern.no_std.allowed-positions] The `no_std` attribute may only be applied to the crate root. +r[names.preludes.extern.no_std.duplicates] +Duplicate instances of the `no_std` attribute have no effect. + +> [!NOTE] +> `rustc` currently warns on subsequent duplicate `no_std` attributes. r[names.preludes.extern.no_std.module] The `no_std` attribute changes the [standard library prelude] to use the `core` prelude instead of `std`. From 97ea13093dca26dc9af49dbfb7830b3d2c2800af Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 22 Sep 2025 13:22:46 -0700 Subject: [PATCH 14/53] Minor update of `no_std` More closely align with the template, and some minor word tweaks. --- src/names/preludes.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/names/preludes.md b/src/names/preludes.md index 188a67e3..d8204f27 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -76,6 +76,7 @@ See https://github.com/rust-lang/rust/issues/57288 for more about the alloc/test limitation. --> + r[names.preludes.extern.no_std] ### The `no_std` attribute @@ -95,16 +96,16 @@ The *`no_std` [attribute][attributes]* is used to prevent the automatic linking > Using `no_std` does not prevent the standard library from being linked in. It is still valid to put `extern crate std;` into the crate and dependencies can also link it in. r[names.preludes.extern.no_std.syntax] -The `no_std` attribute uses the [MetaWord] syntax and thus does not take any inputs. +The `no_std` attribute uses the [MetaWord] syntax. r[names.preludes.extern.no_std.allowed-positions] The `no_std` attribute may only be applied to the crate root. r[names.preludes.extern.no_std.duplicates] -Duplicate instances of the `no_std` attribute have no effect. +The `no_std` attribute may be used any number of times on a form. > [!NOTE] -> `rustc` currently warns on subsequent duplicate `no_std` attributes. +> `rustc` lints against any use following the first. r[names.preludes.extern.no_std.module] The `no_std` attribute changes the [standard library prelude] to use the `core` prelude instead of `std`. From 9d79e59adaf149a333709bf075ff71a08bb9f8ea Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Sun, 9 Nov 2025 01:56:38 +0000 Subject: [PATCH 15/53] Align `no_std` intro language better and reword We had said here that the `no_std` attribute is used to "prevent the automatic linking of the std crate", but then further down we say, "using `no_std` does not prevent the standard library from being linked in". The important distinction here is the word "automatically", but that gets a bit lost due to reusing the "prevent" phrasing. Probably "prevent" is just too strong a word to use when what we're really saying is that we're causing something to not happen automatically. Let's make that more clear and increase sentence parallelism. --- src/names/preludes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/names/preludes.md b/src/names/preludes.md index d8204f27..a8efb837 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -81,7 +81,7 @@ r[names.preludes.extern.no_std] ### The `no_std` attribute r[names.preludes.extern.no_std.intro] -The *`no_std` [attribute][attributes]* is used to prevent the automatic linking of the [`std`] crate, deferring to [`core`] instead. +The *`no_std` [attribute][attributes]* causes the [`std`] crate to not be linked automatically, deferring to the [`core`] crate instead. > [!EXAMPLE] > From ae893d6e01e2f581c0999b3adebeffbcf423da91 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Tue, 11 Nov 2025 21:28:35 +0000 Subject: [PATCH 16/53] Revise `no_std` text to increase parallelism Some sentences here could be improved with more sentence parallelism and a bit of reordering, so let's do that. --- src/names/preludes.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/names/preludes.md b/src/names/preludes.md index a8efb837..000afa1e 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -108,16 +108,16 @@ The `no_std` attribute may be used any number of times on a form. > `rustc` lints against any use following the first. r[names.preludes.extern.no_std.module] -The `no_std` attribute changes the [standard library prelude] to use the `core` prelude instead of `std`. +The `no_std` attribute changes the [standard library prelude] to use the `core` prelude instead of the `std` prelude. r[names.preludes.extern.no_std.inject] By default, the [`std`] crate is injected into the [extern prelude], and all macros exported from `std` are added to the [`macro_use` prelude]. -If the `no_std` attribute is specified, then the [`core`] crate is used instead of `std`, and similarly all macros exported from `core` are placed into the [`macro_use` prelude]. +If the `no_std` attribute is specified, then the [`core`] crate is used instead of the `std` crate, and similarly all macros exported from `core` are placed into the [`macro_use` prelude]. r[names.preludes.extern.no_std.edition2018] > [!EDITION-2018] -> Before the 2018 edition, `std` is also injected into the crate root. `core` is injected instead of `std` if `no_std` is specified. Starting with the 2018 edition, these are not injected into the crate root. +> Before the 2018 edition, `std` is injected into the crate root by default. If `no_std` is specified, `core` is injected instead. Starting with the 2018 edition, regardless of `no_std` being specified, neither is injected into the crate root. r[names.preludes.lang] ## Language prelude From 8d7877ec0d388c065d2a8b3b109191300a116c02 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Tue, 11 Nov 2025 21:51:02 +0000 Subject: [PATCH 17/53] Revise `no_std` intro WRT the preludes We had text in the intro about "deferring to the core crate instead", but it may not have been sufficiently clear what we mean exactly by that. Let's talk specifically about how `no_std` causes us to use the `core` crate for the standard library prelude and for the `macro_use` prelude. --- src/names/preludes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/names/preludes.md b/src/names/preludes.md index 000afa1e..321a8a08 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -81,7 +81,7 @@ r[names.preludes.extern.no_std] ### The `no_std` attribute r[names.preludes.extern.no_std.intro] -The *`no_std` [attribute][attributes]* causes the [`std`] crate to not be linked automatically, deferring to the [`core`] crate instead. +The *`no_std` [attribute][attributes]* causes the [`std`] crate to not be linked automatically, the [standard library prelude] to instead use the `core` prelude, and the [`macro_use` prelude] to instead use the macros exported from the `core` crate. > [!EXAMPLE] > @@ -183,7 +183,7 @@ r[names.preludes.no_implicit_prelude.edition2018] [Machine-dependent integer types]: ../types/numeric.md#machine-dependent-integer-types [Macro namespace]: namespaces.md [name resolution]: name-resolution.md -[Standard library prelude]: #standard-library-prelude +[standard library prelude]: names.preludes.std [Textual types]: ../types/textual.md [tool attributes]: ../attributes.md#tool-attributes [Tool prelude]: #tool-prelude From b15b601de6441282e61c314251dff28dd5b3de4f Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Tue, 11 Nov 2025 22:19:16 +0000 Subject: [PATCH 18/53] Revise `no_std` warning We want to highlight how using `no_std` doesn't prevent `std` from being linked. Let's revise and elaborate this text for clarity. --- src/names/preludes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/names/preludes.md b/src/names/preludes.md index 321a8a08..bca08f75 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -93,7 +93,7 @@ The *`no_std` [attribute][attributes]* causes the [`std`] crate to not be linked > Using `no_std` is useful when either the crate is targeting a platform that does not support the standard library or is purposefully not using the capabilities of the standard library. Those capabilities are mainly dynamic memory allocation (e.g. `Box` and `Vec`) and file and network capabilities (e.g. `std::fs` and `std::io`). > [!WARNING] -> Using `no_std` does not prevent the standard library from being linked in. It is still valid to put `extern crate std;` into the crate and dependencies can also link it in. +> Using `no_std` does not prevent the standard library from being linked. It is still valid to write `extern crate std` in the crate or in one of its dependencies; this will cause the compiler to link the `std` crate into the program. r[names.preludes.extern.no_std.syntax] The `no_std` attribute uses the [MetaWord] syntax. From 97f3e33bb42c00b974ca2bc1272389e05f29be32 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Tue, 11 Nov 2025 22:25:25 +0000 Subject: [PATCH 19/53] Revise `no_std` text WRT `macro_use` The text here could be read in such a way as to imply that `no_std` affected whether or not `core` was added to the extern prelude, but that isn't the case. Let's make it clear that this section is about what is added to the `macro_use` prelude and speak to that directly. --- src/names/preludes.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/names/preludes.md b/src/names/preludes.md index bca08f75..63d08af1 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -110,10 +110,8 @@ The `no_std` attribute may be used any number of times on a form. r[names.preludes.extern.no_std.module] The `no_std` attribute changes the [standard library prelude] to use the `core` prelude instead of the `std` prelude. -r[names.preludes.extern.no_std.inject] -By default, the [`std`] crate is injected into the [extern prelude], and all macros exported from `std` are added to the [`macro_use` prelude]. - -If the `no_std` attribute is specified, then the [`core`] crate is used instead of the `std` crate, and similarly all macros exported from `core` are placed into the [`macro_use` prelude]. +r[names.preludes.extern.no_std.macro_use] +By default, all macros exported from the `std` crate are added to the [`macro_use` prelude]. If the `no_std` attribute is specified, then all macros exported from the `core` crate are placed into the [`macro_use` prelude] instead. r[names.preludes.extern.no_std.edition2018] > [!EDITION-2018] From 2f10103ec00a15b3b4a1ff83bb108ce3b45e8078 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 31 May 2025 15:43:05 -0700 Subject: [PATCH 20/53] Unwrap no_implicit_prelude --- src/names/preludes.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/names/preludes.md b/src/names/preludes.md index 63d08af1..0d6ce56e 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -155,10 +155,7 @@ r[names.preludes.no_implicit_prelude] ## The `no_implicit_prelude` attribute r[names.preludes.no_implicit_prelude.intro] -The *`no_implicit_prelude` [attribute]* may be applied at the crate level or -on a module to indicate that it should not automatically bring the [standard -library prelude], [extern prelude], or [tool prelude] into scope for that -module or any of its descendants. +The *`no_implicit_prelude` [attribute]* may be applied at the crate level or on a module to indicate that it should not automatically bring the [standard library prelude], [extern prelude], or [tool prelude] into scope for that module or any of its descendants. r[names.preludes.no_implicit_prelude.lang] This attribute does not affect the [language prelude]. From 0fe507dddf07517a812bcab77029a6cc8f930641 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 31 May 2025 15:54:34 -0700 Subject: [PATCH 21/53] Add an example for no_implicit_prelude --- src/names/preludes.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/names/preludes.md b/src/names/preludes.md index 0d6ce56e..364724fd 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -157,6 +157,18 @@ r[names.preludes.no_implicit_prelude] r[names.preludes.no_implicit_prelude.intro] The *`no_implicit_prelude` [attribute]* may be applied at the crate level or on a module to indicate that it should not automatically bring the [standard library prelude], [extern prelude], or [tool prelude] into scope for that module or any of its descendants. +> [!EXAMPLE] +> ```rust +> // It can be applied to the crate root to apply to all modules. +> #![no_implicit_prelude] +> +> // Or it can be applied to a module to only affect that module or any of its descendants. +> #[no_implicit_prelude] +> mod example { +> // ... +> } +> ``` + r[names.preludes.no_implicit_prelude.lang] This attribute does not affect the [language prelude]. From b5e3e2680af1432f166a8a472d070bd03e4c2bf1 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 31 May 2025 15:55:11 -0700 Subject: [PATCH 22/53] Add explicit rules for no_implicit_prelude This is to follow the attribute template. --- src/names/preludes.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/names/preludes.md b/src/names/preludes.md index 364724fd..db5eedc8 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -169,6 +169,21 @@ The *`no_implicit_prelude` [attribute]* may be applied at the crate level or on > } > ``` +r[names.preludes.no_implicit_prelude.syntax] +The `no_implicit_prelude` attribute uses the [MetaWord] syntax and thus does not take any inputs. + +r[names.preludes.no_implicit_prelude.allowed-positions] +The `no_implicit_prelude` attribute may only be applied to the crate level or a module. + +> [!NOTE] +> `rustc` currently warns in other positions, but this may be rejected in the future. + +r[names.preludes.no_implicit_prelude.duplicates] +Duplicate instances of the `no_implicit_prelude` attribute have no effect. + +> [!NOTE] +> `rustc` currently warns on subsequent duplicate `no_implicit_prelude` attributes. + r[names.preludes.no_implicit_prelude.lang] This attribute does not affect the [language prelude]. From a2b8f937e4f83a62316efb2815f0be95c91326f5 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 31 May 2025 15:56:23 -0700 Subject: [PATCH 23/53] Rewrite no_implicit_prelude to move to a specific rule This rewrites the intro to be a little more general, and moves the description of the behavior to a specific rule that can be cited. --- src/names/preludes.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/names/preludes.md b/src/names/preludes.md index db5eedc8..4f2ae167 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -155,7 +155,7 @@ r[names.preludes.no_implicit_prelude] ## The `no_implicit_prelude` attribute r[names.preludes.no_implicit_prelude.intro] -The *`no_implicit_prelude` [attribute]* may be applied at the crate level or on a module to indicate that it should not automatically bring the [standard library prelude], [extern prelude], or [tool prelude] into scope for that module or any of its descendants. +The *`no_implicit_prelude` [attribute]* is used to prevent implicit preludes from being brought into scope. > [!EXAMPLE] > ```rust @@ -184,6 +184,9 @@ Duplicate instances of the `no_implicit_prelude` attribute have no effect. > [!NOTE] > `rustc` currently warns on subsequent duplicate `no_implicit_prelude` attributes. +r[names.preludes.no_implicit_prelude.excluded-preludes] +The `no_implicit_prelude` attribute prevents the [standard library prelude], [extern prelude], and the [tool prelude] from being brought into scope for the module or any of its descendants. + r[names.preludes.no_implicit_prelude.lang] This attribute does not affect the [language prelude]. From 0ed80f7bc2df8db56a7300ebbb943fbdaf5e3e90 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 31 May 2025 15:57:08 -0700 Subject: [PATCH 24/53] Be explicit in the wording here --- src/names/preludes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/names/preludes.md b/src/names/preludes.md index 4f2ae167..1fc4fb10 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -188,7 +188,7 @@ r[names.preludes.no_implicit_prelude.excluded-preludes] The `no_implicit_prelude` attribute prevents the [standard library prelude], [extern prelude], and the [tool prelude] from being brought into scope for the module or any of its descendants. r[names.preludes.no_implicit_prelude.lang] -This attribute does not affect the [language prelude]. +The `no_implicit_prelude` attribute does not affect the [language prelude]. r[names.preludes.no_implicit_prelude.edition2018] > [!EDITION-2018] From 70fa8bd0fc196dcac2481bbf55d738184112e22a Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 22 Sep 2025 13:24:41 -0700 Subject: [PATCH 25/53] Minor update of `no_implicit_prelude` More closely align with the template, and some minor word tweaks. --- src/names/preludes.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/names/preludes.md b/src/names/preludes.md index 1fc4fb10..4351d162 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -151,6 +151,7 @@ r[names.preludes.tool.intro] The tool prelude includes tool names for external tools in the [type namespace]. See the [tool attributes] section for more details. + r[names.preludes.no_implicit_prelude] ## The `no_implicit_prelude` attribute @@ -170,19 +171,19 @@ The *`no_implicit_prelude` [attribute]* is used to prevent implicit preludes fro > ``` r[names.preludes.no_implicit_prelude.syntax] -The `no_implicit_prelude` attribute uses the [MetaWord] syntax and thus does not take any inputs. +The `no_implicit_prelude` attribute uses the [MetaWord] syntax. r[names.preludes.no_implicit_prelude.allowed-positions] The `no_implicit_prelude` attribute may only be applied to the crate level or a module. > [!NOTE] -> `rustc` currently warns in other positions, but this may be rejected in the future. +> `rustc` ignores use in other positions but lints against it. This may become an error in the future. r[names.preludes.no_implicit_prelude.duplicates] -Duplicate instances of the `no_implicit_prelude` attribute have no effect. +The `no_implicit_prelude` attribute may be used any number of times on a form. > [!NOTE] -> `rustc` currently warns on subsequent duplicate `no_implicit_prelude` attributes. +> `rustc` lints against any use following the first. r[names.preludes.no_implicit_prelude.excluded-preludes] The `no_implicit_prelude` attribute prevents the [standard library prelude], [extern prelude], and the [tool prelude] from being brought into scope for the module or any of its descendants. From 9ca5c57e2535a770e399ef2a9f154df07c58506e Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 8 Nov 2025 19:05:50 -0800 Subject: [PATCH 26/53] Fix no_implicit_prelude to document the *current* edition in the main text This follows our style guide where the main text should document the current edition, and the edition blocks should note the differences to previous editions. --- src/names/preludes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/names/preludes.md b/src/names/preludes.md index 4351d162..d97aa53d 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -186,7 +186,7 @@ The `no_implicit_prelude` attribute may be used any number of times on a form. > `rustc` lints against any use following the first. r[names.preludes.no_implicit_prelude.excluded-preludes] -The `no_implicit_prelude` attribute prevents the [standard library prelude], [extern prelude], and the [tool prelude] from being brought into scope for the module or any of its descendants. +The `no_implicit_prelude` attribute prevents the [standard library prelude], [extern prelude], [`macro_use` prelude], and the [tool prelude] from being brought into scope for the module or any of its descendants. r[names.preludes.no_implicit_prelude.lang] The `no_implicit_prelude` attribute does not affect the [language prelude]. From 69707f462a8f20b39d919087b2a3f34b9b3c4959 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Tue, 11 Nov 2025 23:19:00 +0000 Subject: [PATCH 27/53] Wrap and reword `no_implicit_prelude` code comments One of the comments in the example stretched out a bit far; let's wrap that and reword the comments in the example for clarity and flow. --- src/names/preludes.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/names/preludes.md b/src/names/preludes.md index d97aa53d..e2bcda3d 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -160,10 +160,12 @@ The *`no_implicit_prelude` [attribute]* is used to prevent implicit preludes fro > [!EXAMPLE] > ```rust -> // It can be applied to the crate root to apply to all modules. +> // The attribute can be applied to the crate root to affect +> // all modules. > #![no_implicit_prelude] > -> // Or it can be applied to a module to only affect that module or any of its descendants. +> // Or it can be applied to a module to only affect that module +> // and its descendants. > #[no_implicit_prelude] > mod example { > // ... From 60b75862e1541dc79e6d99d76e05f8b6ca035fa2 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Tue, 11 Nov 2025 23:21:51 +0000 Subject: [PATCH 28/53] Revise `no_implicit_prelude.allowed-positions` text It's more clear to say either that something can be applied "at the crate level" or "to the crate" than "to the crate level". Let's pick the latter and adjust for better grammatical parallelism. --- src/names/preludes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/names/preludes.md b/src/names/preludes.md index e2bcda3d..bdc92096 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -176,7 +176,7 @@ r[names.preludes.no_implicit_prelude.syntax] The `no_implicit_prelude` attribute uses the [MetaWord] syntax. r[names.preludes.no_implicit_prelude.allowed-positions] -The `no_implicit_prelude` attribute may only be applied to the crate level or a module. +The `no_implicit_prelude` attribute may only be applied to the crate or to a module. > [!NOTE] > `rustc` ignores use in other positions but lints against it. This may become an error in the future. From ee8065669e8f91643fa8e4f502220efbb49c2501 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Tue, 11 Nov 2025 23:24:40 +0000 Subject: [PATCH 29/53] Revise `no_implicit_prelude.excluded-preludes` text Rather than saying "or any of its descendants", we can say "and its descendants" to express the same thing more concisely. Let's do that. --- src/names/preludes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/names/preludes.md b/src/names/preludes.md index bdc92096..65a3700b 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -188,7 +188,7 @@ The `no_implicit_prelude` attribute may be used any number of times on a form. > `rustc` lints against any use following the first. r[names.preludes.no_implicit_prelude.excluded-preludes] -The `no_implicit_prelude` attribute prevents the [standard library prelude], [extern prelude], [`macro_use` prelude], and the [tool prelude] from being brought into scope for the module or any of its descendants. +The `no_implicit_prelude` attribute prevents the [standard library prelude], [extern prelude], [`macro_use` prelude], and the [tool prelude] from being brought into scope for the module and its descendants. r[names.preludes.no_implicit_prelude.lang] The `no_implicit_prelude` attribute does not affect the [language prelude]. From a5a9f03bf8f9da3d5241881f42870c883eb315a8 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Tue, 11 Nov 2025 23:26:43 +0000 Subject: [PATCH 30/53] Bring `no_implicit_prelude.edition2018` into present The remainder of this note is in the present tense, so saying that something "will" happen starting in the 2018 edition makes it sound as though that will happen in the future, even if what we mean is that the compiler "will" do it in the 2018 edition and later. Let's use the present tense here in emphatic form to distinguish this, and let's expand "it" for clarity. --- src/names/preludes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/names/preludes.md b/src/names/preludes.md index 65a3700b..3a2c3ff1 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -195,7 +195,7 @@ The `no_implicit_prelude` attribute does not affect the [language prelude]. r[names.preludes.no_implicit_prelude.edition2018] > [!EDITION-2018] -> In the 2015 edition, the `no_implicit_prelude` attribute does not affect the [`macro_use` prelude], and all macros exported from the standard library are still included in the `macro_use` prelude. Starting in the 2018 edition, it will remove the `macro_use` prelude. +> In the 2015 edition, the `no_implicit_prelude` attribute does not affect the [`macro_use` prelude], and all macros exported from the standard library are still included in the `macro_use` prelude. Starting in the 2018 edition, the attribute does remove the `macro_use` prelude. [`extern crate`]: ../items/extern-crates.md [`macro_use` attribute]: ../macros-by-example.md#the-macro_use-attribute From 845ec9674389067ca1fcc70b80a8087acc1cfe4e Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sat, 25 Oct 2025 00:23:20 +0200 Subject: [PATCH 31/53] document `cfg` conditions on inline assembly templates and operands --- src/attributes.md | 2 ++ src/inline-assembly.md | 40 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/attributes.md b/src/attributes.md index 79b98988..376c6977 100644 --- a/src/attributes.md +++ b/src/attributes.md @@ -107,6 +107,7 @@ Attributes may be applied to many forms in the language: * [Function][functions], [closure] and [function pointer] parameters accept outer attributes. This includes attributes on variadic parameters denoted with `...` in function pointers and [external blocks][variadic functions]. +* [Inline assembly] template strings and operands accept outer attributes. r[attributes.meta] ## Meta item attribute syntax @@ -409,3 +410,4 @@ The following is an index of all built-in attributes. [variadic functions]: items/external-blocks.html#variadic-functions [`diagnostic::on_unimplemented`]: attributes/diagnostics.md#the-diagnosticon_unimplemented-attribute [`diagnostic::do_not_recommend`]: attributes/diagnostics.md#the-diagnosticdo_not_recommend-attribute +[Inline assembly]: inline-assembly.md diff --git a/src/inline-assembly.md b/src/inline-assembly.md index 41bff252..caa6148c 100644 --- a/src/inline-assembly.md +++ b/src/inline-assembly.md @@ -49,15 +49,19 @@ r[asm.syntax] The following grammar specifies the arguments that can be passed to the `asm!`, `global_asm!` and `naked_asm!` macros. ```grammar,assembly -@root AsmArgs -> FormatString (`,` FormatString)* (`,` AsmOperand)* `,`? +@root AsmArgs -> AsmAttrFormatString (`,` AsmAttrFormatString)* (`,` AsmAttrOperand)* `,`? FormatString -> STRING_LITERAL | RAW_STRING_LITERAL | MacroInvocation +AsmAttrFormatString -> (OuterAttribute)* FormatString + AsmOperand -> ClobberAbi | AsmOptions | RegOperand +AsmAttrOperand -> (OuterAttribute)* AsmOperand + ClobberAbi -> `clobber_abi` `(` Abi (`,` Abi)* `,`? `)` AsmOptions -> @@ -266,6 +270,40 @@ Further constraints on the directives used by inline assembly are indicated by [ [format-syntax]: std::fmt#syntax [rfc-2795]: https://github.com/rust-lang/rfcs/pull/2795 +r[asm.attributes] +## Attributes + +r[asm.attributes.supported-attributes] +Only the [`cfg`] and [`cfg_attr`] attributes are accepted semantically on inline assembly template strings and operands. Other attributes are parsed, but rejected when the assembly macro is expanded. + +```rust, +# fn main() {} +# #[cfg(target_arch = "x86_64")] +core::arch::global_asm!( + #[cfg(not(panic = "abort"))] + ".cfi_startproc", + // ... + "ret", + #[cfg(not(panic = "abort"))] + ".cfi_endproc", +); +``` + +r[asm.attributes.starts-with-template] +Syntactically there must be at least one template string before the first operand. + +```rust, ignore +// This is rejected because `a = out(reg) x` does not parse as a template string. +core::arch::asm!( + #[cfg(false)] + a = out(reg) x, //~ ERROR expected token: `,` + "", +); +``` + +[`cfg`]: conditional-compilation.md#the-cfg-attribute +[`cfg_attr`]: conditional-compilation.md#the-cfg_attr-attribute + r[asm.operand-type] ## Operand type From 0de83376ed061e7893937ecf69b3eaf3650e4e11 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Sun, 16 Nov 2025 09:17:28 +0000 Subject: [PATCH 32/53] Remove stray comma from info string There was a stray comma on this info string. Let's remove it. --- src/inline-assembly.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/inline-assembly.md b/src/inline-assembly.md index caa6148c..7a6a5ac5 100644 --- a/src/inline-assembly.md +++ b/src/inline-assembly.md @@ -276,7 +276,7 @@ r[asm.attributes] r[asm.attributes.supported-attributes] Only the [`cfg`] and [`cfg_attr`] attributes are accepted semantically on inline assembly template strings and operands. Other attributes are parsed, but rejected when the assembly macro is expanded. -```rust, +```rust # fn main() {} # #[cfg(target_arch = "x86_64")] core::arch::global_asm!( From a1fa462eff8ad1845e1076c47fead42914fe9ef9 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Sun, 16 Nov 2025 09:25:33 +0000 Subject: [PATCH 33/53] Revise `starts-with-template` example This test is believed to fail, so we should mark it with `compile_fail` rather than `ignore`. Let's wrap the comment. The compiler's error message, in this case, doesn't add any insight; let's remove the details of that. --- src/inline-assembly.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/inline-assembly.md b/src/inline-assembly.md index 7a6a5ac5..dcc6329b 100644 --- a/src/inline-assembly.md +++ b/src/inline-assembly.md @@ -292,11 +292,12 @@ core::arch::global_asm!( r[asm.attributes.starts-with-template] Syntactically there must be at least one template string before the first operand. -```rust, ignore -// This is rejected because `a = out(reg) x` does not parse as a template string. +```rust,compile_fail +// This is rejected because `a = out(reg) x` does not parse as a +// template string. core::arch::asm!( #[cfg(false)] - a = out(reg) x, //~ ERROR expected token: `,` + a = out(reg) x, // ERROR. "", ); ``` From 921222e265e2a53544cb8768467e405ef866a88c Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Sun, 16 Nov 2025 12:19:41 +0000 Subject: [PATCH 34/53] Remove stray comma The sentence "Other attributes are parsed but rejected" has a two-part compound predicate; that is, the subject is used for two verbs, separated by a coordinating conjunction ("but"), and is not repeated. In these cases, a comma is omitted before the coordinating conjunction, so let's remove the comma. --- src/inline-assembly.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/inline-assembly.md b/src/inline-assembly.md index dcc6329b..50d83573 100644 --- a/src/inline-assembly.md +++ b/src/inline-assembly.md @@ -274,7 +274,7 @@ r[asm.attributes] ## Attributes r[asm.attributes.supported-attributes] -Only the [`cfg`] and [`cfg_attr`] attributes are accepted semantically on inline assembly template strings and operands. Other attributes are parsed, but rejected when the assembly macro is expanded. +Only the [`cfg`] and [`cfg_attr`] attributes are accepted semantically on inline assembly template strings and operands. Other attributes are parsed but rejected when the assembly macro is expanded. ```rust # fn main() {} From 447b76c7a9a492e9315c40c50d28499fb81d1164 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Sun, 16 Nov 2025 12:42:12 +0000 Subject: [PATCH 35/53] Add note about restrictions on asm attributes We have a list that describes where attributes may be applied. We're adding inline assembly template strings and operands to that list, but only certain attributes may be used, and other caveats apply. Let's note that there are restrictions and link to the relevant section for more details, as we do already for certain other items on this list. It may be important, normatively, to note this restriction here if we now or later refer to some attribute as being accepted anywhere that attributes are allowed. --- src/attributes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/attributes.md b/src/attributes.md index 376c6977..895231e8 100644 --- a/src/attributes.md +++ b/src/attributes.md @@ -107,7 +107,7 @@ Attributes may be applied to many forms in the language: * [Function][functions], [closure] and [function pointer] parameters accept outer attributes. This includes attributes on variadic parameters denoted with `...` in function pointers and [external blocks][variadic functions]. -* [Inline assembly] template strings and operands accept outer attributes. +* [Inline assembly] template strings and operands accept outer attributes. Only certain attributes are accepted semantically; for details, see [asm.attributes.supported-attributes]. r[attributes.meta] ## Meta item attribute syntax From ac44a375764e9bd3c04d20f8a8a496e552830c6b Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Sun, 16 Nov 2025 12:45:08 +0000 Subject: [PATCH 36/53] Add admonition about asm attribute implementation The implementation of attributes for asm macro template strings and operands doesn't use the normal system in `rustc` for handling attributes. This leads to the limitations and may lead to subtle divergences in behavior. Let's make a note about this. For background, see: - https://github.com/rust-lang/reference/pull/2063#discussion_r2462614284 - https://github.com/rust-lang/rust/pull/147736#issuecomment-3435781687 --- src/inline-assembly.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/inline-assembly.md b/src/inline-assembly.md index 50d83573..b08ad410 100644 --- a/src/inline-assembly.md +++ b/src/inline-assembly.md @@ -289,6 +289,9 @@ core::arch::global_asm!( ); ``` +> [!NOTE] +> In `rustc`, the assembly macros implement handling of these attributes separately from the normal system that handles similar attributes in the language. This accounts for the limited kinds of attributes supported and may give rise to subtle differences in behavior. + r[asm.attributes.starts-with-template] Syntactically there must be at least one template string before the first operand. From cd0b2559d17fd5b7c0fbc8d01275bb3fd6b99f55 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Sun, 16 Nov 2025 07:51:49 +0000 Subject: [PATCH 37/53] Remove restriction on dereferencing pointers in const We had said that the dereference operator could not be used with raw pointers in a constant expression. However, that restriction has been lifted. First, in Rust 1.58, we stabilized `const_raw_ptr_deref`. https://github.com/rust-lang/rust/pull/89551 This allowed for dereferencing immutable raw pointers in a constant expression. Then, in Rust 1.83, we stabilized `const_mut_refs` and `const_refs_to_cell`. https://github.com/rust-lang/rust/pull/129195 That allowed for: - Mentioning `&mut` types. - Creating `&mut` and `*mut` values. - Creating `&T` and `*const T` values where `T` contains interior mutability. - Dereferencing `&mut` and `*mut` values (both for reads and writes). Let's remove the stated restriction on dereferencing raw pointers in a constant expression and add examples. --- src/const_eval.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/const_eval.md b/src/const_eval.md index 04146adf..35b14853 100644 --- a/src/const_eval.md +++ b/src/const_eval.md @@ -203,7 +203,23 @@ r[const-eval.const-expr.borrows] > See [issue #143129](https://github.com/rust-lang/rust/issues/143129) for more details. r[const-eval.const-expr.deref] -* The [dereference operator] except for raw pointers. +* The [dereference operator]. + + ```rust,no_run + # use core::cell::UnsafeCell; + const _: u8 = unsafe { + let x: *mut u8 = &raw mut *&mut 0; + // ^^^^^^^ + // Dereference of mutable reference. + *x = 1; // Dereference of mutable pointer. + *(x as *const u8) // Dereference of constant pointer. + }; + const _: u8 = unsafe { + let x = &UnsafeCell::new(0); + *x.get() = 1; // Mutation of interior mutable value. + *x.get() + }; + ``` r[const-eval.const-expr.group] From 0659e98417197390ee16d304c51a27773b62c3af Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Sun, 16 Nov 2025 08:08:10 +0000 Subject: [PATCH 38/53] Say "dereference expressions" in constant exprs list To define what's allowed in a constant expression, we have a list that starts with the text: > The following expressions are constant expressions... Correspondingly, most of the items in this list are stated in terms of being a "this expression" or a "that expression". However, for deref, we had instead said "the dereference operator". Even though the `expr.deref` section is currently titled "the dereference operator", it seems more clear and consistent in the context of this list to talk about dereference expressions, so let's do that. These are expressions, after all, The grammar production is named `DereferenceExpression`. (There is one other place in the list that we talk about operators: "built-in negation, arithmetic, logical, comparison, or lazy boolean operators used on integer and floating point types, `bool`, and `char`." Perhaps we'll reword that one later. It stands out a bit less than this one did.) --- src/const_eval.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/const_eval.md b/src/const_eval.md index 35b14853..71f392dc 100644 --- a/src/const_eval.md +++ b/src/const_eval.md @@ -203,7 +203,7 @@ r[const-eval.const-expr.borrows] > See [issue #143129](https://github.com/rust-lang/rust/issues/143129) for more details. r[const-eval.const-expr.deref] -* The [dereference operator]. +* [Dereference expressions]. ```rust,no_run # use core::cell::UnsafeCell; @@ -320,8 +320,8 @@ The types of a const function's parameters and return type are restricted to tho [constant expressions]: #constant-expressions [constants]: items/constant-items.md [Const parameters]: items/generics.md -[dereference expression]: expressions/operator-expr.md#the-dereference-operator -[dereference operator]: expressions/operator-expr.md#the-dereference-operator +[dereference expression]: expr.deref +[dereference expressions]: expr.deref [destructors]: destructors.md [enum discriminants]: items/enumerations.md#discriminants [expression statements]: statements.md#expression-statements From 38093f5a075c65422d9216b8c3f62a2e367c635c Mon Sep 17 00:00:00 2001 From: Jane Losare-Lusby Date: Fri, 14 Nov 2025 15:36:20 -0800 Subject: [PATCH 39/53] Add review process overview to review-policy.md --- docs/review-policy.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/review-policy.md b/docs/review-policy.md index 9d61151d..d46476df 100644 --- a/docs/review-policy.md +++ b/docs/review-policy.md @@ -1,5 +1,13 @@ Team members are given permission to merge changes from other contributors in the repository. There are different guidelines for reviewing based on the kind of changes being made: +## Review Principles + +Reviewers and authors should focus on a few key principles during the review process: + +* **Understandability**: Language within the reference should be understandable to most members of the project. Contributions should assumes that readers are familiar with the rest of the content of the reference, but wherever possible sections should facilitate that understanding by linking to related content that are needed to build an understanding. +* **Defensibility**: When the lang-docs team merges a change to the reference they are agreeing to take responsibility for it going forward. Team members need to feel confident defending and explaining the correctness of content within the reference. Whenever possible, changes to the reference should back up any claims they make with concise examples verifying their correctness. +* **Voice**: Authors are not expected to have specification writer competence when drafting new contributions to the reference. So long as claims are understandable and defensible, it is fine for PRs to be written in a casual tone or with the voice of the author instead of the voice of the reference. Team members are expected to bring editorial experience as part of their reviews and will edit the phrasing to fit the reference before merging if necessary. + ## Policy changes - Significant changes to the policy of how the team operates, such as changes to this document, should have agreement of the team without any blocking objections. From 81ed7c1e53ad233b01ef8452026838578c14dd0e Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Tue, 18 Nov 2025 22:05:08 +0000 Subject: [PATCH 40/53] Revise "review principles" text This text is great. Jane put this together after talking with the team in some detail in a lang-docs office hours call. In this commit, we revise the wording slightly and adjust capitalization to match our style. --- docs/review-policy.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/review-policy.md b/docs/review-policy.md index d46476df..2195c444 100644 --- a/docs/review-policy.md +++ b/docs/review-policy.md @@ -1,12 +1,12 @@ Team members are given permission to merge changes from other contributors in the repository. There are different guidelines for reviewing based on the kind of changes being made: -## Review Principles +## Review principles Reviewers and authors should focus on a few key principles during the review process: -* **Understandability**: Language within the reference should be understandable to most members of the project. Contributions should assumes that readers are familiar with the rest of the content of the reference, but wherever possible sections should facilitate that understanding by linking to related content that are needed to build an understanding. -* **Defensibility**: When the lang-docs team merges a change to the reference they are agreeing to take responsibility for it going forward. Team members need to feel confident defending and explaining the correctness of content within the reference. Whenever possible, changes to the reference should back up any claims they make with concise examples verifying their correctness. -* **Voice**: Authors are not expected to have specification writer competence when drafting new contributions to the reference. So long as claims are understandable and defensible, it is fine for PRs to be written in a casual tone or with the voice of the author instead of the voice of the reference. Team members are expected to bring editorial experience as part of their reviews and will edit the phrasing to fit the reference before merging if necessary. +* **Understandability**: Language within the Reference should be understandable to most members of the Project. Contributions should assumes that readers are familiar with the rest of the content of the Reference, but, wherever possible, sections should facilitate that understanding by linking to related content. +* **Defensibility**: When the lang-docs team merges a change to the Reference, they are agreeing to take responsibility for it going forward. Team members need to feel confident defending and explaining the correctness of content within the Reference. Whenever possible, changes to the Reference should back up any claims with concise examples to verify correctness. +* **Voice**: Authors are not expected to have competence as a specification writer when drafting new contributions to the Reference. So long as claims are understandable and defensible, it is fine for PRs to be written in a casual tone or with the voice of the author instead of the voice of the Reference. Team members will bring editorial experience as part of their reviews and will revise the phrasing, organization, style, etc. to fit the Reference before merging if necessary. ## Policy changes From 40c08a457529b1f53b7d9216196305a6829bbcb3 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 19 Nov 2025 16:33:24 +0200 Subject: [PATCH 41/53] remove unused "link reference definitions" --- src/syntax-index.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/syntax-index.md b/src/syntax-index.md index 03df966d..fc06a26d 100644 --- a/src/syntax-index.md +++ b/src/syntax-index.md @@ -301,7 +301,6 @@ This appendix provides an index of tokens and common forms with links to where t [closure expressions]: expr.closure [closures]: expr.closure [comparison]: expr.cmp -[compound type bounds]: bound [compound]: expr.compound-assign [configuration predicates]: cfg [const assembly operands]: asm.operand-type.supported-operands.const @@ -321,7 +320,6 @@ This appendix provides an index of tokens and common forms with links to where t [extern crate]: items.extern-crate [extern function pointer types]: type.fn-pointer.qualifiers [extern function qualifier]: items.fn.extern -[extern]: items.extern [external block functions]: items.extern.fn [external block statics]: items.extern.static [external blocks]: items.extern @@ -349,7 +347,6 @@ This appendix provides an index of tokens and common forms with links to where t [inherent impls]: items.impl.inherent [inner attribute]: attributes.inner [iterator loops]: expr.loop.for -[keywords chapter]: lex.keywords [lazy-bool]: expr.bool-logic [let statements]: statement.let [lifetime bounds]: bound.lifetime @@ -407,7 +404,6 @@ This appendix provides an index of tokens and common forms with links to where t [return expressions]: expr.return [self parameters]: items.fn.params.self-pat [single-element tuple expressions]: expr.tuple -[sized]: bound.sized [slice patterns]: patterns.slice [slice types]: type.slice [static items]: items.static From 81a0697a3ce52844c04b75ef5baa8fcd3bd7aad3 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Fri, 28 Nov 2025 09:44:54 +0200 Subject: [PATCH 42/53] use oxford comma --- src/attributes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/attributes.md b/src/attributes.md index 895231e8..e5d96944 100644 --- a/src/attributes.md +++ b/src/attributes.md @@ -235,7 +235,7 @@ pub fn f() {} ``` > [!NOTE] -> `rustc` currently recognizes the tools "clippy", "rustfmt", "diagnostic", "miri" and "rust_analyzer". +> `rustc` currently recognizes the tools "clippy", "rustfmt", "diagnostic", "miri", and "rust_analyzer". r[attributes.builtin] ## Built-in attributes index From a87322def5a36a19ccfa0efc994fb32991127201 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Sat, 8 Nov 2025 06:04:25 +0000 Subject: [PATCH 43/53] Clarify const item text WRT mutable statics The rule is that "mutable references contained within a mutable static may be referenced in the final value of a constant." However, the key here is that "mutable static" means either a `static mut` item or a `static` item with an interior mutable type. We had made that clear over in `const-eval.const-expr.path-static` but not in our rules about const item validity, and our link for "mutable static" had implied it may mean `static mut`. Let's fix that and add an example to demonstrate the point. --- src/items/constant-items.md | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/items/constant-items.md b/src/items/constant-items.md index 321894a9..3d9d044c 100644 --- a/src/items/constant-items.md +++ b/src/items/constant-items.md @@ -133,9 +133,9 @@ const _: U = unsafe { U { f: &mut S }}; // OK. // This is treated as a sequence of untyped bytes. ``` -Mutable references contained within a [mutable static] may be referenced in the final value of a constant. +Mutable references contained within a mutable `static` may be referenced in the final value of a constant. A mutable `static` is a [`static mut`] item or a [`static`] item with an [interior mutable] type. -```rust +```rust,no_run # #![allow(static_mut_refs)] static mut S: &mut u8 = unsafe { static mut I: u8 = 0; &mut I }; const _: &&mut u8 = unsafe { &S }; // OK. @@ -143,6 +143,21 @@ const _: &&mut u8 = unsafe { &S }; // OK. // This mutable reference comes from a `static mut`. ``` +```rust,no_run +# #![allow(static_mut_refs)] +# use core::cell::UnsafeCell; +struct PhantomCell { _m: UnsafeCell<()> } +unsafe impl Sync for PhantomCell {} +static S: (&mut u8, Option) = { + static mut I: u8 = 0; + (unsafe { &mut I }, None) +}; +const _: &&mut u8 = &S.0; +// ^^^^^^^ +// This mutable reference comes from a `static` with an +// interior mutable type. +``` + > [!NOTE] > This is allowed as it's separately not allowed to read from a mutable static during constant evaluation. See [const-eval.const-expr.path-static]. @@ -251,17 +266,19 @@ fn unused_generic_function() { } ``` +[`static mut`]: items.static.mut +[`static`]: items.static [const_eval]: ../const_eval.md [associated constant]: ../items/associated-items.md#associated-constants [constant value]: ../const_eval.md#constant-expressions [external static]: items.extern.static [free]: ../glossary.md#free-item +[interior mutable]: interior-mut [static lifetime elision]: ../lifetime-elision.md#const-and-static-elision [trait definition]: traits.md [underscore imports]: use-declarations.md#underscore-imports [`Copy`]: ../special-types-and-traits.md#copy [value namespace]: ../names/namespaces.md -[mutable static]: items.static.mut [promoted]: destructors.scope.const-promotion [promotion]: destructors.scope.const-promotion [union type]: type.union From 95974736943751458ff8e98e94e03ab43646e807 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Nov 2025 14:41:03 +0100 Subject: [PATCH 44/53] get rid of const.no-mut-refs --- src/items/constant-items.md | 146 ------------------------------------ 1 file changed, 146 deletions(-) diff --git a/src/items/constant-items.md b/src/items/constant-items.md index 3d9d044c..a1518471 100644 --- a/src/items/constant-items.md +++ b/src/items/constant-items.md @@ -48,152 +48,6 @@ const BITS_N_STRINGS: BitsNStrings<'static> = BitsNStrings { }; ``` -r[items.const.no-mut-refs] -The final value of a `const` item, after the initializer is evaluated to a value that has the declared type of the constant, cannot contain any mutable references except as described below. - -```rust -# #![allow(static_mut_refs)] -static mut S: u8 = 0; -const _: &u8 = unsafe { &mut S }; // OK. -// ^^^^^^ -// Allowed since this is coerced to `&S`. -``` - -```rust -# use core::sync::atomic::AtomicU8; -static S: AtomicU8 = AtomicU8::new(0); -const _: &AtomicU8 = &S; // OK. -// ^^ -// Allowed even though the shared reference is to an interior -// mutable value. -``` - -```rust,compile_fail,E0080 -# #![allow(static_mut_refs)] -static mut S: u8 = 0; -const _: &mut u8 = unsafe { &mut S }; // ERROR. -// ^^^^^^ -// Not allowed as the mutable reference appears in the final value. -``` - -> [!NOTE] -> Constant initializers can be thought of, in most cases, as being inlined wherever the constant appears. If a constant whose value contains a mutable reference to a mutable static were to appear twice, and this were to be allowed, that would create two mutable references, each having `'static` lifetime, to the same place. This could produce undefined behavior. -> -> Constants that contain mutable references to temporaries whose scopes have been extended to the end of the program have that same problem and an additional one. -> -> ```rust,compile_fail,E0764 -> const _: &mut u8 = &mut 0; // ERROR. -> // ^^^^^^ -> // Not allowed as the mutable reference appears in the final value and -> // because the constant expression contains a mutable borrow of an -> // expression whose temporary scope would be extended to the end of -> // the program. -> ``` -> -> Here, the value `0` is a temporary whose scope is extended to the end of the program (see [destructors.scope.lifetime-extension.static]). Such temporaries cannot be mutably borrowed in constant expressions (see [const-eval.const-expr.borrows]). -> -> To allow this, we'd have to decide whether each use of the constant creates a new `u8` value or whether each use shares the same lifetime-extended temporary. The latter choice, though closer to how `rustc` thinks about this today, would break the conceptual model that, in most cases, the constant initializer can be thought of as being inlined wherever the constant is used. Since we haven't decided, and due to the other problem mentioned, this is not allowed. - -```rust,compile_fail,E0080 -# #![allow(static_mut_refs)] -static mut S: u8 = 0; -const _: &dyn Send = &unsafe { &mut S }; // ERROR. -// ^^^^^^ -// Not allowed as the mutable reference appears in the final value, -// even though type erasure occurs. -``` - -Mutable references where the referent is a value of a [zero-sized type] are allowed. - -```rust -# #![allow(static_mut_refs)] -static mut S: () = (); -const _: &mut () = unsafe { &mut S }; // OK. -// ^^ This is a zero-sized type. -``` - -```rust -# #![allow(static_mut_refs)] -static mut S: [u8; 0] = [0; 0]; -const _: &mut [u8; 0] = unsafe { &mut S }; // OK. -// ^^^^^^^ This is a zero-sized type. -``` - -> [!NOTE] -> This is allowed as, for a value of a zero-sized type, no bytes can actually be mutated. We must accept this as `&mut []` is [promoted]. - -Values of [union type] are not considered to contain any references; for this purpose, a value of union type is treated as a sequence of untyped bytes. - -```rust -# #![allow(static_mut_refs)] -union U { f: &'static mut u8 } -static mut S: u8 = 0; -const _: U = unsafe { U { f: &mut S }}; // OK. -// ^^^^^^^^^^^^^^^ -// This is treated as a sequence of untyped bytes. -``` - -Mutable references contained within a mutable `static` may be referenced in the final value of a constant. A mutable `static` is a [`static mut`] item or a [`static`] item with an [interior mutable] type. - -```rust,no_run -# #![allow(static_mut_refs)] -static mut S: &mut u8 = unsafe { static mut I: u8 = 0; &mut I }; -const _: &&mut u8 = unsafe { &S }; // OK. -// ^^^^^^^ -// This mutable reference comes from a `static mut`. -``` - -```rust,no_run -# #![allow(static_mut_refs)] -# use core::cell::UnsafeCell; -struct PhantomCell { _m: UnsafeCell<()> } -unsafe impl Sync for PhantomCell {} -static S: (&mut u8, Option) = { - static mut I: u8 = 0; - (unsafe { &mut I }, None) -}; -const _: &&mut u8 = &S.0; -// ^^^^^^^ -// This mutable reference comes from a `static` with an -// interior mutable type. -``` - -> [!NOTE] -> This is allowed as it's separately not allowed to read from a mutable static during constant evaluation. See [const-eval.const-expr.path-static]. - -Mutable references contained within an [external static] may be referenced in the final value of a constant. - -```rust -# #![allow(static_mut_refs)] -unsafe extern "C" { static S: &'static mut u8; } -const _: &&mut u8 = unsafe { &S }; // OK. -// ^^^^^^^ -// This mutable references comes from an extern static. -``` - -> [!NOTE] -> This is allowed as it's separately not allowed to read from an external static during constant evaluation. See [const-eval.const-expr.path-static]. - -> [!NOTE] -> As described above, we accept, in the final value of constant items, shared references to static items whose values have interior mutability. -> -> ```rust -> # use core::sync::atomic::AtomicU8; -> static S: AtomicU8 = AtomicU8::new(0); -> const _: &AtomicU8 = &S; // OK. -> ``` -> -> However, we disallow similar code when the interior mutable value is created in the initializer. -> -> ```rust,compile_fail,E0492 -> # use core::sync::atomic::AtomicU8; -> const _: &AtomicU8 = &AtomicU8::new(0); // ERROR. -> ``` -> -> Here, the `AtomicU8` is a temporary whose scope is extended to the end of the program (see [destructors.scope.lifetime-extension.static]). Such temporaries with interior mutability cannot be borrowed in constant expressions (see [const-eval.const-expr.borrows]). -> -> To allow this, we'd have to decide whether each use of the constant creates a new `AtomicU8` or whether each use shares the same lifetime-extended temporary. The latter choice, though closer to how `rustc` thinks about this today, would break the conceptual model that, in most cases, the constant initializer can be thought of as being inlined wherever the constant is used. Since we haven't decided, this is not allowed. - r[items.const.expr-omission] The constant expression may only be omitted in a [trait definition]. From b666677ae6e6314a811dfaa30847eb7bb07c2c09 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Sun, 30 Nov 2025 02:54:29 +0000 Subject: [PATCH 45/53] Remove unused link reference definitions These link reference definitions were used in `const.no-mut-refs` and are no longer needed. --- src/items/constant-items.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/items/constant-items.md b/src/items/constant-items.md index a1518471..0b2f223c 100644 --- a/src/items/constant-items.md +++ b/src/items/constant-items.md @@ -120,20 +120,13 @@ fn unused_generic_function() { } ``` -[`static mut`]: items.static.mut -[`static`]: items.static [const_eval]: ../const_eval.md [associated constant]: ../items/associated-items.md#associated-constants [constant value]: ../const_eval.md#constant-expressions -[external static]: items.extern.static [free]: ../glossary.md#free-item -[interior mutable]: interior-mut [static lifetime elision]: ../lifetime-elision.md#const-and-static-elision [trait definition]: traits.md [underscore imports]: use-declarations.md#underscore-imports [`Copy`]: ../special-types-and-traits.md#copy [value namespace]: ../names/namespaces.md -[promoted]: destructors.scope.const-promotion [promotion]: destructors.scope.const-promotion -[union type]: type.union -[zero-sized type]: layout.properties.size From 88c77014b479f70ed334b00ef25c639ab1f70a9f Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 22 Nov 2025 12:13:36 -0800 Subject: [PATCH 46/53] Update to mdbook 0.5 Changelog: https://github.com/rust-lang/mdBook/blob/master/CHANGELOG.md#mdbook-051 --- .github/workflows/main.yml | 2 +- mdbook-spec/Cargo.lock | 695 ++++++------------------------- mdbook-spec/Cargo.toml | 5 +- mdbook-spec/src/admonitions.rs | 2 +- mdbook-spec/src/grammar.rs | 2 +- mdbook-spec/src/lib.rs | 14 +- mdbook-spec/src/rules.rs | 3 +- mdbook-spec/src/std_links.rs | 7 +- mdbook-spec/src/test_links.rs | 2 +- src/expressions/operator-expr.md | 2 +- src/syntax-index.md | 8 +- src/types/boolean.md | 2 +- theme/reference.css | 2 +- 13 files changed, 146 insertions(+), 600 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2f2b9b29..5be0bd51 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -4,7 +4,7 @@ on: merge_group: env: - MDBOOK_VERSION: 0.4.52 + MDBOOK_VERSION: 0.5.1 jobs: code-tests: diff --git a/mdbook-spec/Cargo.lock b/mdbook-spec/Cargo.lock index 1dea1df7..13866cee 100644 --- a/mdbook-spec/Cargo.lock +++ b/mdbook-spec/Cargo.lock @@ -11,81 +11,11 @@ dependencies = [ "memchr", ] -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anstream" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" - -[[package]] -name = "anstyle-parse" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" -dependencies = [ - "anstyle", - "windows-sys 0.59.0", -] - [[package]] name = "anyhow" -version = "1.0.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" - -[[package]] -name = "autocfg" -version = "1.4.0" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "bitflags" @@ -93,41 +23,6 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bstr" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22" -dependencies = [ - "memchr", - "regex-automata", - "serde", -] - -[[package]] -name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "cc" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" -dependencies = [ - "shlex", -] - [[package]] name = "cfg-if" version = "1.0.0" @@ -135,128 +30,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "chrono" -version = "0.4.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "num-traits", - "windows-targets", -] - -[[package]] -name = "clap" -version = "4.5.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" -dependencies = [ - "clap_builder", -] - -[[package]] -name = "clap_builder" -version = "4.5.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", - "terminal_size", -] - -[[package]] -name = "clap_complete" -version = "4.5.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9647a559c112175f17cf724dc72d3645680a883c58481332779192b0d8e7a01" -dependencies = [ - "clap", -] - -[[package]] -name = "clap_lex" -version = "0.7.3" +name = "equivalent" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" - -[[package]] -name = "colorchoice" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "cpufeatures" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" -dependencies = [ - "libc", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "dbus" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bb21987b9fb1613058ba3843121dd18b163b254d8a6e797e144cbac14d96d1b" -dependencies = [ - "libc", - "libdbus-sys", - "winapi", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "env_filter" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" -dependencies = [ - "log", - "regex", -] - -[[package]] -name = "env_logger" -version = "0.11.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" -dependencies = [ - "anstream", - "anstyle", - "env_filter", - "humantime", - "log", -] +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" @@ -275,96 +52,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "handlebars" -version = "6.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd4ccde012831f9a071a637b0d4e31df31c0f6c525784b35ae76a9ac6bc1e315" -dependencies = [ - "log", - "num-order", - "pest", - "pest_derive", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - -[[package]] -name = "iana-time-zone" -version = "0.1.61" +name = "hashbrown" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" [[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" +name = "indexmap" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ - "cc", + "equivalent", + "hashbrown", ] -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - [[package]] name = "itoa" version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "540654e97a3f4470a492cd30ff187bc95d89557a903a2bbf112e2fae98104ef2" -[[package]] -name = "js-sys" -version = "0.3.72" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" -dependencies = [ - "wasm-bindgen", -] - [[package]] name = "libc" version = "0.2.164" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" -[[package]] -name = "libdbus-sys" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06085512b750d640299b79be4bad3d2fa90a9c00b1fd9e1b46364f66f0485c72" -dependencies = [ - "cc", - "pkg-config", -] - [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -372,35 +86,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] -name = "log" -version = "0.4.22" +name = "mdbook-core" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "2ef8430ec21b88489dfffd90c0fb9bd3eab96bf7642ef0cab74754b9d2e5b7f6" +dependencies = [ + "anyhow", + "regex", + "serde", + "serde_json", + "toml", + "tracing", +] [[package]] -name = "mdbook" -version = "0.4.43" +name = "mdbook-markdown" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe1f98b8d66e537d2f0ba06e7dec4f44001deec539a2d18bfc102d6a86189148" +checksum = "27f58c1b5686d0add2b513c15401177f84e87742ec381ccd4bfc2216de9a52e8" dependencies = [ - "anyhow", - "chrono", - "clap", - "clap_complete", - "env_logger", - "handlebars", - "log", - "memchr", - "once_cell", - "opener", "pulldown-cmark", "regex", + "tracing", +] + +[[package]] +name = "mdbook-preprocessor" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01f84f2b2ef3ccf2c6dd71255f9d90912cce7d5a5aa32899d033003d2c71f84d" +dependencies = [ + "anyhow", + "mdbook-core", "serde", "serde_json", - "shlex", - "tempfile", - "toml", - "topological-sort", ] [[package]] @@ -408,10 +127,10 @@ name = "mdbook-spec" version = "0.1.2" dependencies = [ "anyhow", - "mdbook", + "mdbook-markdown", + "mdbook-preprocessor", "once_cell", "pathdiff", - "pulldown-cmark", "railroad", "regex", "semver", @@ -426,57 +145,12 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" -[[package]] -name = "normpath" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8911957c4b1549ac0dc74e30db9c8b0e66ddcd6d7acc33098f4c63a64a6d7ed" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "num-modular" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f" - -[[package]] -name = "num-order" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "537b596b97c40fcf8056d153049eb22f481c17ebce72a513ec9286e4986d1bb6" -dependencies = [ - "num-modular", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - [[package]] name = "once_cell" version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" -[[package]] -name = "opener" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0812e5e4df08da354c851a3376fead46db31c2214f849d3de356d774d057681" -dependencies = [ - "bstr", - "dbus", - "normpath", - "windows-sys 0.59.0", -] - [[package]] name = "pathdiff" version = "0.2.2" @@ -484,55 +158,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361" [[package]] -name = "pest" -version = "2.7.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" -dependencies = [ - "memchr", - "thiserror", - "ucd-trie", -] - -[[package]] -name = "pest_derive" -version = "2.7.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" -dependencies = [ - "pest", - "pest_generator", -] - -[[package]] -name = "pest_generator" -version = "2.7.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" -dependencies = [ - "pest", - "pest_meta", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "pest_meta" -version = "2.7.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" -dependencies = [ - "once_cell", - "pest", - "sha2", -] - -[[package]] -name = "pkg-config" -version = "0.3.31" +name = "pin-project-lite" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "proc-macro2" @@ -545,9 +174,9 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.10.3" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993" +checksum = "1e8bbe1a966bd2f362681a44f6edce3c2310ac21e4d5067a6e7ec396297a6ea0" dependencies = [ "bitflags", "memchr", @@ -557,9 +186,9 @@ dependencies = [ [[package]] name = "pulldown-cmark-escape" -version = "0.10.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd348ff538bc9caeda7ee8cad2d1d48236a1f443c1fa3913c6a02fe0043b1dd3" +checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae" [[package]] name = "quote" @@ -581,9 +210,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.1" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", @@ -593,9 +222,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", @@ -644,18 +273,28 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.215" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -664,39 +303,26 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.133" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] -name = "sha2" -version = "0.10.8" +name = "serde_spanned" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" dependencies = [ - "cfg-if", - "cpufeatures", - "digest", + "serde_core", ] -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - [[package]] name = "syn" version = "2.0.89" @@ -722,61 +348,74 @@ dependencies = [ ] [[package]] -name = "terminal_size" -version = "0.4.0" +name = "toml" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef" +checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" dependencies = [ - "rustix", - "windows-sys 0.59.0", + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", ] [[package]] -name = "thiserror" -version = "1.0.69" +name = "toml_datetime" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" dependencies = [ - "thiserror-impl", + "serde_core", ] [[package]] -name = "thiserror-impl" -version = "1.0.69" +name = "toml_parser" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" dependencies = [ - "proc-macro2", - "quote", - "syn", + "winnow", ] [[package]] -name = "toml" -version = "0.5.11" +name = "toml_writer" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] +checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" [[package]] -name = "topological-sort" -version = "0.2.2" +name = "tracing" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] [[package]] -name = "typenum" -version = "1.17.0" +name = "tracing-attributes" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] -name = "ucd-trie" -version = "0.1.7" +name = "tracing-core" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +dependencies = [ + "once_cell", +] [[package]] name = "unicase" @@ -796,18 +435,6 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - [[package]] name = "walkdir" version = "2.5.0" @@ -818,77 +445,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "wasm-bindgen" -version = "0.2.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" -dependencies = [ - "cfg-if", - "once_cell", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - [[package]] name = "winapi-util" version = "0.1.9" @@ -898,21 +454,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets", -] - [[package]] name = "windows-sys" version = "0.52.0" @@ -994,3 +535,9 @@ name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" diff --git a/mdbook-spec/Cargo.toml b/mdbook-spec/Cargo.toml index 8bd02e44..c4189709 100644 --- a/mdbook-spec/Cargo.toml +++ b/mdbook-spec/Cargo.toml @@ -11,11 +11,10 @@ default-run = "mdbook-spec" [dependencies] anyhow = "1.0.79" -mdbook = { version = "0.4.36", default-features = false } +mdbook-markdown = "0.5.1" +mdbook-preprocessor = "0.5.1" once_cell = "1.19.0" pathdiff = "0.2.1" -# Try to keep in sync with mdbook. -pulldown-cmark = { version = "0.10.3", default-features = false } railroad = { version = "0.3.2", default-features = false } regex = "1.9.4" semver = "1.0.21" diff --git a/mdbook-spec/src/admonitions.rs b/mdbook-spec/src/admonitions.rs index 8aaf6cf6..da391838 100644 --- a/mdbook-spec/src/admonitions.rs +++ b/mdbook-spec/src/admonitions.rs @@ -10,7 +10,7 @@ //! 4. Update `docs/authoring.md` to show an example of your new admonition. use crate::{Diagnostics, warn_or_err}; -use mdbook::book::Chapter; +use mdbook_preprocessor::book::Chapter; use regex::{Captures, Regex}; use std::sync::LazyLock; diff --git a/mdbook-spec/src/grammar.rs b/mdbook-spec/src/grammar.rs index 8a15c719..b0c2c581 100644 --- a/mdbook-spec/src/grammar.rs +++ b/mdbook-spec/src/grammar.rs @@ -1,7 +1,7 @@ //! Support for rendering the grammar. use crate::{Diagnostics, warn_or_err}; -use mdbook::book::{Book, BookItem, Chapter}; +use mdbook_preprocessor::book::{Book, BookItem, Chapter}; use regex::{Captures, Regex}; use std::collections::{HashMap, HashSet}; use std::fmt::Write; diff --git a/mdbook-spec/src/lib.rs b/mdbook-spec/src/lib.rs index f5799ae0..0feab5ef 100644 --- a/mdbook-spec/src/lib.rs +++ b/mdbook-spec/src/lib.rs @@ -2,10 +2,10 @@ use crate::rules::Rules; use anyhow::{Context, Result, bail}; -use mdbook::BookItem; -use mdbook::book::{Book, Chapter}; -use mdbook::errors::Error; -use mdbook::preprocess::{CmdPreprocessor, Preprocessor, PreprocessorContext}; +use mdbook_preprocessor::book::BookItem; +use mdbook_preprocessor::book::{Book, Chapter}; +use mdbook_preprocessor::errors::Error; +use mdbook_preprocessor::{Preprocessor, PreprocessorContext}; use once_cell::sync::Lazy; use regex::{Captures, Regex}; use semver::{Version, VersionReq}; @@ -26,17 +26,17 @@ static MD_LINK_REFERENCE_DEFINITION: Lazy = pub fn handle_preprocessing() -> Result<(), Error> { let pre = Spec::new(None)?; - let (ctx, book) = CmdPreprocessor::parse_input(io::stdin())?; + let (ctx, book) = mdbook_preprocessor::parse_input(io::stdin())?; let book_version = Version::parse(&ctx.mdbook_version)?; - let version_req = VersionReq::parse(mdbook::MDBOOK_VERSION)?; + let version_req = VersionReq::parse(mdbook_preprocessor::MDBOOK_VERSION)?; if !version_req.matches(&book_version) { eprintln!( "warning: The {} plugin was built against version {} of mdbook, \ but we're being called from version {}", pre.name(), - mdbook::MDBOOK_VERSION, + mdbook_preprocessor::MDBOOK_VERSION, ctx.mdbook_version ); } diff --git a/mdbook-spec/src/rules.rs b/mdbook-spec/src/rules.rs index 8c3e9a3a..4bfec06b 100644 --- a/mdbook-spec/src/rules.rs +++ b/mdbook-spec/src/rules.rs @@ -2,8 +2,7 @@ use crate::test_links::RuleToTests; use crate::{Diagnostics, Spec, warn_or_err}; -use mdbook::BookItem; -use mdbook::book::Book; +use mdbook_preprocessor::book::{Book, BookItem}; use once_cell::sync::Lazy; use regex::{Captures, Regex}; use std::collections::{BTreeMap, HashSet}; diff --git a/mdbook-spec/src/std_links.rs b/mdbook-spec/src/std_links.rs index cbbed3a5..3251194e 100644 --- a/mdbook-spec/src/std_links.rs +++ b/mdbook-spec/src/std_links.rs @@ -2,10 +2,10 @@ use crate::{Diagnostics, bug, warn_or_err}; use anyhow::{Result, bail}; -use mdbook::BookItem; -use mdbook::book::{Book, Chapter}; +use mdbook_markdown::pulldown_cmark::{BrokenLink, CowStr, Event, LinkType, Options, Parser, Tag}; +use mdbook_preprocessor::book::BookItem; +use mdbook_preprocessor::book::{Book, Chapter}; use once_cell::sync::Lazy; -use pulldown_cmark::{BrokenLink, CowStr, Event, LinkType, Options, Parser, Tag}; use regex::Regex; use std::collections::HashMap; use std::fmt::Write as _; @@ -243,6 +243,7 @@ fn run_rustdoc( LinkType::Autolink | LinkType::Email => { bug!("link type should have been filtered {link:?}"); } + LinkType::WikiLink { .. } => panic!("unsupported wikilink"), } } } diff --git a/mdbook-spec/src/test_links.rs b/mdbook-spec/src/test_links.rs index 8f847d58..3f105c3b 100644 --- a/mdbook-spec/src/test_links.rs +++ b/mdbook-spec/src/test_links.rs @@ -1,7 +1,7 @@ //! Handling for linking tests in rust's testsuite to rule identifiers. use crate::{Rules, Spec}; -use mdbook::book::{Book, BookItem}; +use mdbook_preprocessor::book::{Book, BookItem}; use std::collections::HashMap; use std::fmt::Write; use std::path::PathBuf; diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index fae78dd4..0ea7ee0b 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -378,7 +378,7 @@ The operands of all of these operators are evaluated in [value expression contex | `/` | Division*† | | Division | `std::ops::Div` | `std::ops::DivAssign` | | `%` | Remainder**† | | Remainder | `std::ops::Rem` | `std::ops::RemAssign` | | `&` | Bitwise AND | [Logical AND] | | `std::ops::BitAnd` | `std::ops::BitAndAssign` | -| | | Bitwise OR | [Logical OR] | | `std::ops::BitOr` | `std::ops::BitOrAssign` | +| `\|` | Bitwise OR | [Logical OR] | | `std::ops::BitOr` | `std::ops::BitOrAssign` | | `^` | Bitwise XOR | [Logical XOR] | | `std::ops::BitXor` | `std::ops::BitXorAssign` | | `<<` | Left Shift | | | `std::ops::Shl` | `std::ops::ShlAssign` | | `>>` | Right Shift*** | | | `std::ops::Shr` | `std::ops::ShrAssign` | diff --git a/src/syntax-index.md b/src/syntax-index.md index fc06a26d..b07b1867 100644 --- a/src/syntax-index.md +++ b/src/syntax-index.md @@ -76,9 +76,9 @@ This appendix provides an index of tokens and common forms with links to where t | `^` | Caret | [bitwise and logical XOR][arith] | | `!` | Not | [bitwise and logical NOT][negation], [macro calls], [inner attributes][attributes], [never type], [negative impls] | | `&` | And | [bitwise and logical AND][arith], [borrow], [references], [reference patterns] | -| \| | Or | [bitwise and logical OR][arith], [closures], [or patterns], [if let], [while let] | +| `\|` | Or | [bitwise and logical OR][arith], [closures], [or patterns], [if let], [while let] | | `&&` | AndAnd | [lazy AND][lazy-bool], [borrow], [references], [reference patterns] | -| \|\| | OrOr | [lazy OR][lazy-bool], [closures] | +| `\|\|` | OrOr | [lazy OR][lazy-bool], [closures] | | `<<` | Shl | [shift left][arith], [nested generics][generics] | | `>>` | Shr | [shift right][arith], [nested generics][generics] | | `+=` | PlusEq | [addition assignment][compound] | @@ -88,7 +88,7 @@ This appendix provides an index of tokens and common forms with links to where t | `%=` | PercentEq | [remainder assignment][compound] | | `^=` | CaretEq | [bitwise XOR assignment][compound] | | `&=` | AndEq | [bitwise AND assignment][compound] | -| \|= | OrEq | [bitwise OR assignment][compound] | +| `\|=` | OrEq | [bitwise OR assignment][compound] | | `<<=` | ShlEq | [shift left assignment][compound] | | `>>=` | ShrEq | [shift right assignment][compound], [nested generics][generics] | | `=` | Eq | [assignment], [let statements], [attributes], various type definitions | @@ -164,7 +164,7 @@ This appendix provides an index of tokens and common forms with links to where t | Expression | Use | |---------------------------|-----| -| \|…\| expr
\|…\| -> Type { … } | [closures] | +| `\|…\| expr`
`\|…\| -> Type { … }` | [closures] | | `ident::…` | [paths] | | `::crate_name::…` | [explicit crate paths] | | `crate::…` | [crate-relative paths] | diff --git a/src/types/boolean.md b/src/types/boolean.md index fdb306eb..27ec97cb 100644 --- a/src/types/boolean.md +++ b/src/types/boolean.md @@ -61,7 +61,7 @@ r[type.bool.expr.not] r[type.bool.expr.or] ### Logical or -| `a` | `b` | [a | b][op-or] | +| `a` | `b` | [`a \| b`][op-or] | |- | - | - | | `true` | `true` | `true` | | `true` | `false` | `true` | diff --git a/theme/reference.css b/theme/reference.css index eb1760d6..7b486671 100644 --- a/theme/reference.css +++ b/theme/reference.css @@ -261,7 +261,7 @@ dfn { padding-right: 0; } /* required to accommodate above, somehow... */ -#menu-bar { +#mdbook-menu-bar { margin-left: 0; } From fa52328c7f1f9dd9ddef911de085b5c332f293a5 Mon Sep 17 00:00:00 2001 From: Jane Losare-Lusby Date: Mon, 13 Oct 2025 13:57:28 -0700 Subject: [PATCH 47/53] 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 94638b6a..71661d6c 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 2fa104ed..64a89286 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 36287e0d..1cd90203 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 da60d7eb..553e475d 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 b3560d2c..c5afbab7 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 4395e3db..11db99e5 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 48/53] 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 553e475d..0005956c 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 11db99e5..94f51577 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 49/53] 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 0005956c..f5dfd734 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 94f51577..721991f1 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 50/53] 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 f5dfd734..67d1a01a 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 51/53] 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 fd865dcc..c6c1656b 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 67d1a01a..4251a397 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 - From 1dcac030363ffa75822ae9d4b267b21161f4f527 Mon Sep 17 00:00:00 2001 From: Jane Losare-Lusby Date: Thu, 4 Dec 2025 12:27:42 -0800 Subject: [PATCH 52/53] clarify shadowing behavior for imports --- src/names/name-resolution.md | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/names/name-resolution.md b/src/names/name-resolution.md index 4251a397..fe772327 100644 --- a/src/names/name-resolution.md +++ b/src/names/name-resolution.md @@ -110,13 +110,9 @@ use m::A::V; // ERROR: Unresolved import `m::A::V`. ``` r[names.resolution.expansion.imports.shadowing] -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: +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 pub mod foo { @@ -127,17 +123,24 @@ pub mod foo { pub mod bar { pub mod baz { - pub struct Name; + pub struct Name(pub ()); } } -use foo::baz::Name; +use foo::baz; fn f() { - use bar::baz::Name; - Name; + use bar::baz; + use baz::Name + Name(()); } ``` +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 @@ -389,6 +392,7 @@ r[names.resolution.type-relative] [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 From 0d30ef6a03b31cffbb5eb2f8992252660d101941 Mon Sep 17 00:00:00 2001 From: Jane Losare-Lusby Date: Thu, 4 Dec 2025 12:28:11 -0800 Subject: [PATCH 53/53] move macro related ambiguities to macros subsection --- src/names/name-resolution.md | 93 +++++++++++++++++++++--------------- src/names/namespaces.md | 12 ++++- 2 files changed, 66 insertions(+), 39 deletions(-) diff --git a/src/names/name-resolution.md b/src/names/name-resolution.md index fe772327..c22476af 100644 --- a/src/names/name-resolution.md +++ b/src/names/name-resolution.md @@ -65,7 +65,7 @@ All name resolution candidates selected during macro expansion are considered sp > // 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. +> m::f!(); // ERROR: `m` is ambiguous. > }; > ``` @@ -261,10 +261,9 @@ pub fn qux() { > ``` 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]. +Path-based scope bindings for macros may not shadow textual scope bindings to macros. ```rust,compile_fail,E0659 -#[macro_export] macro_rules! m2 { () => {} } @@ -273,43 +272,10 @@ macro_rules! m { } pub fn foo() { m!(); // ERROR: `m` is ambiguous - use crate::m2 as m; // In scope for entire function body. + use 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.macros] ### Macros @@ -328,7 +294,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. 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]. @@ -367,6 +333,57 @@ fn foo() { } ``` +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] diff --git a/src/names/namespaces.md b/src/names/namespaces.md index c5afbab7..c0156fc4 100644 --- a/src/names/namespaces.md +++ b/src/names/namespaces.md @@ -117,8 +117,18 @@ 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. + > [!NOTE] -> For restrictions on shadowing macro sub-namespaces with [use declaration]s, see [name resolution ambiguity errors]. +> `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 +> ``` [Associated const declarations]: ../items/associated-items.md#associated-constants [Associated function declarations]: ../items/associated-items.md#associated-functions-and-methods